merge taler-wire and taler-bank-transfer tools, they are very related and otherwise duplicate lots of logic; also enable both credit and debit histories to be shown
This commit is contained in:
parent
42bc3bc437
commit
20a7d8fc08
@ -24,6 +24,18 @@
|
|||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
#include "taler_bank_service.h"
|
#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.
|
* Amount to transfer.
|
||||||
*/
|
*/
|
||||||
@ -34,28 +46,56 @@ static struct TALER_Amount amount;
|
|||||||
*/
|
*/
|
||||||
static char *credit_account;
|
static char *credit_account;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debit account payto://-URI.
|
||||||
|
*/
|
||||||
|
static char *debit_account;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wire transfer subject.
|
* Wire transfer subject.
|
||||||
*/
|
*/
|
||||||
static char *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.
|
* Authentication data.
|
||||||
*/
|
*/
|
||||||
static struct TALER_BANK_AuthenticationData auth = {
|
static struct TALER_BANK_AuthenticationData auth;
|
||||||
.method = TALER_BANK_AUTH_BASIC
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return value from main().
|
* Return value from main().
|
||||||
*/
|
*/
|
||||||
static int global_ret;
|
static int global_ret = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main execution context for the main loop.
|
* Main execution context for the main loop.
|
||||||
*/
|
*/
|
||||||
static struct GNUNET_CURL_Context *ctx;
|
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.
|
* Handle to access the exchange.
|
||||||
*/
|
*/
|
||||||
@ -82,6 +122,21 @@ do_shutdown (void *cls)
|
|||||||
TALER_BANK_admin_add_incoming_cancel (op);
|
TALER_BANK_admin_add_incoming_cancel (op);
|
||||||
op = NULL;
|
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)
|
if (NULL != ctx)
|
||||||
{
|
{
|
||||||
GNUNET_CURL_fini (ctx);
|
GNUNET_CURL_fini (ctx);
|
||||||
@ -92,6 +147,308 @@ do_shutdown (void *cls)
|
|||||||
GNUNET_CURL_gnunet_rc_destroy (rc);
|
GNUNET_CURL_gnunet_rc_destroy (rc);
|
||||||
rc = NULL;
|
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 ()
|
||||||
|
{
|
||||||
|
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 ()
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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 ()
|
||||||
|
{
|
||||||
|
struct TALER_WireTransferIdentifierRawP wtid;
|
||||||
|
void *buf;
|
||||||
|
size_t buf_size;
|
||||||
|
|
||||||
|
if (NULL != debit_account)
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"Invalid option -C specified, conflicts with -D\n");
|
||||||
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -140,6 +497,51 @@ res_cb (void *cls,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask the bank to execute a wire transfer to the exchange.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
execute_admin_transfer ()
|
||||||
|
{
|
||||||
|
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.
|
* Main function that will be run.
|
||||||
*
|
*
|
||||||
@ -154,39 +556,89 @@ run (void *cls,
|
|||||||
const char *cfgfile,
|
const char *cfgfile,
|
||||||
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||||
{
|
{
|
||||||
struct TALER_ReservePublicKeyP reserve_pub;
|
|
||||||
|
|
||||||
(void) cls;
|
(void) cls;
|
||||||
(void) args;
|
(void) args;
|
||||||
(void) cfgfile;
|
(void) cfgfile;
|
||||||
(void) cfg;
|
(void) cfg;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
|
||||||
|
NULL);
|
||||||
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
|
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
|
||||||
&rc);
|
&rc);
|
||||||
GNUNET_assert (NULL != ctx);
|
GNUNET_assert (NULL != ctx);
|
||||||
rc = GNUNET_CURL_gnunet_rc_create (ctx);
|
rc = GNUNET_CURL_gnunet_rc_create (ctx);
|
||||||
|
if (NULL != account_section)
|
||||||
op = TALER_BANK_admin_add_incoming (ctx,
|
{
|
||||||
&auth,
|
if ( (NULL != auth.wire_gateway_url) ||
|
||||||
&reserve_pub,
|
(NULL != auth.details.basic.username) ||
|
||||||
&amount,
|
(NULL != auth.details.basic.password) )
|
||||||
credit_account,
|
{
|
||||||
&res_cb,
|
fprintf (stderr,
|
||||||
NULL);
|
"Conflicting authentication options provided. Please only use one method.\n");
|
||||||
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
|
GNUNET_SCHEDULER_shutdown ();
|
||||||
NULL);
|
return;
|
||||||
if (NULL == op)
|
}
|
||||||
|
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 == incoming_history) )
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"Please specify only -i or -o, but not both.\n");
|
||||||
GNUNET_SCHEDULER_shutdown ();
|
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 ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -198,46 +650,64 @@ run (void *cls,
|
|||||||
* @return 0 ok, 1 on error
|
* @return 0 ok, 1 on error
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
main (int argc, char *const *argv)
|
main (int argc,
|
||||||
|
char *const *argv)
|
||||||
{
|
{
|
||||||
const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||||
GNUNET_GETOPT_option_mandatory
|
TALER_getopt_get_amount ('a',
|
||||||
(TALER_getopt_get_amount ('a',
|
"amount",
|
||||||
"amount",
|
"VALUE",
|
||||||
"VALUE",
|
"value to transfer",
|
||||||
"value to transfer",
|
&amount),
|
||||||
&amount)),
|
GNUNET_GETOPT_option_string ('b',
|
||||||
GNUNET_GETOPT_option_mandatory
|
"bank",
|
||||||
(GNUNET_GETOPT_option_string ('b',
|
"URL",
|
||||||
"bank",
|
"Wire gateway URL to use to talk to the bank",
|
||||||
"URL",
|
&auth.wire_gateway_url),
|
||||||
"Wire gateway URL to use to talk to the bank",
|
|
||||||
&auth.wire_gateway_url)),
|
|
||||||
GNUNET_GETOPT_option_help ("Deposit funds into a Taler reserve"),
|
GNUNET_GETOPT_option_help ("Deposit funds into a Taler reserve"),
|
||||||
GNUNET_GETOPT_option_mandatory
|
GNUNET_GETOPT_option_string ('C',
|
||||||
(GNUNET_GETOPT_option_string ('C',
|
"credit",
|
||||||
"credit",
|
"ACCOUNT",
|
||||||
"ACCOUNT",
|
"payto URI of the bank account to credit (when making outgoing transfers)",
|
||||||
"payto URI of the bank account to credit",
|
&credit_account),
|
||||||
&credit_account)),
|
GNUNET_GETOPT_option_string ('D',
|
||||||
GNUNET_GETOPT_option_mandatory
|
"debit",
|
||||||
(GNUNET_GETOPT_option_string ('s',
|
"PAYTO-URL",
|
||||||
"subject",
|
"payto URI of the bank account to debit (when making incoming transfers)",
|
||||||
"STRING",
|
&debit_account),
|
||||||
"specifies the wire transfer subject (must be a reserve public key)",
|
GNUNET_GETOPT_option_flag ('i',
|
||||||
&subject)),
|
"credit-history",
|
||||||
GNUNET_GETOPT_option_mandatory
|
"Ask to get a list of 10 incoming transactions.",
|
||||||
(GNUNET_GETOPT_option_string ('u',
|
&incoming_history),
|
||||||
"user",
|
GNUNET_GETOPT_option_flag ('o',
|
||||||
"USERNAME",
|
"debit-history",
|
||||||
"username to use for authentication",
|
"Ask to get a list of 10 outgoing transactions.",
|
||||||
&auth.details.basic.username)),
|
&outgoing_history),
|
||||||
GNUNET_GETOPT_option_mandatory
|
GNUNET_GETOPT_option_string ('p',
|
||||||
(GNUNET_GETOPT_option_string ('p',
|
"pass",
|
||||||
"pass",
|
"PASSPHRASE",
|
||||||
"PASSPHRASE",
|
"passphrase to use for authentication",
|
||||||
"passphrase to use for authentication",
|
&auth.details.basic.password),
|
||||||
&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
|
GNUNET_GETOPT_OPTION_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,16 +15,7 @@ bin_PROGRAMS = \
|
|||||||
taler-exchange-keyup \
|
taler-exchange-keyup \
|
||||||
taler-exchange-keycheck \
|
taler-exchange-keycheck \
|
||||||
taler-exchange-wire \
|
taler-exchange-wire \
|
||||||
taler-exchange-dbinit \
|
taler-exchange-dbinit
|
||||||
taler-wire
|
|
||||||
|
|
||||||
taler_wire_SOURCES = \
|
|
||||||
taler-wire.c
|
|
||||||
taler_wire_LDADD = \
|
|
||||||
$(top_builddir)/src/util/libtalerutil.la \
|
|
||||||
$(top_builddir)/src/bank-lib/libtalerbank.la \
|
|
||||||
-lgnunetcurl \
|
|
||||||
-lgnunetutil
|
|
||||||
|
|
||||||
taler_exchange_keyup_SOURCES = \
|
taler_exchange_keyup_SOURCES = \
|
||||||
taler-exchange-keyup.c
|
taler-exchange-keyup.c
|
||||||
|
@ -66,7 +66,13 @@ run (void *cls,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (reset_db)
|
if (reset_db)
|
||||||
(void) plugin->drop_tables (plugin->cls);
|
{
|
||||||
|
if (GNUNET_OK != plugin->drop_tables (plugin->cls))
|
||||||
|
{
|
||||||
|
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||||
|
"Could not drop tables. Either database was not yet initialized, or permission denied. Consult the logs. Will still try to create new tables.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (GNUNET_OK !=
|
if (GNUNET_OK !=
|
||||||
plugin->create_tables (plugin->cls))
|
plugin->create_tables (plugin->cls))
|
||||||
{
|
{
|
||||||
@ -79,8 +85,10 @@ run (void *cls,
|
|||||||
if (gc_db)
|
if (gc_db)
|
||||||
{
|
{
|
||||||
if (GNUNET_SYSERR == plugin->gc (plugin->cls))
|
if (GNUNET_SYSERR == plugin->gc (plugin->cls))
|
||||||
|
{
|
||||||
fprintf (stderr,
|
fprintf (stderr,
|
||||||
"Garbage collection failed!\n");
|
"Garbage collection failed!\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TALER_EXCHANGEDB_plugin_unload (plugin);
|
TALER_EXCHANGEDB_plugin_unload (plugin);
|
||||||
}
|
}
|
||||||
|
@ -1,402 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of TALER
|
|
||||||
Copyright (C) 2014--2019 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 <http://www.gnu.org/licenses/>
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @file taler-wire.c
|
|
||||||
* @brief Utility for performing wire transfers.
|
|
||||||
* @author Marcello Stanisci
|
|
||||||
* @author Christian Grothoff
|
|
||||||
*/
|
|
||||||
#include <platform.h>
|
|
||||||
#include <gnunet/gnunet_util_lib.h>
|
|
||||||
#include "taler_util.h"
|
|
||||||
#include "taler_bank_service.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If set to #GNUNET_YES, then we'll ask the bank for a list
|
|
||||||
* of transactions from the account mentioned in the config
|
|
||||||
* section.
|
|
||||||
*/
|
|
||||||
static int history;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If set to #GNUNET_YES, then we'll ask the bank to execute a
|
|
||||||
* wire transfer.
|
|
||||||
*/
|
|
||||||
static int transfer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Global return code.
|
|
||||||
*/
|
|
||||||
static unsigned int global_ret = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a wire transfer is being performed, this value
|
|
||||||
* specifies the amount to transfer.
|
|
||||||
*/
|
|
||||||
static struct TALER_Amount amount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Starting row.
|
|
||||||
*/
|
|
||||||
static unsigned long long start_row;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Which config section has the credentials to access the bank.
|
|
||||||
*/
|
|
||||||
static char *account_section;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* URL identifying the account that is going to receive the
|
|
||||||
* wire transfer.
|
|
||||||
*/
|
|
||||||
static char *destination_account_url;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle for executing the wire transfer.
|
|
||||||
*/
|
|
||||||
static struct TALER_BANK_TransferHandle *eh;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle to ongoing history operation.
|
|
||||||
*/
|
|
||||||
static struct TALER_BANK_CreditHistoryHandle *hh;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For authentication.
|
|
||||||
*/
|
|
||||||
static struct TALER_BANK_AuthenticationData auth;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handle to the context for interacting with the bank.
|
|
||||||
*/
|
|
||||||
static struct GNUNET_CURL_Context *ctx;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Scheduler context for running the @e ctx.
|
|
||||||
*/
|
|
||||||
static struct GNUNET_CURL_RescheduleContext *rc;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
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;
|
|
||||||
(void) ec;
|
|
||||||
(void) http_status;
|
|
||||||
(void) json;
|
|
||||||
if (NULL == details)
|
|
||||||
{
|
|
||||||
fprintf (stdout,
|
|
||||||
"End of transactions list.\n");
|
|
||||||
global_ret = 0;
|
|
||||||
GNUNET_SCHEDULER_shutdown ();
|
|
||||||
return GNUNET_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
if (MHD_HTTP_OK != response_code)
|
|
||||||
{
|
|
||||||
fprintf (stderr,
|
|
||||||
"The wire transfer didn't execute correctly (%d).\n",
|
|
||||||
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 ()
|
|
||||||
{
|
|
||||||
struct TALER_WireTransferIdentifierRawP wtid;
|
|
||||||
void *buf;
|
|
||||||
size_t buf_size;
|
|
||||||
|
|
||||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
|
|
||||||
&wtid,
|
|
||||||
sizeof (wtid));
|
|
||||||
TALER_BANK_prepare_transfer (destination_account_url,
|
|
||||||
&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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ask the bank the list of transactions for the bank account
|
|
||||||
* mentioned in the config section given by the user.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
execute_history ()
|
|
||||||
{
|
|
||||||
hh = TALER_BANK_credit_history (ctx,
|
|
||||||
&auth,
|
|
||||||
start_row,
|
|
||||||
-10,
|
|
||||||
&history_cb,
|
|
||||||
NULL);
|
|
||||||
if (NULL == hh)
|
|
||||||
{
|
|
||||||
fprintf (stderr,
|
|
||||||
"Could not request the transaction history.\n");
|
|
||||||
GNUNET_SCHEDULER_shutdown ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets executed upon shutdown. Main duty is wire-plugin unloading.
|
|
||||||
*
|
|
||||||
* @param cls closure.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
do_shutdown (void *cls)
|
|
||||||
{
|
|
||||||
(void) cls;
|
|
||||||
if (NULL != ctx)
|
|
||||||
{
|
|
||||||
GNUNET_CURL_fini (ctx);
|
|
||||||
ctx = NULL;
|
|
||||||
}
|
|
||||||
if (NULL != rc)
|
|
||||||
{
|
|
||||||
GNUNET_CURL_gnunet_rc_destroy (rc);
|
|
||||||
rc = NULL;
|
|
||||||
}
|
|
||||||
if (NULL != hh)
|
|
||||||
{
|
|
||||||
TALER_BANK_credit_history_cancel (hh);
|
|
||||||
hh = NULL;
|
|
||||||
}
|
|
||||||
if (NULL != eh)
|
|
||||||
{
|
|
||||||
TALER_BANK_transfer_cancel (eh);
|
|
||||||
eh = NULL;
|
|
||||||
}
|
|
||||||
TALER_BANK_auth_free (&auth);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
if (NULL == account_section)
|
|
||||||
{
|
|
||||||
fprintf (stderr,
|
|
||||||
"The option: -s ACCOUNT-SECTION, is mandatory.\n");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (GNUNET_YES == history)
|
|
||||||
execute_history ();
|
|
||||||
else if (GNUNET_YES == transfer)
|
|
||||||
execute_wire_transfer ();
|
|
||||||
else
|
|
||||||
fprintf (stderr,
|
|
||||||
"Please give either --history/-H or --transfer/t\n");
|
|
||||||
|
|
||||||
ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
|
|
||||||
&rc);
|
|
||||||
rc = GNUNET_CURL_gnunet_rc_create (ctx);
|
|
||||||
if (NULL == ctx)
|
|
||||||
{
|
|
||||||
GNUNET_break (0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main function of taler-wire. This tool is used to command the
|
|
||||||
* execution of wire transfers from the command line. Its main
|
|
||||||
* purpose is to test whether the bank and exchange can speak the
|
|
||||||
* same protocol of a certain wire plugin.
|
|
||||||
*
|
|
||||||
* @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)
|
|
||||||
{
|
|
||||||
struct GNUNET_GETOPT_CommandLineOption options[] = {
|
|
||||||
GNUNET_GETOPT_option_flag ('H',
|
|
||||||
"history",
|
|
||||||
"Ask to get a list of 10 transactions.",
|
|
||||||
&history),
|
|
||||||
GNUNET_GETOPT_option_flag ('t',
|
|
||||||
"transfer",
|
|
||||||
"Execute a wire transfer.",
|
|
||||||
&transfer),
|
|
||||||
GNUNET_GETOPT_option_ulong ('w',
|
|
||||||
"since-when",
|
|
||||||
"SW",
|
|
||||||
"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_mandatory
|
|
||||||
(GNUNET_GETOPT_option_string ('s',
|
|
||||||
"section",
|
|
||||||
"ACCOUNT-SECTION",
|
|
||||||
"Which config section has the credentials to access the bank. Mandatory.\n",
|
|
||||||
&account_section)),
|
|
||||||
GNUNET_GETOPT_option_mandatory
|
|
||||||
(TALER_getopt_get_amount ('a',
|
|
||||||
"amount",
|
|
||||||
"AMOUNT",
|
|
||||||
"Specify the amount to transfer.",
|
|
||||||
&amount)),
|
|
||||||
GNUNET_GETOPT_option_mandatory
|
|
||||||
(GNUNET_GETOPT_option_string ('d',
|
|
||||||
"destination",
|
|
||||||
"PAYTO-URL",
|
|
||||||
"Destination account for the wire transfer.",
|
|
||||||
&destination_account_url)),
|
|
||||||
GNUNET_GETOPT_OPTION_END
|
|
||||||
};
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
GNUNET_assert
|
|
||||||
(GNUNET_OK == GNUNET_log_setup ("taler-wire",
|
|
||||||
"WARNING",
|
|
||||||
NULL)); /* filename */
|
|
||||||
ret = GNUNET_PROGRAM_run
|
|
||||||
(argc,
|
|
||||||
argv,
|
|
||||||
"taler-wire",
|
|
||||||
"CLI bank client.",
|
|
||||||
options,
|
|
||||||
&run,
|
|
||||||
NULL);
|
|
||||||
if (GNUNET_OK != ret)
|
|
||||||
return ret;
|
|
||||||
return global_ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* end of taler-wire.c */
|
|
Loading…
Reference in New Issue
Block a user