From a26a29065c81665200d3098cb0b84ac17b496959 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 3 Aug 2021 12:03:48 +0200 Subject: rename: taler-wire-gateway-client to taler-exchange-wire-gateway-client --- src/bank-lib/Makefile.am | 8 +- src/bank-lib/taler-exchange-wire-gateway-client.c | 748 ++++++++++++++++++++++ src/bank-lib/taler-wire-gateway-client.c | 748 ---------------------- 3 files changed, 752 insertions(+), 752 deletions(-) create mode 100644 src/bank-lib/taler-exchange-wire-gateway-client.c delete mode 100644 src/bank-lib/taler-wire-gateway-client.c (limited to 'src') diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am index a520b24df..78349dc8d 100644 --- a/src/bank-lib/Makefile.am +++ b/src/bank-lib/Makefile.am @@ -7,7 +7,7 @@ if USE_COVERAGE endif bin_PROGRAMS = \ - taler-wire-gateway-client \ + taler-exchange-wire-gateway-client \ taler-fakebank-run taler_fakebank_run_SOURCES = \ @@ -17,9 +17,9 @@ taler_fakebank_run_LDADD = \ $(top_builddir)/src/util/libtalerutil.la \ -lgnunetutil -taler_wire_gateway_client_SOURCES = \ - taler-wire-gateway-client.c -taler_wire_gateway_client_LDADD = \ +taler_exchange_wire_gateway_client_SOURCES = \ + taler-exchange-wire-gateway-client.c +taler_exchange_wire_gateway_client_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/util/libtalerutil.la \ $(top_builddir)/src/json/libtalerjson.la \ diff --git a/src/bank-lib/taler-exchange-wire-gateway-client.c b/src/bank-lib/taler-exchange-wire-gateway-client.c new file mode 100644 index 000000000..c10b4ddde --- /dev/null +++ b/src/bank-lib/taler-exchange-wire-gateway-client.c @@ -0,0 +1,748 @@ +/* + This file is part of TALER + Copyright (C) 2017-2020 Taler Systems SA + + 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 +*/ +/** + * @file taler-wire-gateway-client.c + * @brief Execute wire transfer. + * @author Christian Grothoff + */ +#include "platform.h" +#include +#include +#include +#include "taler_bank_service.h" + +/** + * If set to #GNUNET_YES, then we'll ask the bank for a list + * of incoming transactions from the account. + */ +static int incoming_history; + +/** + * If set to #GNUNET_YES, then we'll ask the bank for a list + * of outgoing transactions from the account. + */ +static int outgoing_history; + +/** + * Amount to transfer. + */ +static struct TALER_Amount amount; + +/** + * Credit account payto://-URI. + */ +static char *credit_account; + +/** + * Debit account payto://-URI. + */ +static char *debit_account; + +/** + * Wire transfer subject. + */ +static char *subject; + +/** + * Which config section has the credentials to access the bank. + */ +static char *account_section; + +/** + * Starting row. + */ +static unsigned long long start_row; + +/** + * Authentication data. + */ +static struct TALER_BANK_AuthenticationData auth; + +/** + * Return value from main(). + */ +static int global_ret = 1; + +/** + * Main execution context for the main loop. + */ +static struct GNUNET_CURL_Context *ctx; + +/** + * Handle to ongoing credit history operation. + */ +static struct TALER_BANK_CreditHistoryHandle *chh; + +/** + * Handle to ongoing debit history operation. + */ +static struct TALER_BANK_DebitHistoryHandle *dhh; + +/** + * Handle for executing the wire transfer. + */ +static struct TALER_BANK_TransferHandle *eh; + +/** + * Handle to access the exchange. + */ +static struct TALER_BANK_AdminAddIncomingHandle *op; + +/** + * Context for running the CURL event loop. + */ +static struct GNUNET_CURL_RescheduleContext *rc; + + +/** + * Function run when the test terminates (good or bad). + * Cleans up our state. + * + * @param cls NULL + */ +static void +do_shutdown (void *cls) +{ + (void) cls; + if (NULL != op) + { + TALER_BANK_admin_add_incoming_cancel (op); + op = NULL; + } + if (NULL != chh) + { + TALER_BANK_credit_history_cancel (chh); + chh = NULL; + } + if (NULL != dhh) + { + TALER_BANK_debit_history_cancel (dhh); + dhh = NULL; + } + if (NULL != eh) + { + TALER_BANK_transfer_cancel (eh); + eh = NULL; + } + if (NULL != ctx) + { + GNUNET_CURL_fini (ctx); + ctx = NULL; + } + if (NULL != rc) + { + GNUNET_CURL_gnunet_rc_destroy (rc); + rc = NULL; + } + TALER_BANK_auth_free (&auth); +} + + +/** + * Callback used to process ONE entry in the transaction + * history returned by the bank. + * + * @param cls closure + * @param http_status HTTP status code from server + * @param ec taler error code + * @param serial_id identification of the position at + * which we are returning data + * @param details details about the wire transfer + * @param json original full response from server + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to + * abort iteration + */ +static int +credit_history_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t serial_id, + const struct TALER_BANK_CreditDetails *details, + const json_t *json) +{ + (void) cls; + + if (MHD_HTTP_OK != http_status) + { + if ( (MHD_HTTP_NO_CONTENT != http_status) || + (TALER_EC_NONE != ec) || + (NULL == details) ) + { + fprintf (stderr, + "Failed to obtain credit history: %u/%d\n", + http_status, + ec); + if (NULL != json) + json_dumpf (json, + stderr, + JSON_INDENT (2)); + global_ret = 2; + GNUNET_SCHEDULER_shutdown (); + return GNUNET_NO; + } + fprintf (stdout, + "End of transactions list.\n"); + global_ret = 0; + GNUNET_SCHEDULER_shutdown (); + return GNUNET_NO; + } + + /* If credit/debit accounts were specified, use as a filter */ + if ( (NULL != credit_account) && + (0 != strcasecmp (credit_account, + details->credit_account_url) ) ) + return GNUNET_OK; + if ( (NULL != debit_account) && + (0 != strcasecmp (debit_account, + details->debit_account_url) ) ) + return GNUNET_OK; + + fprintf (stdout, + "%llu: %s->%s (%s) over %s at %s\n", + (unsigned long long) serial_id, + details->debit_account_url, + details->credit_account_url, + TALER_B2S (&details->reserve_pub), + TALER_amount2s (&details->amount), + GNUNET_STRINGS_absolute_time_to_string (details->execution_date)); + return GNUNET_OK; +} + + +/** + * Ask the bank the list of transactions for the bank account + * mentioned in the config section given by the user. + */ +static void +execute_credit_history (void) +{ + if (NULL != subject) + { + fprintf (stderr, + "Specifying subject is not supported when inspecting credit history\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + chh = TALER_BANK_credit_history (ctx, + &auth, + start_row, + -10, + &credit_history_cb, + NULL); + if (NULL == chh) + { + fprintf (stderr, + "Could not request the credit transaction history.\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } +} + + +/** + * Function with the debit debit transaction history. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the bank's reply is bogus (fails to follow the protocol), + * #MHD_HTTP_NO_CONTENT if there are no more results; on success the + * last callback is always of this status (even if `abs(num_results)` were + * already returned). + * @param ec detailed error code + * @param serial_id monotonically increasing counter corresponding to the transaction + * @param details details about the wire transfer + * @param json detailed response from the HTTPD, or NULL if reply was not in JSON + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration + */ +static int +debit_history_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t serial_id, + const struct TALER_BANK_DebitDetails *details, + const json_t *json) +{ + (void) cls; + + if (MHD_HTTP_OK != http_status) + { + if ( (MHD_HTTP_NO_CONTENT != http_status) || + (TALER_EC_NONE != ec) || + (NULL == details) ) + { + fprintf (stderr, + "Failed to obtain debit history: %u/%d\n", + http_status, + ec); + if (NULL != json) + json_dumpf (json, + stderr, + JSON_INDENT (2)); + global_ret = 2; + GNUNET_SCHEDULER_shutdown (); + return GNUNET_NO; + } + fprintf (stdout, + "End of transactions list.\n"); + global_ret = 0; + GNUNET_SCHEDULER_shutdown (); + return GNUNET_NO; + } + + /* If credit/debit accounts were specified, use as a filter */ + if ( (NULL != credit_account) && + (0 != strcasecmp (credit_account, + details->credit_account_url) ) ) + return GNUNET_OK; + if ( (NULL != debit_account) && + (0 != strcasecmp (debit_account, + details->debit_account_url) ) ) + return GNUNET_OK; + + fprintf (stdout, + "%llu: %s->%s (%s) over %s at %s\n", + (unsigned long long) serial_id, + details->debit_account_url, + details->credit_account_url, + TALER_B2S (&details->wtid), + TALER_amount2s (&details->amount), + GNUNET_STRINGS_absolute_time_to_string (details->execution_date)); + return GNUNET_OK; +} + + +/** + * Ask the bank the list of transactions for the bank account + * mentioned in the config section given by the user. + */ +static void +execute_debit_history (void) +{ + if (NULL != subject) + { + fprintf (stderr, + "Specifying subject is not supported when inspecting debit history\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + dhh = TALER_BANK_debit_history (ctx, + &auth, + start_row, + -10, + &debit_history_cb, + NULL); + if (NULL == dhh) + { + fprintf (stderr, + "Could not request the debit transaction history.\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } +} + + +/** + * Callback that processes the outcome of a wire transfer + * execution. + * + * @param cls closure + * @param response_code HTTP status code + * @param ec taler error code + * @param row_id unique ID of the wire transfer in the bank's records + * @param timestamp when did the transaction go into effect + */ +static void +confirmation_cb (void *cls, + unsigned int response_code, + enum TALER_ErrorCode ec, + uint64_t row_id, + struct GNUNET_TIME_Absolute timestamp) +{ + (void) cls; + eh = NULL; + if (MHD_HTTP_OK != response_code) + { + fprintf (stderr, + "The wire transfer didn't execute correctly (%u/%d).\n", + response_code, + ec); + GNUNET_SCHEDULER_shutdown (); + return; + } + + fprintf (stdout, + "Wire transfer #%llu executed successfully at %s.\n", + (unsigned long long) row_id, + GNUNET_STRINGS_absolute_time_to_string (timestamp)); + global_ret = 0; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Ask the bank to execute a wire transfer. + */ +static void +execute_wire_transfer (void) +{ + struct TALER_WireTransferIdentifierRawP wtid; + void *buf; + size_t buf_size; + char *params; + + if (NULL != debit_account) + { + fprintf (stderr, + "Invalid option -C specified, conflicts with -D\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + + // See if subject was given as a payto-parameter. + if (NULL == subject) + subject = TALER_payto_get_subject (credit_account); + if (NULL != subject) + { + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (subject, + strlen (subject), + &wtid, + sizeof (wtid))) + { + fprintf (stderr, + "Error: wire transfer subject must be a WTID\n"); + return; + } + GNUNET_SCHEDULER_shutdown (); + return; + } + else + { + /* pick one at random */ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &wtid, + sizeof (wtid)); + } + params = strchr (credit_account, + (unsigned char) '&'); + if (NULL != params) + *params = '\0'; + TALER_BANK_prepare_transfer (credit_account, + &amount, + "http://exchange.example.com/", + &wtid, + &buf, + &buf_size); + eh = TALER_BANK_transfer (ctx, + &auth, + buf, + buf_size, + &confirmation_cb, + NULL); + if (NULL == eh) + { + fprintf (stderr, + "Could not execute the wire transfer\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } +} + + +/** + * Function called with the result of the operation. + * + * @param cls closure + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request + * 0 if the bank's reply is bogus (fails to follow the protocol) + * @param ec detailed error code + * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error + * @param timestamp timestamp when the transaction got settled at the bank. + * @param json detailed response from the HTTPD, or NULL if reply was not in JSON + */ +static void +res_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + uint64_t serial_id, + struct GNUNET_TIME_Absolute timestamp, + const json_t *json) +{ + (void) cls; + (void) timestamp; + op = NULL; + switch (ec) + { + case TALER_EC_NONE: + global_ret = 0; + fprintf (stdout, + "%llu\n", + (unsigned long long) serial_id); + break; + default: + fprintf (stderr, + "Operation failed with status code %u/%u\n", + (unsigned int) ec, + http_status); + if (NULL != json) + json_dumpf (json, + stderr, + JSON_INDENT (2)); + break; + } + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Ask the bank to execute a wire transfer to the exchange. + */ +static void +execute_admin_transfer (void) +{ + struct TALER_ReservePublicKeyP reserve_pub; + + if (NULL != subject) + { + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (subject, + strlen (subject), + &reserve_pub, + sizeof (reserve_pub))) + { + fprintf (stderr, + "Error: wire transfer subject must be a reserve public key\n"); + return; + } + } + else + { + /* pick one that is kind-of well-formed at random */ + GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, + &reserve_pub, + sizeof (reserve_pub)); + } + op = TALER_BANK_admin_add_incoming (ctx, + &auth, + &reserve_pub, + &amount, + credit_account, + &res_cb, + NULL); + if (NULL == op) + { + fprintf (stderr, + "Could not execute the wire transfer to the exchange\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } +} + + +/** + * Main function that will be run. + * + * @param cls closure + * @param args remaining command-line arguments + * @param cfgfile name of the configuration file used (for saving, can be NULL!) + * @param cfg configuration + */ +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ + (void) cls; + (void) args; + (void) cfgfile; + (void) cfg; + + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &rc); + GNUNET_assert (NULL != ctx); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + if (NULL != account_section) + { + if ( (NULL != auth.wire_gateway_url) || + (NULL != auth.details.basic.username) || + (NULL != auth.details.basic.password) ) + { + fprintf (stderr, + "Conflicting authentication options provided. Please only use one method.\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_OK != + TALER_BANK_auth_parse_cfg (cfg, + account_section, + &auth)) + { + fprintf (stderr, + "Authentication information not found in configuration section `%s'\n", + account_section); + GNUNET_SCHEDULER_shutdown (); + return; + } + } + else + { + if ( (NULL != auth.wire_gateway_url) && + (NULL != auth.details.basic.username) && + (NULL != auth.details.basic.password) ) + { + auth.method = TALER_BANK_AUTH_BASIC; + } + else if (NULL == auth.wire_gateway_url) + { + fprintf (stderr, + "No account specified (use -b or -s options).\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + } + if ( (GNUNET_YES == incoming_history) && + (GNUNET_YES == outgoing_history) ) + { + fprintf (stderr, + "Please specify only -i or -o, but not both.\n"); + GNUNET_SCHEDULER_shutdown (); + return; + } + if (GNUNET_YES == incoming_history) + { + execute_credit_history (); + return; + } + if (GNUNET_YES == outgoing_history) + { + execute_debit_history (); + return; + } + if (NULL != credit_account) + { + execute_wire_transfer (); + return; + } + if (NULL != debit_account) + { + execute_admin_transfer (); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No operation specified.\n"); + global_ret = 0; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * The main function of the taler-bank-transfer tool + * + * @param argc number of arguments from the command line + * @param argv command line arguments + * @return 0 ok, 1 on error + */ +int +main (int argc, + char *const *argv) +{ + const struct GNUNET_GETOPT_CommandLineOption options[] = { + TALER_getopt_get_amount ('a', + "amount", + "VALUE", + "value to transfer", + &amount), + GNUNET_GETOPT_option_string ('b', + "bank", + "URL", + "Wire gateway URL to use to talk to the bank", + &auth.wire_gateway_url), + GNUNET_GETOPT_option_string ('C', + "credit", + "ACCOUNT", + "payto URI of the bank account to credit (when making outgoing transfers)", + &credit_account), + GNUNET_GETOPT_option_string ('D', + "debit", + "PAYTO-URL", + "payto URI of the bank account to debit (when making incoming transfers)", + &debit_account), + GNUNET_GETOPT_option_flag ('i', + "credit-history", + "Ask to get a list of 10 incoming transactions.", + &incoming_history), + GNUNET_GETOPT_option_flag ('o', + "debit-history", + "Ask to get a list of 10 outgoing transactions.", + &outgoing_history), + GNUNET_GETOPT_option_string ('p', + "pass", + "PASSPHRASE", + "passphrase to use for authentication", + &auth.details.basic.password), + GNUNET_GETOPT_option_string ('s', + "section", + "ACCOUNT-SECTION", + "Which config section has the credentials to access the bank. Conflicts with -b -u and -p options.\n", + &account_section), + GNUNET_GETOPT_option_string ('S', + "subject", + "SUBJECT", + "specifies the wire transfer subject", + &subject), + GNUNET_GETOPT_option_string ('u', + "user", + "USERNAME", + "username to use for authentication", + &auth.details.basic.username), + GNUNET_GETOPT_option_ulong ('w', + "since-when", + "ROW", + "When asking the bank for transactions history, this option commands that all the results should have IDs settled after SW. If not given, then the 10 youngest transactions are returned.", + &start_row), + GNUNET_GETOPT_OPTION_END + }; + enum GNUNET_GenericReturnValue ret; + + /* force linker to link against libtalerutil; if we do + not do this, the linker may "optimize" libtalerutil + away and skip #TALER_OS_init(), which we do need */ + (void) TALER_project_data_default (); + if (GNUNET_OK != + GNUNET_STRINGS_get_utf8_args (argc, argv, + &argc, &argv)) + return 4; + global_ret = 1; + ret = GNUNET_PROGRAM_run ( + argc, argv, + "taler-wire-gateway-client", + gettext_noop ("Client tool of the Taler Wire Gateway"), + options, + &run, NULL); + GNUNET_free_nz ((void *) argv); + if (GNUNET_SYSERR == ret) + return 3; + if (GNUNET_NO == ret) + return 0; + return global_ret; +} + + +/* end taler-wire-gateway-client.c */ diff --git a/src/bank-lib/taler-wire-gateway-client.c b/src/bank-lib/taler-wire-gateway-client.c deleted file mode 100644 index c10b4ddde..000000000 --- a/src/bank-lib/taler-wire-gateway-client.c +++ /dev/null @@ -1,748 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2017-2020 Taler Systems SA - - 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 -*/ -/** - * @file taler-wire-gateway-client.c - * @brief Execute wire transfer. - * @author Christian Grothoff - */ -#include "platform.h" -#include -#include -#include -#include "taler_bank_service.h" - -/** - * If set to #GNUNET_YES, then we'll ask the bank for a list - * of incoming transactions from the account. - */ -static int incoming_history; - -/** - * If set to #GNUNET_YES, then we'll ask the bank for a list - * of outgoing transactions from the account. - */ -static int outgoing_history; - -/** - * Amount to transfer. - */ -static struct TALER_Amount amount; - -/** - * Credit account payto://-URI. - */ -static char *credit_account; - -/** - * Debit account payto://-URI. - */ -static char *debit_account; - -/** - * Wire transfer subject. - */ -static char *subject; - -/** - * Which config section has the credentials to access the bank. - */ -static char *account_section; - -/** - * Starting row. - */ -static unsigned long long start_row; - -/** - * Authentication data. - */ -static struct TALER_BANK_AuthenticationData auth; - -/** - * Return value from main(). - */ -static int global_ret = 1; - -/** - * Main execution context for the main loop. - */ -static struct GNUNET_CURL_Context *ctx; - -/** - * Handle to ongoing credit history operation. - */ -static struct TALER_BANK_CreditHistoryHandle *chh; - -/** - * Handle to ongoing debit history operation. - */ -static struct TALER_BANK_DebitHistoryHandle *dhh; - -/** - * Handle for executing the wire transfer. - */ -static struct TALER_BANK_TransferHandle *eh; - -/** - * Handle to access the exchange. - */ -static struct TALER_BANK_AdminAddIncomingHandle *op; - -/** - * Context for running the CURL event loop. - */ -static struct GNUNET_CURL_RescheduleContext *rc; - - -/** - * Function run when the test terminates (good or bad). - * Cleans up our state. - * - * @param cls NULL - */ -static void -do_shutdown (void *cls) -{ - (void) cls; - if (NULL != op) - { - TALER_BANK_admin_add_incoming_cancel (op); - op = NULL; - } - if (NULL != chh) - { - TALER_BANK_credit_history_cancel (chh); - chh = NULL; - } - if (NULL != dhh) - { - TALER_BANK_debit_history_cancel (dhh); - dhh = NULL; - } - if (NULL != eh) - { - TALER_BANK_transfer_cancel (eh); - eh = NULL; - } - if (NULL != ctx) - { - GNUNET_CURL_fini (ctx); - ctx = NULL; - } - if (NULL != rc) - { - GNUNET_CURL_gnunet_rc_destroy (rc); - rc = NULL; - } - TALER_BANK_auth_free (&auth); -} - - -/** - * Callback used to process ONE entry in the transaction - * history returned by the bank. - * - * @param cls closure - * @param http_status HTTP status code from server - * @param ec taler error code - * @param serial_id identification of the position at - * which we are returning data - * @param details details about the wire transfer - * @param json original full response from server - * @return #GNUNET_OK to continue, #GNUNET_SYSERR to - * abort iteration - */ -static int -credit_history_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t serial_id, - const struct TALER_BANK_CreditDetails *details, - const json_t *json) -{ - (void) cls; - - if (MHD_HTTP_OK != http_status) - { - if ( (MHD_HTTP_NO_CONTENT != http_status) || - (TALER_EC_NONE != ec) || - (NULL == details) ) - { - fprintf (stderr, - "Failed to obtain credit history: %u/%d\n", - http_status, - ec); - if (NULL != json) - json_dumpf (json, - stderr, - JSON_INDENT (2)); - global_ret = 2; - GNUNET_SCHEDULER_shutdown (); - return GNUNET_NO; - } - fprintf (stdout, - "End of transactions list.\n"); - global_ret = 0; - GNUNET_SCHEDULER_shutdown (); - return GNUNET_NO; - } - - /* If credit/debit accounts were specified, use as a filter */ - if ( (NULL != credit_account) && - (0 != strcasecmp (credit_account, - details->credit_account_url) ) ) - return GNUNET_OK; - if ( (NULL != debit_account) && - (0 != strcasecmp (debit_account, - details->debit_account_url) ) ) - return GNUNET_OK; - - fprintf (stdout, - "%llu: %s->%s (%s) over %s at %s\n", - (unsigned long long) serial_id, - details->debit_account_url, - details->credit_account_url, - TALER_B2S (&details->reserve_pub), - TALER_amount2s (&details->amount), - GNUNET_STRINGS_absolute_time_to_string (details->execution_date)); - return GNUNET_OK; -} - - -/** - * Ask the bank the list of transactions for the bank account - * mentioned in the config section given by the user. - */ -static void -execute_credit_history (void) -{ - if (NULL != subject) - { - fprintf (stderr, - "Specifying subject is not supported when inspecting credit history\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } - chh = TALER_BANK_credit_history (ctx, - &auth, - start_row, - -10, - &credit_history_cb, - NULL); - if (NULL == chh) - { - fprintf (stderr, - "Could not request the credit transaction history.\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } -} - - -/** - * Function with the debit debit transaction history. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the bank's reply is bogus (fails to follow the protocol), - * #MHD_HTTP_NO_CONTENT if there are no more results; on success the - * last callback is always of this status (even if `abs(num_results)` were - * already returned). - * @param ec detailed error code - * @param serial_id monotonically increasing counter corresponding to the transaction - * @param details details about the wire transfer - * @param json detailed response from the HTTPD, or NULL if reply was not in JSON - * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration - */ -static int -debit_history_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t serial_id, - const struct TALER_BANK_DebitDetails *details, - const json_t *json) -{ - (void) cls; - - if (MHD_HTTP_OK != http_status) - { - if ( (MHD_HTTP_NO_CONTENT != http_status) || - (TALER_EC_NONE != ec) || - (NULL == details) ) - { - fprintf (stderr, - "Failed to obtain debit history: %u/%d\n", - http_status, - ec); - if (NULL != json) - json_dumpf (json, - stderr, - JSON_INDENT (2)); - global_ret = 2; - GNUNET_SCHEDULER_shutdown (); - return GNUNET_NO; - } - fprintf (stdout, - "End of transactions list.\n"); - global_ret = 0; - GNUNET_SCHEDULER_shutdown (); - return GNUNET_NO; - } - - /* If credit/debit accounts were specified, use as a filter */ - if ( (NULL != credit_account) && - (0 != strcasecmp (credit_account, - details->credit_account_url) ) ) - return GNUNET_OK; - if ( (NULL != debit_account) && - (0 != strcasecmp (debit_account, - details->debit_account_url) ) ) - return GNUNET_OK; - - fprintf (stdout, - "%llu: %s->%s (%s) over %s at %s\n", - (unsigned long long) serial_id, - details->debit_account_url, - details->credit_account_url, - TALER_B2S (&details->wtid), - TALER_amount2s (&details->amount), - GNUNET_STRINGS_absolute_time_to_string (details->execution_date)); - return GNUNET_OK; -} - - -/** - * Ask the bank the list of transactions for the bank account - * mentioned in the config section given by the user. - */ -static void -execute_debit_history (void) -{ - if (NULL != subject) - { - fprintf (stderr, - "Specifying subject is not supported when inspecting debit history\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } - dhh = TALER_BANK_debit_history (ctx, - &auth, - start_row, - -10, - &debit_history_cb, - NULL); - if (NULL == dhh) - { - fprintf (stderr, - "Could not request the debit transaction history.\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } -} - - -/** - * Callback that processes the outcome of a wire transfer - * execution. - * - * @param cls closure - * @param response_code HTTP status code - * @param ec taler error code - * @param row_id unique ID of the wire transfer in the bank's records - * @param timestamp when did the transaction go into effect - */ -static void -confirmation_cb (void *cls, - unsigned int response_code, - enum TALER_ErrorCode ec, - uint64_t row_id, - struct GNUNET_TIME_Absolute timestamp) -{ - (void) cls; - eh = NULL; - if (MHD_HTTP_OK != response_code) - { - fprintf (stderr, - "The wire transfer didn't execute correctly (%u/%d).\n", - response_code, - ec); - GNUNET_SCHEDULER_shutdown (); - return; - } - - fprintf (stdout, - "Wire transfer #%llu executed successfully at %s.\n", - (unsigned long long) row_id, - GNUNET_STRINGS_absolute_time_to_string (timestamp)); - global_ret = 0; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Ask the bank to execute a wire transfer. - */ -static void -execute_wire_transfer (void) -{ - struct TALER_WireTransferIdentifierRawP wtid; - void *buf; - size_t buf_size; - char *params; - - if (NULL != debit_account) - { - fprintf (stderr, - "Invalid option -C specified, conflicts with -D\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } - - // See if subject was given as a payto-parameter. - if (NULL == subject) - subject = TALER_payto_get_subject (credit_account); - if (NULL != subject) - { - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (subject, - strlen (subject), - &wtid, - sizeof (wtid))) - { - fprintf (stderr, - "Error: wire transfer subject must be a WTID\n"); - return; - } - GNUNET_SCHEDULER_shutdown (); - return; - } - else - { - /* pick one at random */ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, - &wtid, - sizeof (wtid)); - } - params = strchr (credit_account, - (unsigned char) '&'); - if (NULL != params) - *params = '\0'; - TALER_BANK_prepare_transfer (credit_account, - &amount, - "http://exchange.example.com/", - &wtid, - &buf, - &buf_size); - eh = TALER_BANK_transfer (ctx, - &auth, - buf, - buf_size, - &confirmation_cb, - NULL); - if (NULL == eh) - { - fprintf (stderr, - "Could not execute the wire transfer\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } -} - - -/** - * Function called with the result of the operation. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - * 0 if the bank's reply is bogus (fails to follow the protocol) - * @param ec detailed error code - * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error - * @param timestamp timestamp when the transaction got settled at the bank. - * @param json detailed response from the HTTPD, or NULL if reply was not in JSON - */ -static void -res_cb (void *cls, - unsigned int http_status, - enum TALER_ErrorCode ec, - uint64_t serial_id, - struct GNUNET_TIME_Absolute timestamp, - const json_t *json) -{ - (void) cls; - (void) timestamp; - op = NULL; - switch (ec) - { - case TALER_EC_NONE: - global_ret = 0; - fprintf (stdout, - "%llu\n", - (unsigned long long) serial_id); - break; - default: - fprintf (stderr, - "Operation failed with status code %u/%u\n", - (unsigned int) ec, - http_status); - if (NULL != json) - json_dumpf (json, - stderr, - JSON_INDENT (2)); - break; - } - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Ask the bank to execute a wire transfer to the exchange. - */ -static void -execute_admin_transfer (void) -{ - struct TALER_ReservePublicKeyP reserve_pub; - - if (NULL != subject) - { - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (subject, - strlen (subject), - &reserve_pub, - sizeof (reserve_pub))) - { - fprintf (stderr, - "Error: wire transfer subject must be a reserve public key\n"); - return; - } - } - else - { - /* pick one that is kind-of well-formed at random */ - GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, - &reserve_pub, - sizeof (reserve_pub)); - } - op = TALER_BANK_admin_add_incoming (ctx, - &auth, - &reserve_pub, - &amount, - credit_account, - &res_cb, - NULL); - if (NULL == op) - { - fprintf (stderr, - "Could not execute the wire transfer to the exchange\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } -} - - -/** - * Main function that will be run. - * - * @param cls closure - * @param args remaining command-line arguments - * @param cfgfile name of the configuration file used (for saving, can be NULL!) - * @param cfg configuration - */ -static void -run (void *cls, - char *const *args, - const char *cfgfile, - const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - (void) cls; - (void) args; - (void) cfgfile; - (void) cfg; - - GNUNET_SCHEDULER_add_shutdown (&do_shutdown, - NULL); - ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, - &rc); - GNUNET_assert (NULL != ctx); - rc = GNUNET_CURL_gnunet_rc_create (ctx); - if (NULL != account_section) - { - if ( (NULL != auth.wire_gateway_url) || - (NULL != auth.details.basic.username) || - (NULL != auth.details.basic.password) ) - { - fprintf (stderr, - "Conflicting authentication options provided. Please only use one method.\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } - if (GNUNET_OK != - TALER_BANK_auth_parse_cfg (cfg, - account_section, - &auth)) - { - fprintf (stderr, - "Authentication information not found in configuration section `%s'\n", - account_section); - GNUNET_SCHEDULER_shutdown (); - return; - } - } - else - { - if ( (NULL != auth.wire_gateway_url) && - (NULL != auth.details.basic.username) && - (NULL != auth.details.basic.password) ) - { - auth.method = TALER_BANK_AUTH_BASIC; - } - else if (NULL == auth.wire_gateway_url) - { - fprintf (stderr, - "No account specified (use -b or -s options).\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } - } - if ( (GNUNET_YES == incoming_history) && - (GNUNET_YES == outgoing_history) ) - { - fprintf (stderr, - "Please specify only -i or -o, but not both.\n"); - GNUNET_SCHEDULER_shutdown (); - return; - } - if (GNUNET_YES == incoming_history) - { - execute_credit_history (); - return; - } - if (GNUNET_YES == outgoing_history) - { - execute_debit_history (); - return; - } - if (NULL != credit_account) - { - execute_wire_transfer (); - return; - } - if (NULL != debit_account) - { - execute_admin_transfer (); - return; - } - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No operation specified.\n"); - global_ret = 0; - GNUNET_SCHEDULER_shutdown (); -} - - -/** - * The main function of the taler-bank-transfer tool - * - * @param argc number of arguments from the command line - * @param argv command line arguments - * @return 0 ok, 1 on error - */ -int -main (int argc, - char *const *argv) -{ - const struct GNUNET_GETOPT_CommandLineOption options[] = { - TALER_getopt_get_amount ('a', - "amount", - "VALUE", - "value to transfer", - &amount), - GNUNET_GETOPT_option_string ('b', - "bank", - "URL", - "Wire gateway URL to use to talk to the bank", - &auth.wire_gateway_url), - GNUNET_GETOPT_option_string ('C', - "credit", - "ACCOUNT", - "payto URI of the bank account to credit (when making outgoing transfers)", - &credit_account), - GNUNET_GETOPT_option_string ('D', - "debit", - "PAYTO-URL", - "payto URI of the bank account to debit (when making incoming transfers)", - &debit_account), - GNUNET_GETOPT_option_flag ('i', - "credit-history", - "Ask to get a list of 10 incoming transactions.", - &incoming_history), - GNUNET_GETOPT_option_flag ('o', - "debit-history", - "Ask to get a list of 10 outgoing transactions.", - &outgoing_history), - GNUNET_GETOPT_option_string ('p', - "pass", - "PASSPHRASE", - "passphrase to use for authentication", - &auth.details.basic.password), - GNUNET_GETOPT_option_string ('s', - "section", - "ACCOUNT-SECTION", - "Which config section has the credentials to access the bank. Conflicts with -b -u and -p options.\n", - &account_section), - GNUNET_GETOPT_option_string ('S', - "subject", - "SUBJECT", - "specifies the wire transfer subject", - &subject), - GNUNET_GETOPT_option_string ('u', - "user", - "USERNAME", - "username to use for authentication", - &auth.details.basic.username), - GNUNET_GETOPT_option_ulong ('w', - "since-when", - "ROW", - "When asking the bank for transactions history, this option commands that all the results should have IDs settled after SW. If not given, then the 10 youngest transactions are returned.", - &start_row), - GNUNET_GETOPT_OPTION_END - }; - enum GNUNET_GenericReturnValue ret; - - /* force linker to link against libtalerutil; if we do - not do this, the linker may "optimize" libtalerutil - away and skip #TALER_OS_init(), which we do need */ - (void) TALER_project_data_default (); - if (GNUNET_OK != - GNUNET_STRINGS_get_utf8_args (argc, argv, - &argc, &argv)) - return 4; - global_ret = 1; - ret = GNUNET_PROGRAM_run ( - argc, argv, - "taler-wire-gateway-client", - gettext_noop ("Client tool of the Taler Wire Gateway"), - options, - &run, NULL); - GNUNET_free_nz ((void *) argv); - if (GNUNET_SYSERR == ret) - return 3; - if (GNUNET_NO == ret) - return 0; - return global_ret; -} - - -/* end taler-wire-gateway-client.c */ -- cgit v1.2.3