Put /history[-range] logic in a dedicate file.
This commit is contained in:
parent
9fc380f7c8
commit
e13a8902f0
1
.gitignore
vendored
1
.gitignore
vendored
@ -115,3 +115,4 @@ src/bank-lib/test_bank_api_twisted
|
|||||||
src/lib/test_exchange_api_new
|
src/lib/test_exchange_api_new
|
||||||
src/lib/test_auditor_api
|
src/lib/test_auditor_api
|
||||||
src/lib/test_exchange_api_overlapping_keys_bug
|
src/lib/test_exchange_api_overlapping_keys_bug
|
||||||
|
src/lib/test_exchange_api_home/.local/share/taler/exchange/revocations/
|
||||||
|
@ -57,6 +57,7 @@ libtalerfakebank_la_LDFLAGS = \
|
|||||||
-no-undefined
|
-no-undefined
|
||||||
|
|
||||||
libtalerfakebank_la_SOURCES = \
|
libtalerfakebank_la_SOURCES = \
|
||||||
|
fakebank_history.c \
|
||||||
fakebank.c
|
fakebank.c
|
||||||
|
|
||||||
libtalerfakebank_la_LIBADD = \
|
libtalerfakebank_la_LIBADD = \
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "taler_fakebank_lib.h"
|
#include "taler_fakebank_lib.h"
|
||||||
#include "taler_bank_service.h"
|
#include "taler_bank_service.h"
|
||||||
|
#include "fakebank.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum POST request size (for /admin/add/incoming)
|
* Maximum POST request size (for /admin/add/incoming)
|
||||||
@ -32,169 +33,6 @@
|
|||||||
#define REQUEST_BUFFER_MAX (4*1024)
|
#define REQUEST_BUFFER_MAX (4*1024)
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse URL arguments of a /history[-range] HTTP request.
|
|
||||||
*
|
|
||||||
* @param connection MHD connection object.
|
|
||||||
* @param ha @a HistoryArgs structure.
|
|
||||||
*/
|
|
||||||
#define PARSE_HISTORY_ARGS(connection, ha) \
|
|
||||||
parse_history_args_ (connection, ha, __FUNCTION__)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Details about a transcation we (as the simulated bank) received.
|
|
||||||
*/
|
|
||||||
struct Transaction
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* We store transactions in a DLL.
|
|
||||||
*/
|
|
||||||
struct Transaction *next;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We store transactions in a DLL.
|
|
||||||
*/
|
|
||||||
struct Transaction *prev;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Amount to be transferred.
|
|
||||||
*/
|
|
||||||
struct TALER_Amount amount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Account to debit.
|
|
||||||
*/
|
|
||||||
uint64_t debit_account;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Account to credit.
|
|
||||||
*/
|
|
||||||
uint64_t credit_account;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subject of the transfer.
|
|
||||||
*/
|
|
||||||
char *subject;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base URL of the exchange.
|
|
||||||
*/
|
|
||||||
char *exchange_base_url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When did the transaction happen?
|
|
||||||
*/
|
|
||||||
struct GNUNET_TIME_Absolute date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of this transaction.
|
|
||||||
*/
|
|
||||||
uint64_t row_id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag set if the transfer was rejected.
|
|
||||||
*/
|
|
||||||
int rejected;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Has this transaction been subjected to #TALER_FAKEBANK_check()
|
|
||||||
* and should thus no longer be counted in
|
|
||||||
* #TALER_FAKEBANK_check_empty()?
|
|
||||||
*/
|
|
||||||
int checked;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Needed to implement ascending/descending ordering
|
|
||||||
* of /history results.
|
|
||||||
*/
|
|
||||||
struct HistoryElement
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* History JSON element.
|
|
||||||
*/
|
|
||||||
json_t *element;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Previous element.
|
|
||||||
*/
|
|
||||||
struct HistoryElement *prev;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Next element.
|
|
||||||
*/
|
|
||||||
struct HistoryElement *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Values to implement the "/history-range" range.
|
|
||||||
*/
|
|
||||||
struct HistoryRangeDates
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Oldest row in the results.
|
|
||||||
*/
|
|
||||||
struct GNUNET_TIME_Absolute start;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Youngest row in the results.
|
|
||||||
*/
|
|
||||||
struct GNUNET_TIME_Absolute end;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Values to implement the "/history" range.
|
|
||||||
*/
|
|
||||||
struct HistoryRangeIds
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* (Exclusive) row ID for the result set.
|
|
||||||
*/
|
|
||||||
unsigned long long start;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* How many transactions we want in the result set. If
|
|
||||||
* negative/positive, @a start will be strictly younger/older
|
|
||||||
* of any element in the result set.
|
|
||||||
*/
|
|
||||||
long long count;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the "base" structure for both the /history and the
|
|
||||||
* /history-range API calls.
|
|
||||||
*/
|
|
||||||
struct HistoryArgs
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Direction asked by the client: CREDIT / DEBIT / BOTH / CANCEL.
|
|
||||||
*/
|
|
||||||
enum TALER_BANK_Direction direction;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bank account number of the requesting client.
|
|
||||||
*/
|
|
||||||
unsigned long long account_number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ordering of the results.
|
|
||||||
*/
|
|
||||||
unsigned int ascending;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overloaded type that indicates the "range" to be returned
|
|
||||||
* in the results; this can be either a date range, or a
|
|
||||||
* starting row id + the count.
|
|
||||||
*/
|
|
||||||
void *range;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle for the fake bank.
|
* Handle for the fake bank.
|
||||||
*/
|
*/
|
||||||
@ -746,442 +584,6 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************
|
|
||||||
* Serving "/history" starts here. *
|
|
||||||
***********************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type for a function that decides whether or not
|
|
||||||
* the history-building loop should iterate once again.
|
|
||||||
* Typically called from inside the 'while' condition.
|
|
||||||
*
|
|
||||||
* @param ha history argument.
|
|
||||||
* @param pos current position.
|
|
||||||
* @return GNUNET_YES if the iteration shuold go on.
|
|
||||||
*/
|
|
||||||
typedef int (*CheckAdvance)
|
|
||||||
(const struct HistoryArgs *ha,
|
|
||||||
const struct Transaction *pos);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type for a function that steps over the next element
|
|
||||||
* in the list of all transactions, after the current @a pos
|
|
||||||
* _got_ included in the result.
|
|
||||||
*/
|
|
||||||
typedef struct Transaction * (*Step)
|
|
||||||
(const struct HistoryArgs *ha,
|
|
||||||
const struct Transaction *pos);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Type for a function that steps over the next element
|
|
||||||
* in the list of all transactions, after the current @a pos
|
|
||||||
* did _not_ get included in the result.
|
|
||||||
*/
|
|
||||||
typedef struct Transaction * (*Skip)
|
|
||||||
(const struct HistoryArgs *ha,
|
|
||||||
const struct Transaction *pos);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decides whether the history builder will advance or not
|
|
||||||
* to the next element.
|
|
||||||
*
|
|
||||||
* @param ha history args
|
|
||||||
* @return GNUNET_YES/NO to advance/not-advance.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
handle_history_advance (const struct HistoryArgs *ha,
|
|
||||||
const struct Transaction *pos)
|
|
||||||
{
|
|
||||||
const struct HistoryRangeIds *hri = ha->range;
|
|
||||||
|
|
||||||
return (NULL != pos) && (0 != hri->count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates on the "next" element to be processed. To
|
|
||||||
* be used when the current element does not get inserted in
|
|
||||||
* the result.
|
|
||||||
*
|
|
||||||
* @param ha history arguments.
|
|
||||||
* @param pos current element being processed.
|
|
||||||
* @return the next element to be processed.
|
|
||||||
*/
|
|
||||||
static struct Transaction *
|
|
||||||
handle_history_skip (const struct HistoryArgs *ha,
|
|
||||||
const struct Transaction *pos)
|
|
||||||
{
|
|
||||||
const struct HistoryRangeIds *hri = ha->range;
|
|
||||||
|
|
||||||
if (hri->count > 0)
|
|
||||||
return pos->next;
|
|
||||||
if (hri->count < 0)
|
|
||||||
return pos->prev;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates on the "next" element to be processed. To
|
|
||||||
* be used when the current element _gets_ inserted in the result.
|
|
||||||
*
|
|
||||||
* @param ha history arguments.
|
|
||||||
* @param pos current element being processed.
|
|
||||||
* @return the next element to be processed.
|
|
||||||
*/
|
|
||||||
static struct Transaction *
|
|
||||||
handle_history_step (const struct HistoryArgs *ha,
|
|
||||||
const struct Transaction *pos)
|
|
||||||
{
|
|
||||||
struct HistoryRangeIds *hri = ha->range;
|
|
||||||
|
|
||||||
if (hri->count > 0)
|
|
||||||
{
|
|
||||||
hri->count--;
|
|
||||||
return pos->next;
|
|
||||||
}
|
|
||||||
if (hri->count < 0)
|
|
||||||
{
|
|
||||||
hri->count++;
|
|
||||||
return pos->prev;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decides whether the history builder will advance or not
|
|
||||||
* to the next element.
|
|
||||||
*
|
|
||||||
* @param ha history args
|
|
||||||
* @return GNUNET_YES/NO to advance/not-advance.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
handle_history_range_advance (const struct HistoryArgs *ha,
|
|
||||||
const struct Transaction *pos)
|
|
||||||
{
|
|
||||||
const struct HistoryRangeDates *hrd = ha->range;
|
|
||||||
|
|
||||||
if ( (NULL != pos) &&
|
|
||||||
(pos->date.abs_value_us <= hrd->end.abs_value_us) )
|
|
||||||
return GNUNET_YES;
|
|
||||||
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates towards the "next" element to be processed. To
|
|
||||||
* be used when the current element does not get inserted in
|
|
||||||
* the result.
|
|
||||||
*
|
|
||||||
* @param ha history arguments.
|
|
||||||
* @param pos current element being processed.
|
|
||||||
* @return the next element to be processed.
|
|
||||||
*/
|
|
||||||
static struct Transaction *
|
|
||||||
handle_history_range_skip (const struct HistoryArgs *ha,
|
|
||||||
const struct Transaction *pos)
|
|
||||||
{
|
|
||||||
/* Transactions
|
|
||||||
* are stored from "head"/older to "tail"/younger. */
|
|
||||||
return pos->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates on the "next" element to be processed. To
|
|
||||||
* be used when the current element _gets_ inserted in the result.
|
|
||||||
* Same implementation of the "skip" counterpart, as /history-range
|
|
||||||
* does not have the notion of count/delta.
|
|
||||||
*/
|
|
||||||
Step handle_history_range_step = handle_history_range_skip;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Actual history response builder.
|
|
||||||
*
|
|
||||||
* @param pos first (included) element in the result set.
|
|
||||||
* @param ha history arguments.
|
|
||||||
* @param caller_name which function is building the history.
|
|
||||||
* @return MHD_YES / MHD_NO, after having enqueued the response
|
|
||||||
* object into MHD.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
build_history_response (struct MHD_Connection *connection,
|
|
||||||
struct Transaction *pos,
|
|
||||||
struct HistoryArgs *ha,
|
|
||||||
Skip skip,
|
|
||||||
Step step,
|
|
||||||
CheckAdvance advance)
|
|
||||||
{
|
|
||||||
|
|
||||||
struct HistoryElement *history_results_head = NULL;
|
|
||||||
struct HistoryElement *history_results_tail = NULL;
|
|
||||||
struct HistoryElement *history_element = NULL;
|
|
||||||
json_t *history;
|
|
||||||
json_t *jresponse;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while (advance (ha,
|
|
||||||
pos))
|
|
||||||
{
|
|
||||||
json_t *trans;
|
|
||||||
char *subject;
|
|
||||||
const char *sign;
|
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Found transaction over %s from %llu to %llu\n",
|
|
||||||
TALER_amount2s (&pos->amount),
|
|
||||||
(unsigned long long) pos->debit_account,
|
|
||||||
(unsigned long long) pos->credit_account);
|
|
||||||
|
|
||||||
if ( (! ( ( (ha->account_number == pos->debit_account) &&
|
|
||||||
(0 != (ha->direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
|
|
||||||
( (ha->account_number == pos->credit_account) &&
|
|
||||||
(0 != (ha->direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) ||
|
|
||||||
( (0 == (ha->direction & TALER_BANK_DIRECTION_CANCEL)) &&
|
|
||||||
(GNUNET_YES == pos->rejected) ) )
|
|
||||||
{
|
|
||||||
pos = skip (ha,
|
|
||||||
pos);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GNUNET_asprintf (&subject,
|
|
||||||
"%s %s",
|
|
||||||
pos->subject,
|
|
||||||
pos->exchange_base_url);
|
|
||||||
sign =
|
|
||||||
(ha->account_number == pos->debit_account)
|
|
||||||
? (pos->rejected ? "cancel-" : "-")
|
|
||||||
: (pos->rejected ? "cancel+" : "+");
|
|
||||||
trans = json_pack
|
|
||||||
("{s:I, s:o, s:o, s:s, s:I, s:s}",
|
|
||||||
"row_id", (json_int_t) pos->row_id,
|
|
||||||
"date", GNUNET_JSON_from_time_abs (pos->date),
|
|
||||||
"amount", TALER_JSON_from_amount (&pos->amount),
|
|
||||||
"sign", sign,
|
|
||||||
"counterpart", (json_int_t)
|
|
||||||
( (ha->account_number == pos->debit_account)
|
|
||||||
? pos->credit_account
|
|
||||||
: pos->debit_account),
|
|
||||||
"wt_subject", subject);
|
|
||||||
GNUNET_assert (NULL != trans);
|
|
||||||
GNUNET_free (subject);
|
|
||||||
|
|
||||||
history_element = GNUNET_new (struct HistoryElement);
|
|
||||||
history_element->element = trans;
|
|
||||||
|
|
||||||
|
|
||||||
/* XXX: the ordering feature is missing. */
|
|
||||||
|
|
||||||
GNUNET_CONTAINER_DLL_insert_tail (history_results_head,
|
|
||||||
history_results_tail,
|
|
||||||
history_element);
|
|
||||||
pos = step (ha, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
history = json_array ();
|
|
||||||
if (NULL != history_results_head)
|
|
||||||
history_element = history_results_head;
|
|
||||||
|
|
||||||
while (NULL != history_element)
|
|
||||||
{
|
|
||||||
json_array_append_new (history,
|
|
||||||
history_element->element);
|
|
||||||
history_element = history_element->next;
|
|
||||||
if (NULL != history_element)
|
|
||||||
GNUNET_free_non_null (history_element->prev);
|
|
||||||
}
|
|
||||||
GNUNET_free_non_null (history_results_tail);
|
|
||||||
|
|
||||||
if (0 == json_array_size (history))
|
|
||||||
{
|
|
||||||
struct MHD_Response *resp;
|
|
||||||
|
|
||||||
json_decref (history);
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Returning empty transaction history\n");
|
|
||||||
resp = MHD_create_response_from_buffer
|
|
||||||
(0,
|
|
||||||
"",
|
|
||||||
MHD_RESPMEM_PERSISTENT);
|
|
||||||
ret = MHD_queue_response (connection,
|
|
||||||
MHD_HTTP_NO_CONTENT,
|
|
||||||
resp);
|
|
||||||
MHD_destroy_response (resp);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
jresponse = json_pack ("{s:o}",
|
|
||||||
"data",
|
|
||||||
history);
|
|
||||||
if (NULL == jresponse)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finally build response object */
|
|
||||||
{
|
|
||||||
struct MHD_Response *resp;
|
|
||||||
void *json_str;
|
|
||||||
size_t json_len;
|
|
||||||
|
|
||||||
json_str = json_dumps (jresponse,
|
|
||||||
JSON_INDENT(2));
|
|
||||||
json_decref (jresponse);
|
|
||||||
if (NULL == json_str)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
json_len = strlen (json_str);
|
|
||||||
resp = MHD_create_response_from_buffer (json_len,
|
|
||||||
json_str,
|
|
||||||
MHD_RESPMEM_MUST_FREE);
|
|
||||||
if (NULL == resp)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
free (json_str);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
(void) MHD_add_response_header (resp,
|
|
||||||
MHD_HTTP_HEADER_CONTENT_TYPE,
|
|
||||||
"application/json");
|
|
||||||
ret = MHD_queue_response (connection,
|
|
||||||
MHD_HTTP_OK,
|
|
||||||
resp);
|
|
||||||
MHD_destroy_response (resp);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse URL history arguments, of _both_ APIs:
|
|
||||||
* /history and /history-range.
|
|
||||||
*
|
|
||||||
* @param connection MHD connection.
|
|
||||||
* @param function_name name of the caller.
|
|
||||||
* @param ha[out] will contain the parsed values.
|
|
||||||
* @return GNUNET_OK only if the parsing succeedes.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
parse_history_common_args (struct MHD_Connection *connection,
|
|
||||||
struct HistoryArgs *ha)
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @variable
|
|
||||||
* Just check if given and == "basic", no need to keep around.
|
|
||||||
*/
|
|
||||||
const char *auth;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* All those will go into the structure, after parsing.
|
|
||||||
*/
|
|
||||||
const char *direction;
|
|
||||||
const char *cancelled;
|
|
||||||
const char *ordering;
|
|
||||||
const char *account_number;
|
|
||||||
|
|
||||||
|
|
||||||
auth = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"auth");
|
|
||||||
direction = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"direction");
|
|
||||||
cancelled = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"cancelled");
|
|
||||||
ordering = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"ordering");
|
|
||||||
account_number = MHD_lookup_connection_value
|
|
||||||
(connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"account_number");
|
|
||||||
|
|
||||||
/* Fail if one of the above failed. */
|
|
||||||
if ( (NULL == direction) ||
|
|
||||||
(NULL == cancelled) ||
|
|
||||||
( (0 != strcasecmp (cancelled,
|
|
||||||
"OMIT")) &&
|
|
||||||
(0 != strcasecmp (cancelled,
|
|
||||||
"SHOW")) ) ||
|
|
||||||
( (0 != strcasecmp (direction,
|
|
||||||
"BOTH")) &&
|
|
||||||
(0 != strcasecmp (direction,
|
|
||||||
"CREDIT")) &&
|
|
||||||
(0 != strcasecmp (direction,
|
|
||||||
"DEBIT")) ) ||
|
|
||||||
(1 != sscanf (account_number,
|
|
||||||
"%llu",
|
|
||||||
&ha->account_number)) ||
|
|
||||||
( (NULL == auth) || (0 != strcasecmp (auth,
|
|
||||||
"basic")) ) )
|
|
||||||
{
|
|
||||||
/* Invalid request, given that this is fakebank we impolitely
|
|
||||||
* just kill the connection instead of returning a nice error.
|
|
||||||
*/
|
|
||||||
GNUNET_break (0);
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == strcasecmp (direction,
|
|
||||||
"CREDIT"))
|
|
||||||
{
|
|
||||||
ha->direction = TALER_BANK_DIRECTION_CREDIT;
|
|
||||||
}
|
|
||||||
else if (0 == strcasecmp (direction,
|
|
||||||
"DEBIT"))
|
|
||||||
{
|
|
||||||
ha->direction = TALER_BANK_DIRECTION_DEBIT;
|
|
||||||
}
|
|
||||||
else if (0 == strcasecmp (direction,
|
|
||||||
"BOTH"))
|
|
||||||
{
|
|
||||||
ha->direction = TALER_BANK_DIRECTION_BOTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Direction is invalid. */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 == strcasecmp (cancelled,
|
|
||||||
"OMIT"))
|
|
||||||
{
|
|
||||||
/* nothing */
|
|
||||||
} else if (0 == strcasecmp (cancelled,
|
|
||||||
"SHOW"))
|
|
||||||
{
|
|
||||||
ha->direction |= TALER_BANK_DIRECTION_CANCEL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cancel-showing policy is invalid. */
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((NULL != ordering)
|
|
||||||
&& 0 == strcmp ("ascending",
|
|
||||||
ordering))
|
|
||||||
ha->ascending = GNUNET_YES;
|
|
||||||
else
|
|
||||||
ha->ascending = GNUNET_NO;
|
|
||||||
|
|
||||||
return GNUNET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle incoming HTTP request for /history
|
* Handle incoming HTTP request for /history
|
||||||
*
|
*
|
||||||
@ -1201,7 +603,7 @@ handle_history_new (struct TALER_FAKEBANK_Handle *h,
|
|||||||
const char *delta;
|
const char *delta;
|
||||||
struct Transaction *pos;
|
struct Transaction *pos;
|
||||||
|
|
||||||
if (GNUNET_OK != parse_history_common_args (connection,
|
if (GNUNET_OK != TFH_parse_history_common_args (connection,
|
||||||
&ha))
|
&ha))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -1259,12 +661,12 @@ handle_history_new (struct TALER_FAKEBANK_Handle *h,
|
|||||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||||
"/history, start row (0 == no transactions exist): %llu\n",
|
"/history, start row (0 == no transactions exist): %llu\n",
|
||||||
NULL != pos ? pos->row_id : 0);
|
NULL != pos ? pos->row_id : 0);
|
||||||
return build_history_response (connection,
|
return TFH_build_history_response (connection,
|
||||||
pos,
|
pos,
|
||||||
&ha,
|
&ha,
|
||||||
&handle_history_skip,
|
&TFH_handle_history_skip,
|
||||||
&handle_history_step,
|
&TFH_handle_history_step,
|
||||||
&handle_history_advance);
|
&TFH_handle_history_advance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1288,7 +690,7 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h,
|
|||||||
long long unsigned int end_stamp;
|
long long unsigned int end_stamp;
|
||||||
struct Transaction *pos;
|
struct Transaction *pos;
|
||||||
|
|
||||||
if (GNUNET_OK != parse_history_common_args (connection,
|
if (GNUNET_OK != TFH_parse_history_common_args (connection,
|
||||||
&ha))
|
&ha))
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
@ -1309,7 +711,7 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h,
|
|||||||
&end_stamp)) )
|
&end_stamp)) )
|
||||||
{
|
{
|
||||||
GNUNET_break (0);
|
GNUNET_break (0);
|
||||||
return GNUNET_NO;
|
return MHD_NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
hrd.start.abs_value_us = start_stamp * 1000LL * 1000LL;
|
hrd.start.abs_value_us = start_stamp * 1000LL * 1000LL;
|
||||||
@ -1325,336 +727,14 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h,
|
|||||||
if (hrd.start.abs_value_us <= pos->date.abs_value_us)
|
if (hrd.start.abs_value_us <= pos->date.abs_value_us)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return build_history_response (connection,
|
return TFH_build_history_response (connection,
|
||||||
pos,
|
pos,
|
||||||
&ha,
|
&ha,
|
||||||
&handle_history_range_skip,
|
&TFH_handle_history_range_skip,
|
||||||
handle_history_range_step,
|
TFH_handle_history_range_step,
|
||||||
&handle_history_range_advance);
|
&TFH_handle_history_range_advance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle incoming HTTP request for /history
|
|
||||||
*
|
|
||||||
* @param h the fakebank handle
|
|
||||||
* @param connection the connection
|
|
||||||
* @param con_cls place to store state, not used
|
|
||||||
* @return MHD result code
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
handle_history (struct TALER_FAKEBANK_Handle *h,
|
|
||||||
struct MHD_Connection *connection,
|
|
||||||
void **con_cls)
|
|
||||||
{
|
|
||||||
const char *auth;
|
|
||||||
const char *delta;
|
|
||||||
const char *start;
|
|
||||||
const char *dir;
|
|
||||||
const char *acc;
|
|
||||||
const char *cancelled;
|
|
||||||
const char *ordering;
|
|
||||||
unsigned long long account_number;
|
|
||||||
unsigned long long start_number;
|
|
||||||
long long count;
|
|
||||||
enum TALER_BANK_Direction direction;
|
|
||||||
struct Transaction *pos;
|
|
||||||
json_t *history;
|
|
||||||
json_t *jresponse;
|
|
||||||
int ret;
|
|
||||||
int ascending;
|
|
||||||
struct HistoryElement *history_results_head = NULL;
|
|
||||||
struct HistoryElement *history_results_tail = NULL;
|
|
||||||
struct HistoryElement *history_element = NULL;
|
|
||||||
|
|
||||||
auth = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"auth");
|
|
||||||
delta = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"delta");
|
|
||||||
dir = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"direction");
|
|
||||||
cancelled = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"cancelled");
|
|
||||||
start = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"start");
|
|
||||||
ordering = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"ordering");
|
|
||||||
acc = MHD_lookup_connection_value (connection,
|
|
||||||
MHD_GET_ARGUMENT_KIND,
|
|
||||||
"account_number");
|
|
||||||
if ( (NULL == auth) ||
|
|
||||||
(0 != strcasecmp (auth,
|
|
||||||
"basic")) ||
|
|
||||||
(NULL == acc) ||
|
|
||||||
(NULL == delta) )
|
|
||||||
{
|
|
||||||
/* Invalid request,
|
|
||||||
given that this is fakebank we impolitely just
|
|
||||||
kill the connection instead of returning a nice error. */
|
|
||||||
GNUNET_break (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
start_number = 0;
|
|
||||||
if ( (1 != sscanf (delta,
|
|
||||||
"%lld",
|
|
||||||
&count)) ||
|
|
||||||
(1 != sscanf (acc,
|
|
||||||
"%llu",
|
|
||||||
&account_number)) ||
|
|
||||||
( (NULL != start) &&
|
|
||||||
(1 != sscanf (start,
|
|
||||||
"%llu",
|
|
||||||
&start_number)) ) ||
|
|
||||||
(NULL == dir) ||
|
|
||||||
(NULL == cancelled) ||
|
|
||||||
( (0 != strcasecmp (cancelled,
|
|
||||||
"OMIT")) &&
|
|
||||||
(0 != strcasecmp (cancelled,
|
|
||||||
"SHOW")) ) ||
|
|
||||||
( (0 != strcasecmp (dir,
|
|
||||||
"BOTH")) &&
|
|
||||||
(0 != strcasecmp (dir,
|
|
||||||
"CREDIT")) &&
|
|
||||||
(0 != strcasecmp (dir,
|
|
||||||
"DEBIT")) ) )
|
|
||||||
{
|
|
||||||
/* Invalid request, given that this is fakebank we impolitely
|
|
||||||
* just kill the connection instead of returning a nice error.
|
|
||||||
*/
|
|
||||||
GNUNET_break (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Client asked for up to %lld results of type %s for account %llu starting at %llu\n",
|
|
||||||
count,
|
|
||||||
dir,
|
|
||||||
(unsigned long long) account_number,
|
|
||||||
start_number);
|
|
||||||
if (0 == strcasecmp (dir,
|
|
||||||
"CREDIT"))
|
|
||||||
{
|
|
||||||
direction = TALER_BANK_DIRECTION_CREDIT;
|
|
||||||
}
|
|
||||||
else if (0 == strcasecmp (dir,
|
|
||||||
"DEBIT"))
|
|
||||||
{
|
|
||||||
direction = TALER_BANK_DIRECTION_DEBIT;
|
|
||||||
}
|
|
||||||
else if (0 == strcasecmp (dir,
|
|
||||||
"BOTH"))
|
|
||||||
{
|
|
||||||
direction = TALER_BANK_DIRECTION_BOTH;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GNUNET_assert (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
if (0 == strcasecmp (cancelled,
|
|
||||||
"OMIT"))
|
|
||||||
{
|
|
||||||
/* nothing */
|
|
||||||
} else if (0 == strcasecmp (cancelled,
|
|
||||||
"SHOW"))
|
|
||||||
{
|
|
||||||
direction |= TALER_BANK_DIRECTION_CANCEL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GNUNET_assert (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NULL == start)
|
|
||||||
pos = 0 > count ? h->transactions_tail : h->transactions_head;
|
|
||||||
|
|
||||||
else if (NULL != h->transactions_head)
|
|
||||||
{
|
|
||||||
for (pos = h->transactions_head;
|
|
||||||
NULL != pos;
|
|
||||||
pos = pos->next)
|
|
||||||
if (pos->row_id == start_number)
|
|
||||||
break;
|
|
||||||
if (NULL == pos)
|
|
||||||
{
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
|
||||||
"Invalid range specified, transaction %llu not known!\n",
|
|
||||||
(unsigned long long) start_number);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
/* range is exclusive, skip the matching entry */
|
|
||||||
if (count > 0)
|
|
||||||
pos = pos->next;
|
|
||||||
if (count < 0)
|
|
||||||
pos = pos->prev;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* list is empty */
|
|
||||||
pos = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
history = json_array ();
|
|
||||||
if ((NULL != ordering)
|
|
||||||
&& 0 == strcmp ("ascending",
|
|
||||||
ordering))
|
|
||||||
ascending = GNUNET_YES;
|
|
||||||
else
|
|
||||||
ascending = GNUNET_NO;
|
|
||||||
|
|
||||||
while ( (NULL != pos) &&
|
|
||||||
(0 != count) )
|
|
||||||
{
|
|
||||||
json_t *trans;
|
|
||||||
char *subject;
|
|
||||||
const char *sign;
|
|
||||||
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Found transaction over %s from %llu to %llu\n",
|
|
||||||
TALER_amount2s (&pos->amount),
|
|
||||||
(unsigned long long) pos->debit_account,
|
|
||||||
(unsigned long long) pos->credit_account);
|
|
||||||
|
|
||||||
if ( (! ( ( (account_number == pos->debit_account) &&
|
|
||||||
(0 != (direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
|
|
||||||
( (account_number == pos->credit_account) &&
|
|
||||||
(0 != (direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) ||
|
|
||||||
( (0 == (direction & TALER_BANK_DIRECTION_CANCEL)) &&
|
|
||||||
(GNUNET_YES == pos->rejected) ) )
|
|
||||||
{
|
|
||||||
if (count > 0)
|
|
||||||
pos = pos->next;
|
|
||||||
if (count < 0)
|
|
||||||
pos = pos->prev;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GNUNET_asprintf (&subject,
|
|
||||||
"%s %s",
|
|
||||||
pos->subject,
|
|
||||||
pos->exchange_base_url);
|
|
||||||
sign =
|
|
||||||
(account_number == pos->debit_account)
|
|
||||||
? (pos->rejected ? "cancel-" : "-")
|
|
||||||
: (pos->rejected ? "cancel+" : "+");
|
|
||||||
trans = json_pack ("{s:I, s:o, s:o, s:s, s:I, s:s}",
|
|
||||||
"row_id", (json_int_t) pos->row_id,
|
|
||||||
"date", GNUNET_JSON_from_time_abs (pos->date),
|
|
||||||
"amount", TALER_JSON_from_amount (&pos->amount),
|
|
||||||
"sign", sign,
|
|
||||||
"counterpart", (json_int_t) ( (account_number == pos->debit_account)
|
|
||||||
? pos->credit_account
|
|
||||||
: pos->debit_account),
|
|
||||||
"wt_subject", subject);
|
|
||||||
GNUNET_assert (NULL != trans);
|
|
||||||
GNUNET_free (subject);
|
|
||||||
|
|
||||||
history_element = GNUNET_new (struct HistoryElement);
|
|
||||||
history_element->element = trans;
|
|
||||||
|
|
||||||
if (((0 < count) && (GNUNET_YES == ascending))
|
|
||||||
|| ((0 > count) && (GNUNET_NO == ascending)))
|
|
||||||
GNUNET_CONTAINER_DLL_insert_tail (history_results_head,
|
|
||||||
history_results_tail,
|
|
||||||
history_element);
|
|
||||||
else
|
|
||||||
GNUNET_CONTAINER_DLL_insert (history_results_head,
|
|
||||||
history_results_tail,
|
|
||||||
history_element);
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
pos = pos->next;
|
|
||||||
count--;
|
|
||||||
}
|
|
||||||
if (count < 0)
|
|
||||||
{
|
|
||||||
pos = pos->prev;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NULL != history_results_head)
|
|
||||||
history_element = history_results_head;
|
|
||||||
while (NULL != history_element)
|
|
||||||
{
|
|
||||||
json_array_append_new (history,
|
|
||||||
history_element->element);
|
|
||||||
history_element = history_element->next;
|
|
||||||
if (NULL != history_element)
|
|
||||||
GNUNET_free_non_null (history_element->prev);
|
|
||||||
}
|
|
||||||
GNUNET_free_non_null (history_results_tail);
|
|
||||||
|
|
||||||
if (0 == json_array_size (history))
|
|
||||||
{
|
|
||||||
struct MHD_Response *resp;
|
|
||||||
|
|
||||||
json_decref (history);
|
|
||||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
|
||||||
"Returning empty transaction history\n");
|
|
||||||
resp = MHD_create_response_from_buffer (0,
|
|
||||||
"",
|
|
||||||
MHD_RESPMEM_PERSISTENT);
|
|
||||||
ret = MHD_queue_response (connection,
|
|
||||||
MHD_HTTP_NO_CONTENT,
|
|
||||||
resp);
|
|
||||||
MHD_destroy_response (resp);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
jresponse = json_pack ("{s:o}",
|
|
||||||
"data",
|
|
||||||
history);
|
|
||||||
if (NULL == jresponse)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finally build response object */
|
|
||||||
{
|
|
||||||
struct MHD_Response *resp;
|
|
||||||
void *json_str;
|
|
||||||
size_t json_len;
|
|
||||||
|
|
||||||
json_str = json_dumps (jresponse,
|
|
||||||
JSON_INDENT(2));
|
|
||||||
json_decref (jresponse);
|
|
||||||
if (NULL == json_str)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
json_len = strlen (json_str);
|
|
||||||
resp = MHD_create_response_from_buffer (json_len,
|
|
||||||
json_str,
|
|
||||||
MHD_RESPMEM_MUST_FREE);
|
|
||||||
if (NULL == resp)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
free (json_str);
|
|
||||||
return MHD_NO;
|
|
||||||
}
|
|
||||||
(void) MHD_add_response_header (resp,
|
|
||||||
MHD_HTTP_HEADER_CONTENT_TYPE,
|
|
||||||
"application/json");
|
|
||||||
ret = MHD_queue_response (connection,
|
|
||||||
MHD_HTTP_OK,
|
|
||||||
resp);
|
|
||||||
MHD_destroy_response (resp);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************
|
|
||||||
* End of /history implementation. *
|
|
||||||
***********************************/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle incoming HTTP request.
|
* Handle incoming HTTP request.
|
||||||
*
|
*
|
||||||
|
322
src/bank-lib/fakebank.h
Normal file
322
src/bank-lib/fakebank.h
Normal file
@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
(C) 2016, 2017, 2018 Inria and GNUnet e.V.
|
||||||
|
|
||||||
|
TALER is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU 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 bank-lib/fakebank.h
|
||||||
|
* @brief definitions for the "/history[-range]" layer.
|
||||||
|
* @author Marcello Stanisci <stanisci.m@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FAKEBANK_H
|
||||||
|
#define FAKEBANK_H
|
||||||
|
#include "platform.h"
|
||||||
|
#include <gnunet/gnunet_util_lib.h>
|
||||||
|
#include "taler_bank_service.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Details about a transcation we (as the simulated bank) received.
|
||||||
|
*/
|
||||||
|
struct Transaction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* We store transactions in a DLL.
|
||||||
|
*/
|
||||||
|
struct Transaction *next;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We store transactions in a DLL.
|
||||||
|
*/
|
||||||
|
struct Transaction *prev;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Amount to be transferred.
|
||||||
|
*/
|
||||||
|
struct TALER_Amount amount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account to debit.
|
||||||
|
*/
|
||||||
|
uint64_t debit_account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account to credit.
|
||||||
|
*/
|
||||||
|
uint64_t credit_account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subject of the transfer.
|
||||||
|
*/
|
||||||
|
char *subject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base URL of the exchange.
|
||||||
|
*/
|
||||||
|
char *exchange_base_url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When did the transaction happen?
|
||||||
|
*/
|
||||||
|
struct GNUNET_TIME_Absolute date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of this transaction.
|
||||||
|
*/
|
||||||
|
uint64_t row_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag set if the transfer was rejected.
|
||||||
|
*/
|
||||||
|
int rejected;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Has this transaction been subjected to #TALER_FAKEBANK_check()
|
||||||
|
* and should thus no longer be counted in
|
||||||
|
* #TALER_FAKEBANK_check_empty()?
|
||||||
|
*/
|
||||||
|
int checked;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Definitions for "/history" start here. *
|
||||||
|
******************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needed to implement ascending/descending ordering
|
||||||
|
* of /history results.
|
||||||
|
*/
|
||||||
|
struct HistoryElement
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* History JSON element.
|
||||||
|
*/
|
||||||
|
json_t *element;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous element.
|
||||||
|
*/
|
||||||
|
struct HistoryElement *prev;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Next element.
|
||||||
|
*/
|
||||||
|
struct HistoryElement *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Values to implement the "/history-range" range.
|
||||||
|
*/
|
||||||
|
struct HistoryRangeDates
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Oldest row in the results.
|
||||||
|
*/
|
||||||
|
struct GNUNET_TIME_Absolute start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Youngest row in the results.
|
||||||
|
*/
|
||||||
|
struct GNUNET_TIME_Absolute end;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Values to implement the "/history" range.
|
||||||
|
*/
|
||||||
|
struct HistoryRangeIds
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (Exclusive) row ID for the result set.
|
||||||
|
*/
|
||||||
|
unsigned long long start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How many transactions we want in the result set. If
|
||||||
|
* negative/positive, @a start will be strictly younger/older
|
||||||
|
* of any element in the result set.
|
||||||
|
*/
|
||||||
|
long long count;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the "base" structure for both the /history and the
|
||||||
|
* /history-range API calls.
|
||||||
|
*/
|
||||||
|
struct HistoryArgs
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Direction asked by the client: CREDIT / DEBIT / BOTH / CANCEL.
|
||||||
|
*/
|
||||||
|
enum TALER_BANK_Direction direction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bank account number of the requesting client.
|
||||||
|
*/
|
||||||
|
unsigned long long account_number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ordering of the results.
|
||||||
|
*/
|
||||||
|
unsigned int ascending;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overloaded type that indicates the "range" to be returned
|
||||||
|
* in the results; this can be either a date range, or a
|
||||||
|
* starting row id + the count.
|
||||||
|
*/
|
||||||
|
void *range;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for a function that decides whether or not
|
||||||
|
* the history-building loop should iterate once again.
|
||||||
|
* Typically called from inside the 'while' condition.
|
||||||
|
*
|
||||||
|
* @param ha history argument.
|
||||||
|
* @param pos current position.
|
||||||
|
* @return GNUNET_YES if the iteration shuold go on.
|
||||||
|
*/
|
||||||
|
typedef int (*CheckAdvance)
|
||||||
|
(const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type for a function that steps over the next element
|
||||||
|
* in the list of all transactions, after the current @a pos
|
||||||
|
* _got_ included in the result.
|
||||||
|
*/
|
||||||
|
typedef struct Transaction * (*Step)
|
||||||
|
(const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Type for a function that steps over the next element
|
||||||
|
* in the list of all transactions, after the current @a pos
|
||||||
|
* did _not_ get included in the result.
|
||||||
|
*/
|
||||||
|
typedef struct Transaction * (*Skip)
|
||||||
|
(const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actual history response builder.
|
||||||
|
*
|
||||||
|
* @param pos first (included) element in the result set.
|
||||||
|
* @param ha history arguments.
|
||||||
|
* @param caller_name which function is building the history.
|
||||||
|
* @return MHD_YES / MHD_NO, after having enqueued the response
|
||||||
|
* object into MHD.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TFH_build_history_response (struct MHD_Connection *connection,
|
||||||
|
struct Transaction *pos,
|
||||||
|
struct HistoryArgs *ha,
|
||||||
|
Skip skip,
|
||||||
|
Step step,
|
||||||
|
CheckAdvance advance);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse URL history arguments, of _both_ APIs:
|
||||||
|
* /history and /history-range.
|
||||||
|
*
|
||||||
|
* @param connection MHD connection.
|
||||||
|
* @param function_name name of the caller.
|
||||||
|
* @param ha[out] will contain the parsed values.
|
||||||
|
* @return GNUNET_OK only if the parsing succeedes.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TFH_parse_history_common_args (struct MHD_Connection *connection,
|
||||||
|
struct HistoryArgs *ha);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decides whether the history builder will advance or not
|
||||||
|
* to the next element.
|
||||||
|
*
|
||||||
|
* @param ha history args
|
||||||
|
* @return GNUNET_YES/NO to advance/not-advance.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TFH_handle_history_advance (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates on the "next" element to be processed. To
|
||||||
|
* be used when the current element does not get inserted in
|
||||||
|
* the result.
|
||||||
|
*
|
||||||
|
* @param ha history arguments.
|
||||||
|
* @param pos current element being processed.
|
||||||
|
* @return the next element to be processed.
|
||||||
|
*/
|
||||||
|
struct Transaction *
|
||||||
|
TFH_handle_history_skip (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates on the "next" element to be processed. To
|
||||||
|
* be used when the current element _gets_ inserted in the result.
|
||||||
|
*
|
||||||
|
* @param ha history arguments.
|
||||||
|
* @param pos current element being processed.
|
||||||
|
* @return the next element to be processed.
|
||||||
|
*/
|
||||||
|
struct Transaction *
|
||||||
|
TFH_handle_history_step (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decides whether the history builder will advance or not
|
||||||
|
* to the next element.
|
||||||
|
*
|
||||||
|
* @param ha history args
|
||||||
|
* @return GNUNET_YES/NO to advance/not-advance.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TFH_handle_history_range_advance (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates towards the "next" element to be processed. To
|
||||||
|
* be used when the current element does not get inserted in
|
||||||
|
* the result.
|
||||||
|
*
|
||||||
|
* @param ha history arguments.
|
||||||
|
* @param pos current element being processed.
|
||||||
|
* @return the next element to be processed.
|
||||||
|
*/
|
||||||
|
struct Transaction *
|
||||||
|
TFH_handle_history_range_skip (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates on the "next" element to be processed. To
|
||||||
|
* be used when the current element _gets_ inserted in the result.
|
||||||
|
* Same implementation of the "skip" counterpart, as /history-range
|
||||||
|
* does not have the notion of count/delta.
|
||||||
|
*/
|
||||||
|
Step TFH_handle_history_range_step;
|
||||||
|
#endif
|
427
src/bank-lib/fakebank_history.c
Normal file
427
src/bank-lib/fakebank_history.c
Normal file
@ -0,0 +1,427 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
(C) 2016, 2017, 2018 Inria and GNUnet e.V.
|
||||||
|
|
||||||
|
TALER is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU 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 bank-lib/fakebank_history.c
|
||||||
|
* @brief definitions for the "/history[-range]" layer.
|
||||||
|
* @author Marcello Stanisci <stanisci.m@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "platform.h"
|
||||||
|
#include <gnunet/gnunet_util_lib.h>
|
||||||
|
#include "taler_json_lib.h"
|
||||||
|
#include "fakebank.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decides whether the history builder will advance or not
|
||||||
|
* to the next element.
|
||||||
|
*
|
||||||
|
* @param ha history args
|
||||||
|
* @return GNUNET_YES/NO to advance/not-advance.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TFH_handle_history_advance (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos)
|
||||||
|
{
|
||||||
|
const struct HistoryRangeIds *hri = ha->range;
|
||||||
|
|
||||||
|
return (NULL != pos) && (0 != hri->count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates on the "next" element to be processed. To
|
||||||
|
* be used when the current element does not get inserted in
|
||||||
|
* the result.
|
||||||
|
*
|
||||||
|
* @param ha history arguments.
|
||||||
|
* @param pos current element being processed.
|
||||||
|
* @return the next element to be processed.
|
||||||
|
*/
|
||||||
|
struct Transaction *
|
||||||
|
TFH_handle_history_skip (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos)
|
||||||
|
{
|
||||||
|
const struct HistoryRangeIds *hri = ha->range;
|
||||||
|
|
||||||
|
if (hri->count > 0)
|
||||||
|
return pos->next;
|
||||||
|
if (hri->count < 0)
|
||||||
|
return pos->prev;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates on the "next" element to be processed. To
|
||||||
|
* be used when the current element _gets_ inserted in the result.
|
||||||
|
*
|
||||||
|
* @param ha history arguments.
|
||||||
|
* @param pos current element being processed.
|
||||||
|
* @return the next element to be processed.
|
||||||
|
*/
|
||||||
|
struct Transaction *
|
||||||
|
TFH_handle_history_step (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos)
|
||||||
|
{
|
||||||
|
struct HistoryRangeIds *hri = ha->range;
|
||||||
|
|
||||||
|
if (hri->count > 0)
|
||||||
|
{
|
||||||
|
hri->count--;
|
||||||
|
return pos->next;
|
||||||
|
}
|
||||||
|
if (hri->count < 0)
|
||||||
|
{
|
||||||
|
hri->count++;
|
||||||
|
return pos->prev;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decides whether the history builder will advance or not
|
||||||
|
* to the next element.
|
||||||
|
*
|
||||||
|
* @param ha history args
|
||||||
|
* @return GNUNET_YES/NO to advance/not-advance.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TFH_handle_history_range_advance (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos)
|
||||||
|
{
|
||||||
|
const struct HistoryRangeDates *hrd = ha->range;
|
||||||
|
|
||||||
|
if ( (NULL != pos) &&
|
||||||
|
(pos->date.abs_value_us <= hrd->end.abs_value_us) )
|
||||||
|
return GNUNET_YES;
|
||||||
|
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates towards the "next" element to be processed. To
|
||||||
|
* be used when the current element does not get inserted in
|
||||||
|
* the result.
|
||||||
|
*
|
||||||
|
* @param ha history arguments.
|
||||||
|
* @param pos current element being processed.
|
||||||
|
* @return the next element to be processed.
|
||||||
|
*/
|
||||||
|
struct Transaction *
|
||||||
|
TFH_handle_history_range_skip (const struct HistoryArgs *ha,
|
||||||
|
const struct Transaction *pos)
|
||||||
|
{
|
||||||
|
/* Transactions
|
||||||
|
* are stored from "head"/older to "tail"/younger. */
|
||||||
|
return pos->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates on the "next" element to be processed. To
|
||||||
|
* be used when the current element _gets_ inserted in the result.
|
||||||
|
* Same implementation of the "skip" counterpart, as /history-range
|
||||||
|
* does not have the notion of count/delta.
|
||||||
|
*/
|
||||||
|
Step TFH_handle_history_range_step = &TFH_handle_history_range_skip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actual history response builder.
|
||||||
|
*
|
||||||
|
* @param pos first (included) element in the result set.
|
||||||
|
* @param ha history arguments.
|
||||||
|
* @param caller_name which function is building the history.
|
||||||
|
* @return MHD_YES / MHD_NO, after having enqueued the response
|
||||||
|
* object into MHD.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TFH_build_history_response (struct MHD_Connection *connection,
|
||||||
|
struct Transaction *pos,
|
||||||
|
struct HistoryArgs *ha,
|
||||||
|
Skip skip,
|
||||||
|
Step step,
|
||||||
|
CheckAdvance advance)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct HistoryElement *history_results_head = NULL;
|
||||||
|
struct HistoryElement *history_results_tail = NULL;
|
||||||
|
struct HistoryElement *history_element = NULL;
|
||||||
|
json_t *history;
|
||||||
|
json_t *jresponse;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while (advance (ha,
|
||||||
|
pos))
|
||||||
|
{
|
||||||
|
json_t *trans;
|
||||||
|
char *subject;
|
||||||
|
const char *sign;
|
||||||
|
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
|
"Found transaction over %s from %llu to %llu\n",
|
||||||
|
TALER_amount2s (&pos->amount),
|
||||||
|
(unsigned long long) pos->debit_account,
|
||||||
|
(unsigned long long) pos->credit_account);
|
||||||
|
|
||||||
|
if ( (! ( ( (ha->account_number == pos->debit_account) &&
|
||||||
|
(0 != (ha->direction & TALER_BANK_DIRECTION_DEBIT)) ) ||
|
||||||
|
( (ha->account_number == pos->credit_account) &&
|
||||||
|
(0 != (ha->direction & TALER_BANK_DIRECTION_CREDIT) ) ) ) ) ||
|
||||||
|
( (0 == (ha->direction & TALER_BANK_DIRECTION_CANCEL)) &&
|
||||||
|
(GNUNET_YES == pos->rejected) ) )
|
||||||
|
{
|
||||||
|
pos = skip (ha,
|
||||||
|
pos);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GNUNET_asprintf (&subject,
|
||||||
|
"%s %s",
|
||||||
|
pos->subject,
|
||||||
|
pos->exchange_base_url);
|
||||||
|
sign =
|
||||||
|
(ha->account_number == pos->debit_account)
|
||||||
|
? (pos->rejected ? "cancel-" : "-")
|
||||||
|
: (pos->rejected ? "cancel+" : "+");
|
||||||
|
trans = json_pack
|
||||||
|
("{s:I, s:o, s:o, s:s, s:I, s:s}",
|
||||||
|
"row_id", (json_int_t) pos->row_id,
|
||||||
|
"date", GNUNET_JSON_from_time_abs (pos->date),
|
||||||
|
"amount", TALER_JSON_from_amount (&pos->amount),
|
||||||
|
"sign", sign,
|
||||||
|
"counterpart", (json_int_t)
|
||||||
|
( (ha->account_number == pos->debit_account)
|
||||||
|
? pos->credit_account
|
||||||
|
: pos->debit_account),
|
||||||
|
"wt_subject", subject);
|
||||||
|
GNUNET_assert (NULL != trans);
|
||||||
|
GNUNET_free (subject);
|
||||||
|
|
||||||
|
history_element = GNUNET_new (struct HistoryElement);
|
||||||
|
history_element->element = trans;
|
||||||
|
|
||||||
|
|
||||||
|
/* XXX: the ordering feature is missing. */
|
||||||
|
|
||||||
|
GNUNET_CONTAINER_DLL_insert_tail (history_results_head,
|
||||||
|
history_results_tail,
|
||||||
|
history_element);
|
||||||
|
pos = step (ha, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
history = json_array ();
|
||||||
|
if (NULL != history_results_head)
|
||||||
|
history_element = history_results_head;
|
||||||
|
|
||||||
|
while (NULL != history_element)
|
||||||
|
{
|
||||||
|
json_array_append_new (history,
|
||||||
|
history_element->element);
|
||||||
|
history_element = history_element->next;
|
||||||
|
if (NULL != history_element)
|
||||||
|
GNUNET_free_non_null (history_element->prev);
|
||||||
|
}
|
||||||
|
GNUNET_free_non_null (history_results_tail);
|
||||||
|
|
||||||
|
if (0 == json_array_size (history))
|
||||||
|
{
|
||||||
|
struct MHD_Response *resp;
|
||||||
|
|
||||||
|
json_decref (history);
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||||
|
"Returning empty transaction history\n");
|
||||||
|
resp = MHD_create_response_from_buffer
|
||||||
|
(0,
|
||||||
|
"",
|
||||||
|
MHD_RESPMEM_PERSISTENT);
|
||||||
|
ret = MHD_queue_response (connection,
|
||||||
|
MHD_HTTP_NO_CONTENT,
|
||||||
|
resp);
|
||||||
|
MHD_destroy_response (resp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
jresponse = json_pack ("{s:o}",
|
||||||
|
"data",
|
||||||
|
history);
|
||||||
|
if (NULL == jresponse)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally build response object */
|
||||||
|
{
|
||||||
|
struct MHD_Response *resp;
|
||||||
|
void *json_str;
|
||||||
|
size_t json_len;
|
||||||
|
|
||||||
|
json_str = json_dumps (jresponse,
|
||||||
|
JSON_INDENT(2));
|
||||||
|
json_decref (jresponse);
|
||||||
|
if (NULL == json_str)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
json_len = strlen (json_str);
|
||||||
|
resp = MHD_create_response_from_buffer (json_len,
|
||||||
|
json_str,
|
||||||
|
MHD_RESPMEM_MUST_FREE);
|
||||||
|
if (NULL == resp)
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
free (json_str);
|
||||||
|
return MHD_NO;
|
||||||
|
}
|
||||||
|
(void) MHD_add_response_header (resp,
|
||||||
|
MHD_HTTP_HEADER_CONTENT_TYPE,
|
||||||
|
"application/json");
|
||||||
|
ret = MHD_queue_response (connection,
|
||||||
|
MHD_HTTP_OK,
|
||||||
|
resp);
|
||||||
|
MHD_destroy_response (resp);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse URL history arguments, of _both_ APIs:
|
||||||
|
* /history and /history-range.
|
||||||
|
*
|
||||||
|
* @param connection MHD connection.
|
||||||
|
* @param function_name name of the caller.
|
||||||
|
* @param ha[out] will contain the parsed values.
|
||||||
|
* @return GNUNET_OK only if the parsing succeedes.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
TFH_parse_history_common_args (struct MHD_Connection *connection,
|
||||||
|
struct HistoryArgs *ha)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @variable
|
||||||
|
* Just check if given and == "basic", no need to keep around.
|
||||||
|
*/
|
||||||
|
const char *auth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All those will go into the structure, after parsing.
|
||||||
|
*/
|
||||||
|
const char *direction;
|
||||||
|
const char *cancelled;
|
||||||
|
const char *ordering;
|
||||||
|
const char *account_number;
|
||||||
|
|
||||||
|
|
||||||
|
auth = MHD_lookup_connection_value (connection,
|
||||||
|
MHD_GET_ARGUMENT_KIND,
|
||||||
|
"auth");
|
||||||
|
direction = MHD_lookup_connection_value (connection,
|
||||||
|
MHD_GET_ARGUMENT_KIND,
|
||||||
|
"direction");
|
||||||
|
cancelled = MHD_lookup_connection_value (connection,
|
||||||
|
MHD_GET_ARGUMENT_KIND,
|
||||||
|
"cancelled");
|
||||||
|
ordering = MHD_lookup_connection_value (connection,
|
||||||
|
MHD_GET_ARGUMENT_KIND,
|
||||||
|
"ordering");
|
||||||
|
account_number = MHD_lookup_connection_value
|
||||||
|
(connection,
|
||||||
|
MHD_GET_ARGUMENT_KIND,
|
||||||
|
"account_number");
|
||||||
|
|
||||||
|
/* Fail if one of the above failed. */
|
||||||
|
if ( (NULL == direction) ||
|
||||||
|
(NULL == cancelled) ||
|
||||||
|
( (0 != strcasecmp (cancelled,
|
||||||
|
"OMIT")) &&
|
||||||
|
(0 != strcasecmp (cancelled,
|
||||||
|
"SHOW")) ) ||
|
||||||
|
( (0 != strcasecmp (direction,
|
||||||
|
"BOTH")) &&
|
||||||
|
(0 != strcasecmp (direction,
|
||||||
|
"CREDIT")) &&
|
||||||
|
(0 != strcasecmp (direction,
|
||||||
|
"DEBIT")) ) ||
|
||||||
|
(1 != sscanf (account_number,
|
||||||
|
"%llu",
|
||||||
|
&ha->account_number)) ||
|
||||||
|
( (NULL == auth) || (0 != strcasecmp (auth,
|
||||||
|
"basic")) ) )
|
||||||
|
{
|
||||||
|
/* Invalid request, given that this is fakebank we impolitely
|
||||||
|
* just kill the connection instead of returning a nice error.
|
||||||
|
*/
|
||||||
|
GNUNET_break (0);
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcasecmp (direction,
|
||||||
|
"CREDIT"))
|
||||||
|
{
|
||||||
|
ha->direction = TALER_BANK_DIRECTION_CREDIT;
|
||||||
|
}
|
||||||
|
else if (0 == strcasecmp (direction,
|
||||||
|
"DEBIT"))
|
||||||
|
{
|
||||||
|
ha->direction = TALER_BANK_DIRECTION_DEBIT;
|
||||||
|
}
|
||||||
|
else if (0 == strcasecmp (direction,
|
||||||
|
"BOTH"))
|
||||||
|
{
|
||||||
|
ha->direction = TALER_BANK_DIRECTION_BOTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Direction is invalid. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcasecmp (cancelled,
|
||||||
|
"OMIT"))
|
||||||
|
{
|
||||||
|
/* nothing */
|
||||||
|
} else if (0 == strcasecmp (cancelled,
|
||||||
|
"SHOW"))
|
||||||
|
{
|
||||||
|
ha->direction |= TALER_BANK_DIRECTION_CANCEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cancel-showing policy is invalid. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GNUNET_break (0);
|
||||||
|
return GNUNET_NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((NULL != ordering)
|
||||||
|
&& 0 == strcmp ("ascending",
|
||||||
|
ordering))
|
||||||
|
ha->ascending = GNUNET_YES;
|
||||||
|
else
|
||||||
|
ha->ascending = GNUNET_NO;
|
||||||
|
|
||||||
|
return GNUNET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user