diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | configure.ac | 109 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/main.c | 359 | ||||
-rw-r--r-- | src/nfc.c | 2 |
5 files changed, 350 insertions, 125 deletions
diff --git a/Makefile.am b/Makefile.am index 38153e1..40e718c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = src doc . +SUBDIRS = src . EXTRA_DIST = \ AUTHORS \ diff --git a/configure.ac b/configure.ac index 0551c7c..36a65c3 100644 --- a/configure.ac +++ b/configure.ac @@ -68,10 +68,117 @@ AC_CHECK_FUNCS([strstr]) +# Save before checking for libraries +LIBS_SAVE=$LIBS + + +# Check for Taler's libtalermerchant +libtalermerchant=0 +AC_MSG_CHECKING([for libtalermerchant]) +AC_ARG_WITH(merchant, + [AS_HELP_STRING([--with-merchant=PFX], [base of Taler MERCHANT installation])], + [AC_MSG_RESULT([given as $with_merchant])], + [AC_MSG_RESULT(not given) + with_merchant=yes]) +AS_CASE([$with_merchant], + [yes], [], + [no], [AC_MSG_ERROR([--with-merchant is required])], + [LDFLAGS="-L$with_merchant/lib $LDFLAGS" + CPPFLAGS="-I$with_merchant/include $CPPFLAGS $POSTGRESQL_CPPFLAGS"]) + +AC_CHECK_HEADERS([taler/taler_merchant_service.h], + [AC_CHECK_LIB([talermerchant], [TALER_MERCHANT_poll_payment], libtalermerchant=1)], + [], [#ifdef HAVE_TALER_PLATFORM_H + #include <taler/platform.h> + #endif]) + + + +# Check for GNUnet's libgnunetutil. +libgnunetutil=0 +AC_MSG_CHECKING([for libgnunetutil]) +AC_ARG_WITH(gnunet, + [AS_HELP_STRING([--with-gnunet=PFX], [base of GNUnet installation])], + [AC_MSG_RESULT([given as $with_gnunet])], + [AC_MSG_RESULT(not given) + with_gnunet=yes]) +AS_CASE([$with_gnunet], + [yes], [], + [no], [AC_MSG_ERROR([--with-gnunet is required])], + [LDFLAGS="-L$with_gnunet/lib $LDFLAGS" + CPPFLAGS="-I$with_gnunet/include $CPPFLAGS"]) +AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_util_lib.h], + [AC_CHECK_LIB([gnunetutil], [GNUNET_SCHEDULER_run], libgnunetutil=1)], + [], [#ifdef HAVE_GNUNET_PLATFORM_H + #include <gnunet/platform.h> + #endif]) +AS_IF([test $libgnunetutil != 1], + [AC_MSG_ERROR([[ +*** +*** You need libgnunetutil to build this program. +*** This library is part of GNUnet, available at +*** https://gnunet.org +*** ]])]) + + + +# Check for GNUnet's libgnunetjson. +libgnunetjson=0 +AC_MSG_CHECKING([for libgnunetjson]) +AC_ARG_WITH(gnunet, + [AS_HELP_STRING([--with-gnunet=PFX], [base of GNUnet installation])], + [AC_MSG_RESULT([given as $with_gnunet])], + [AC_MSG_RESULT(not given) + with_gnunet=yes]) +AS_CASE([$with_gnunet], + [yes], [], + [no], [AC_MSG_ERROR([--with-gnunet is required])], + [LDFLAGS="-L$with_gnunet/lib $LDFLAGS" + CPPFLAGS="-I$with_gnunet/include $CPPFLAGS"]) +AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_json_lib.h], + [AC_CHECK_LIB([gnunetjson], [GNUNET_JSON_parse], libgnunetjson=1)], + [], [#ifdef HAVE_GNUNET_PLATFORM_H + #include <gnunet/platform.h> + #endif]) +AS_IF([test $libgnunetjson != 1], + [AC_MSG_ERROR([[ +*** +*** You need libgnunetjson to build this program. +*** Make sure you have libjansson installed while +*** building GNUnet. +*** ]])]) + +# Check for GNUnet's libgnunetcurl. +libgnunetcurl=0 +AC_MSG_CHECKING([for libgnunetcurl]) +AC_ARG_WITH(gnunet, + [AS_HELP_STRING([--with-gnunet=PFX], [base of GNUnet installation])], + [AC_MSG_RESULT([given as $with_gnunet])], + [AC_MSG_RESULT(not given) + with_gnunet=yes]) +AS_CASE([$with_gnunet], + [yes], [], + [no], [AC_MSG_ERROR([--with-gnunet is required])], + [LDFLAGS="-L$with_gnunet/lib $LDFLAGS" + CPPFLAGS="-I$with_gnunet/include $CPPFLAGS"]) +AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_curl_lib.h], + [AC_CHECK_LIB([gnunetcurl], [GNUNET_CURL_get_select_info], libgnunetcurl=1)], + [], [#ifdef HAVE_GNUNET_PLATFORM_H + #include <gnunet/platform.h> + #endif]) +AS_IF([test $libgnunetcurl != 1], + [AC_MSG_ERROR([[ +*** +*** You need libgnunetcurl to build this program. +*** Make sure you have libcurl or libgnurl installed while +*** building GNUnet. +*** ]])]) + + # Save before checking libgnurl/libcurl CFLAGS_SAVE=$CFLAGS LDFLAGS_SAVE=$LDFLAGS -LIBS_SAVE=$LIBS + # check for libgnurl # libgnurl diff --git a/src/Makefile.am b/src/Makefile.am index 3105b63..9e157b4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,6 +13,9 @@ taler_nfc_SOURCES = \ communication.c communication.h \ main.c taler_nfc_LDADD = \ + -ltalermerchant \ + -ltalerutil \ + -lgnunetutil \ -ljansson \ -lnfc \ -lpthread \ @@ -16,14 +16,12 @@ details. along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ - /** * @file main.c * @brief main functionality of the application * @author BOSS Marco * @author ... */ - #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -33,27 +31,51 @@ along with #include <curl/curl.h> #include <gnunet/platform.h> #include <gnunet/gnunet_util_lib.h> +#include <taler/taler_merchant_service.h> #include "nfc.h" #include "communication.h" #include "configuration.h" #include "product.h" -ProductOrder product; +static int global_ret; + +static struct GNUNET_SCHEDULER_Task *super_task; + +static struct GNUNET_CURL_Context *ctx; + +static struct GNUNET_CURL_RescheduleContext *; + +struct PaymentActivity +{ + ProductOrder product; + + struct TALER_MERCHANT_PollPaymentOperation *ppo; + + struct TALER_MERCHANT_ProposalOperation *po; + + nfc_device *pnd; +}; + nfc_context *context; -void *_SNACK_start_nfc_transmission (void *ignored) + +static struct PaymentActivity *payment_activity; + + +static void * +start_nfc_transmission (void *ignored) { /* supress warning about unused variable */ (void) ignored; - if ( pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL) != 0 ) + if (pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL) != 0) { printf ("Error setting thread cancelling type\n"); } /* start endless transmission loop (until threads gets cancelled) */ - while ( 1 ) + while (1) { if ( pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, NULL) != 0 ) { @@ -69,67 +91,58 @@ void *_SNACK_start_nfc_transmission (void *ignored) return EXIT_SUCCESS; } -int main (int argc, char*const*argv) -{ - CURL *curl; - char*cfgFile; - struct GNUNET_CONFIGURATION_Handle *cfgHandle; - - /* prepare config file name */ - cfgFile = GNUNET_malloc (strlen (SNACK_DEFAULT_CONFIG_FILE) + 1); - strcpy (cfgFile, SNACK_DEFAULT_CONFIG_FILE); - /* the available command line options */ - struct GNUNET_GETOPT_CommandLineOption options[] = { - GNUNET_GETOPT_option_help ( - "This is an application for snack machines with nfc. Running with GNU taler.\n" - "Current taler wallet AID: F00054414c4552\n"), - GNUNET_GETOPT_option_cfgfile (&cfgFile), - GNUNET_GETOPT_OPTION_END - }; - /* parse the command line */ - if ( GNUNET_GETOPT_run ("taler-mdb\n", options, argc, argv) <= 0 ) +static void +shutdown_task (void *cls) +{ + (void) cls; + /* clear all initialized data */ + if (NULL != context) + nfc_exit (context); + if (NULL != product) + SNACK_product_exit (&product); + if (NULL != curl) + SNACK_taler_exit (&curl); + if (NULL != super_task) + GNUNET_SCHEDULER_cancel (super_task); + if (NULL != ctx) { - GNUNET_free (cfgFile); - return EXIT_SUCCESS; + GNUNET_CURL_fini (ctx); + ctx = NULL; } - - /* setup logger */ - GNUNET_assert - (GNUNET_OK == GNUNET_log_setup ("taler-mdb", "DEBUG", NULL)); // "taler-mdb.log")); - - /* load config file */ - cfgHandle = GNUNET_CONFIGURATION_create (); - if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfgHandle, cfgFile)) + if (NULL != rc) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "main: unable to load config file %s\n", cfgFile); - GNUNET_CONFIGURATION_destroy (cfgHandle); - GNUNET_free (cfgFile); - return EXIT_FAILURE; + GNUNET_CURL_gnunet_rc_destroy (rc); + rc = NULL; } +} + +static void +run (void *cls, + char *const *args, + const char *cfgfile, + const struct GNUNET_CONFIGURATION_Handle *cfg) +{ /* inizialize product */ - if ( SNACK_product_init (&product, cfgHandle) ) + if ( SNACK_product_init (&product, cfg) ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "main: unable to init product structure\n"); - GNUNET_CONFIGURATION_destroy (cfgHandle); - GNUNET_free (cfgFile); - return EXIT_FAILURE; + global_ret = EXIT_FAILURE; + return; } - - /* free cfg because its not needed anymore ( everything is now stored in product ) */ - GNUNET_CONFIGURATION_destroy (cfgHandle); - GNUNET_free (cfgFile); - + GNUNET_SCHEDULER_add_shutdown (&shutdown_task, + NULL); /* initialize nfc */ nfc_init (&context); if ( ! context ) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "main: unable to init nfc\n"); - return EXIT_FAILURE; + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return; } /* inizialize taler */ @@ -137,103 +150,205 @@ int main (int argc, char*const*argv) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "main: nable to init taler communication\n"); - return EXIT_FAILURE; + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return; } + ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, + &is.rc); + rc = GNUNET_CURL_gnunet_rc_create (ctx); + start_read_keyboard (); +} + + +static void +start_read_keyboard () +{ + struct GNUNET_DISK_FileHandle fh = { FILENO_STDIN }; + + printf ("Waiting for MBD input\n"); + printf ("Enter to simulate Snickers, x to quit\n"); + super_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_ABS, + fh, + &read_product_info, + NULL); +} - /* superloop */ - while ( true ) - { - printf ("Waiting for MBD input\n"); - printf ("Enter to simulate Snickers, x to quit\n"); - if ( getchar () == 'x' ) - break; - /* DEMO snickers */ +static void +read_product_info (void *cls) +{ + int input; + + super_task = NULL; + input = getchar (); + if ( (EOF == input) || + ('x' == (char) input) ) + { + GNUNET_SCHEDULER_shutdown (); + return; + } + switch ((char) input) + { + case 'c': + if (NULL != payment_activity) + { + cancel_payment (payment_activity); + payment_activity = NULL; + } + break; + case 's': + GNUNET_assert (NULL == payment_activity); product.amount = "0.1"; product.product = "Snickers"; + payment_activity = launch_payment (&product); + break; + } + start_read_keyboard (); +} - /* create the order request */ - SNACK_taler_create_order_req (&product); +static void +cancel_payment (struct PaymentActivity *pa) +{ + if (NULL != pa->po) + TALER_MERCHANT_proposal_cancel (pa->po); + GNUNET_free (pa); +} - /* create the order */ - while ( SNACK_taler_create_order (curl, &product) ) - ; - /* store the order id into the struct */ - SNACK_product_set_order_id (&product); +static void +proposal_cb (void *cls, + unsigned int http_status, + enum TALER_ErrorCode ec, + const json_t *obj, + const char *order_id) +{ + struct PaymentActivity *pa = cls; - /* store the url to check wheter the payment happened or not */ - SNACK_product_set_check_url (&product); + pa->po = NULL; + // use(order_id); + // start_nfc_transmission(pa); + // pa->pnd = open(); + // +} - /* check the payment status for the first time */ - while ( SNACK_taler_check_payment_status (curl, &product) ) - ; - /* store the url to pay, to do this task the payment status has to be called before, because the url will be in the response */ - SNACK_product_set_pay_url (&product); +static struct PaymentActivity * +launch_payment (const Product *product) +{ + struct PaymentActivity *pa; + + pa = GNUNET_new (struct PaymentActivity); + pa->product = *product; + // SEE: SNACK_taler_create_order_req (&product); + order = json (); + pa->po = TALER_MERCHANT_order_put (ctx, + backend_url, + order, + &proposal_cb, + pa); +} - /* start a thread to send payment request to taler wallet */ - pthread_t nfcThread; - if ( pthread_create (&nfcThread, NULL, _SNACK_start_nfc_transmission, - NULL) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "main: thread creation failed\n"); - return EXIT_FAILURE; - } +static void foo () +{ + /* create the order request */ + SNACK_taler_create_order_req (&product); - /* check the payment status, if paid exit while loop and end thread transmitting nfc messages */ - while ( ! product.paid ) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "main: order payment processing\n"); - sleep (5); + /* create the order */ + while ( SNACK_taler_create_order (curl, &product) ) + ; - while ( SNACK_taler_check_payment_status (curl, &product) ) - ; + /* store the order id into the struct */ + SNACK_product_set_order_id (&product); - /* set the boolean paid member of ProductOrder struct */ - SNACK_product_set_paid_status (&product); + /* store the url to check wheter the payment happened or not */ + SNACK_product_set_check_url (&product); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "main: payment status paid: %s\n", - (product.paid ? "true" : "false") ); - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, "main: order no.: %s paid!\n", - product.orderID); + /* check the payment status for the first time */ + while ( SNACK_taler_check_payment_status (curl, &product) ) + ; + /* store the url to pay, to do this task the payment status has to be called before, because the url will be in the response */ + SNACK_product_set_pay_url (&product); - /* ----------------- - Here comes the code for releasing the product - ----------------- */ + /* start a thread to send payment request to taler wallet */ + pthread_t nfcThread; + if ( pthread_create (&nfcThread, + NULL, + &start_nfc_transmission, + NULL) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "main: thread creation failed\n"); + return EXIT_FAILURE; + } + /* check the payment status, if paid exit while loop and end thread transmitting nfc messages */ + while ( ! product.paid ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "main: order payment processing\n"); + sleep (5); - /* send cancel request to nfc thread */ - while ( pthread_cancel (nfcThread) != 0 ) - { - printf ("Error sending cancel request to thread for nfc transmission"); - } + while ( SNACK_taler_check_payment_status (curl, &product) ) + ; - void*res; - if ( pthread_join (nfcThread, &res) == 0 ) - { - printf ("Thread for nfc transmission finished\n"); - fflush (stdout); - } - else if ( res == PTHREAD_CANCELED ) - { - printf ("Thread for nfc transmission finished\n"); - fflush (stdout); - } + /* set the boolean paid member of ProductOrder struct */ + SNACK_product_set_paid_status (&product); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "main: payment status paid: %s\n", + (product.paid ? "true" : "false") ); + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "main: order no.: %s paid!\n", + product.orderID); + + + /* ----------------- + Here comes the code for releasing the product + ----------------- */ - /* reset the product */ - SNACK_product_reset (&product); + /* send cancel request to nfc thread */ + while ( pthread_cancel (nfcThread) != 0 ) + { + printf ("Error sending cancel request to thread for nfc transmission"); } - /* end of superloop */ - /* clear all initialized data */ - nfc_exit (context); - SNACK_product_exit (&product); - SNACK_taler_exit (&curl); + void*res; + if ( pthread_join (nfcThread, &res) == 0 ) + { + printf ("Thread for nfc transmission finished\n"); + fflush (stdout); + } + else if ( res == PTHREAD_CANCELED ) + { + printf ("Thread for nfc transmission finished\n"); + fflush (stdout); + } - return EXIT_SUCCESS; + /* reset the product */ + SNACK_product_reset (&product); + +} + + + +int +main (int argc, + char*const*argv) +{ + /* the available command line options */ + struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_OPTION_END + }; + + if (GNUNET_OK != + GNUNET_PROGRAM_run (argc, + argv, + "taler-mdb", + "This is an application for snack machines to pay with GNU Taler via nfc.\n" + options, + &run, + NULL)) + return 1; + return global_ret; } @@ -103,7 +103,7 @@ int SNACK_nfc_connect_target (nfc_device *pnd, nfc_target *nt) while ( ctr > 0 ) { - /* set uid lenght to zero ( in case of second selecting the length still has the old value ) */ + /* set uid length to zero ( in case of second selecting the length still has the old value ) */ nt->nti.nai.szUidLen = 0; if ( nfc_initiator_select_passive_target (pnd, nmMifare[0], NULL, 0, nt) <= 0 ) |