gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-exchange] 07/08: Put /history[-range] logic in a ded


From: gnunet
Subject: [GNUnet-SVN] [taler-exchange] 07/08: Put /history[-range] logic in a dedicate file.
Date: Mon, 08 Apr 2019 02:44:39 +0200

This is an automated email from the git hooks/post-receive script.

marcello pushed a commit to branch master
in repository exchange.

commit e13a8902f07a7848d09204cd6f1b9736fe3cf885
Author: Marcello Stanisci <address@hidden>
AuthorDate: Mon Apr 8 02:09:23 2019 +0200

    Put /history[-range] logic in a dedicate file.
---
 .gitignore                      |   1 +
 src/bank-lib/Makefile.am        |   1 +
 src/bank-lib/fakebank.c         | 954 +---------------------------------------
 src/bank-lib/fakebank.h         | 322 ++++++++++++++
 src/bank-lib/fakebank_history.c | 427 ++++++++++++++++++
 5 files changed, 768 insertions(+), 937 deletions(-)

diff --git a/.gitignore b/.gitignore
index 8696558d..6f7a0258 100644
--- a/.gitignore
+++ b/.gitignore
@@ -115,3 +115,4 @@ src/bank-lib/test_bank_api_twisted
 src/lib/test_exchange_api_new
 src/lib/test_auditor_api
 src/lib/test_exchange_api_overlapping_keys_bug
+src/lib/test_exchange_api_home/.local/share/taler/exchange/revocations/
diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am
index e6e2e878..ddc4cf4b 100644
--- a/src/bank-lib/Makefile.am
+++ b/src/bank-lib/Makefile.am
@@ -57,6 +57,7 @@ libtalerfakebank_la_LDFLAGS = \
   -no-undefined
 
 libtalerfakebank_la_SOURCES = \
+  fakebank_history.c \
   fakebank.c
 
 libtalerfakebank_la_LIBADD = \
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c
index f3b58fd2..37aae042 100644
--- a/src/bank-lib/fakebank.c
+++ b/src/bank-lib/fakebank.c
@@ -25,6 +25,7 @@
 #include "platform.h"
 #include "taler_fakebank_lib.h"
 #include "taler_bank_service.h"
+#include "fakebank.h"
 
 /**
  * Maximum POST request size (for /admin/add/incoming)
@@ -33,169 +34,6 @@
 
 
 /**
- * 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.
  */
 struct TALER_FAKEBANK_Handle
@@ -746,442 +584,6 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,
   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
  *
@@ -1201,8 +603,8 @@ handle_history_new (struct TALER_FAKEBANK_Handle *h,
   const char *delta;
   struct Transaction *pos;
 
-  if (GNUNET_OK != parse_history_common_args (connection,
-                                              &ha))
+  if (GNUNET_OK != TFH_parse_history_common_args (connection,
+                                                  &ha))
   {
     GNUNET_break (0);
     return MHD_NO;
@@ -1259,12 +661,12 @@ handle_history_new (struct TALER_FAKEBANK_Handle *h,
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
               "/history, start row (0 == no transactions exist): %llu\n",
               NULL != pos ? pos->row_id : 0);
-  return build_history_response (connection,
-                                 pos,
-                                 &ha,
-                                 &handle_history_skip,
-                                 &handle_history_step,
-                                 &handle_history_advance);
+  return TFH_build_history_response (connection,
+                                     pos,
+                                     &ha,
+                                     &TFH_handle_history_skip,
+                                     &TFH_handle_history_step,
+                                     &TFH_handle_history_advance);
 }
 
 /**
@@ -1288,7 +690,7 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h,
   long long unsigned int end_stamp; 
   struct Transaction *pos;
 
-  if (GNUNET_OK != parse_history_common_args (connection,
+  if (GNUNET_OK != TFH_parse_history_common_args (connection,
                                               &ha))
   {
     GNUNET_break (0);
@@ -1309,7 +711,7 @@ handle_history_range (struct TALER_FAKEBANK_Handle *h,
                                    &end_stamp)) )
   {
     GNUNET_break (0);
-    return GNUNET_NO;
+    return MHD_NO;
   }
 
   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)
       break; 
   }
-  return build_history_response (connection,
-                                 pos,
-                                 &ha,
-                                 &handle_history_range_skip,
-                                 handle_history_range_step,
-                                 &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;
+  return TFH_build_history_response (connection,
+                                     pos,
+                                     &ha,
+                                     &TFH_handle_history_range_skip,
+                                     TFH_handle_history_range_step,
+                                     &TFH_handle_history_range_advance);
 }
 
-/***********************************
- * End of /history implementation. *
- ***********************************/
-
 /**
  * Handle incoming HTTP request.
  *
diff --git a/src/bank-lib/fakebank.h b/src/bank-lib/fakebank.h
new file mode 100644
index 00000000..4e81b353
--- /dev/null
+++ b/src/bank-lib/fakebank.h
@@ -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 <address@hidden>
+ */
+
+#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
diff --git a/src/bank-lib/fakebank_history.c b/src/bank-lib/fakebank_history.c
new file mode 100644
index 00000000..17960a4e
--- /dev/null
+++ b/src/bank-lib/fakebank_history.c
@@ -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 <address@hidden>
+ */
+
+#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;
+}
+
+

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]