commit 285b884edfab8d63d9fd8ffd5a2118a9c3728ae0
parent 123c4a344533f83ce5d5933404bf6e4a82715573
Author: Tellenbach Reto <tellr1@bfh.ch>
Date: Sun, 31 May 2026 21:29:37 +0200
[ref] thinker_TalerAPI: moved to src and added license consistently
Diffstat:
14 files changed, 1226 insertions(+), 2 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Project Config
+cmake_minimum_required(VERSION 3.13)
+project(taler-digitizer LANGUAGES C )
+
+# Langage requirements
+set(CMAKE_C_STANDARD 17)
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS ON)
+
+add_subdirectory(src)
diff --git a/CMakePresets.json b/CMakePresets.json
@@ -0,0 +1,14 @@
+{
+ "version": 3,
+ "configurePresets": [
+ {
+ "name": "debug",
+ "binaryDir": "${sourceDir}/build/debug",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Debug",
+ "CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
+ "CMAKE_C_FLAGS": "-Wall -Wextra -g"
+ }
+ }
+ ]
+}
+\ No newline at end of file
diff --git a/README.md b/README.md
@@ -2,4 +2,8 @@
This software is meant for use on a system which is designed, to allow users to topup their wallet with cash.
**Note:
-This software is currently under developpement. Do not attempt to use it on a system with real customers!**
-\ No newline at end of file
+This software is currently under developpement. Do not attempt to use it on a system with real customers!**
+
+# Building
+
+`export TALER_DIGITIZER_PREFIX=<installation_path>`
+\ No newline at end of file
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
@@ -0,0 +1,12 @@
+# Add files and libs
+add_executable(taler-digitizer taler-digitizer.c)
+
+find_package(PkgConfig REQUIRED)
+
+
+add_subdirectory(lib)
+
+# Manage libs
+target_link_libraries(taler-digitizer
+ PRIVATE bank
+)
+\ No newline at end of file
diff --git a/src/error_codes.h b/src/error_codes.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER cash2ecash
+ Copyright (C) 2026 GNUnet e.V.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file error_codes.h
+ * @brief error codes for Cash Digitizer
+ * @author Reto Tellenbach
+ */
+
+#ifndef ERROR_CODES_H
+#define ERROR_CODES_H
+
+/**
+ * Taler client Cash Digitizer errors.
+ */
+enum DIGITIZER_ErrorCode
+{
+ /**
+ * indicate success (no error)
+ */
+ DIGITIZER_EC_NONE = 0,
+
+ /**
+ * non specific fail
+ */
+ DIGITIZER_EC_GENERIC = 1,
+};
+
+#endif
+\ No newline at end of file
diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Add files
+add_library(bank bank_api_get_config.c bank_api_curl_defaults.c)
+
+find_package(CURL REQUIRED)
+pkg_check_modules(GNUNET REQUIRED gnunetutil)
+pkg_check_modules(LIBMICROHTTPD REQUIRED libmicrohttpd)
+
+target_link_libraries(bank
+ PUBLIC CURL::libcurl gnunetutil talerutil microhttpd
+ PRIVATE talercurl talerjson gnunetutil gnunetcurl gnunetjson jansson
+)
+\ No newline at end of file
diff --git a/src/lib/bank_api_curl_defaults.c b/src/lib/bank_api_curl_defaults.c
@@ -0,0 +1,54 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2018, 2021 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 lib/bank_api_curl_defaults.c
+ * @brief curl easy handle defaults
+ * @author Florian Dold
+ */
+#include "taler/taler_curl_lib.h"
+#include "bank_api_curl_defaults.h"
+
+
+CURL *
+TALER_BANK_curl_easy_get_ (const char *url)
+{
+ CURL *eh;
+
+ eh = curl_easy_init ();
+ if (NULL == eh)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ url));
+ TALER_curl_set_secure_redirect_policy (eh,
+ url);
+ /* Enable compression (using whatever curl likes), see
+ https://curl.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html */
+ GNUNET_break (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_ACCEPT_ENCODING,
+ ""));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_TCP_FASTOPEN,
+ 1L));
+ return eh;
+}
diff --git a/src/lib/bank_api_curl_defaults.h b/src/lib/bank_api_curl_defaults.h
@@ -0,0 +1,40 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2018 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 lib/bank_api_curl_defaults.h
+ * @brief curl easy handle defaults
+ * @author Florian Dold
+ */
+
+#ifndef _TALER_CURL_DEFAULTS_H
+#define _TALER_CURL_DEFAULTS_H
+
+
+#include <gnunet/gnunet_curl_lib.h>
+
+
+/**
+ * Get a curl handle with the right defaults
+ * for the interaction with the lib.
+ *
+ * @param url URL to query
+ */
+CURL *
+TALER_BANK_curl_easy_get_ (const char *url);
+
+#endif /* _TALER_CURL_DEFAULTS_H */
diff --git a/src/lib/bank_api_get_config.c b/src/lib/bank_api_get_config.c
@@ -0,0 +1,319 @@
+/*
+ This file is part of TALER cash2ecash
+ Copyright (C) 2026 GNUnet e.V.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file bank_api_get_config.c
+ * @brief Implementation of the GET /config request of the bank's HTTP API
+ * @author Reto Tellenbach
+ */
+
+#include <microhttpd.h>
+#include "bank_api_get_config.h"
+#include "bank_api_curl_defaults.h"
+#include "taler/taler_json_lib.h"
+
+/**
+ * Which revision of the Taler core-bank protocol is implemented
+ * by this library? Used to determine compatibility.
+ */
+#define TALER_PROTOCOL_CURRENT 12
+
+/**
+ * How many revisions back are we compatible to?
+ */
+#define TALER_PROTOCOL_AGE 0
+
+
+/**
+ * Log error related to CURL operations.
+ *
+ * @param type log level
+ * @param function which function failed to run
+ * @param code what was the curl error code
+ */
+#define CURL_STRERROR(type, function, code) \
+ GNUNET_log (type, \
+ "Curl function `%s' has failed at `%s:%d' with error: %s", \
+ function, __FILE__, __LINE__, curl_easy_strerror (code));
+
+
+/**
+ * Handle for the get config request.
+ */
+struct TALER_BANK_GetConfigHandle
+{
+ /**
+ * The context of this handle
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+ /**
+ * Function to call with the ,
+ * NULL if this has already been done.
+ */
+ TALER_BANK_ConfigCallback config_cb;
+
+ /**
+ * Closure to pass to
+ */
+ void *config_cb_cls;
+
+ /**
+ * Data for the request to get the /config of a bank,
+ * NULL once we are past stage #MHS_INIT.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * The whole request line
+ */
+ char *job_url;
+};
+
+
+/**
+ * Decode the JSON in @a resp_obj from the /config response
+ *
+ * @param[in] resp_obj JSON object to parse
+ * @param[in,out] vi where to store the results we decoded
+ * @param[out] vc where to store config compatibility data
+ * @return #TALER_EC_NONE on success
+ */
+static enum TALER_ErrorCode
+decode_config_json (const json_t *resp_obj,
+ struct TALER_BANK_ConfigInformation *vi,
+ enum TALER_BANK_VersionCompatibility *vc)
+{
+ struct TALER_JSON_ProtocolVersion pv;
+ const char *ver;
+ bool bank_name_missing;
+
+ struct GNUNET_JSON_Specification spec[] = {
+ TALER_JSON_spec_version ("version",
+ &pv),
+ GNUNET_JSON_spec_string ("version",
+ &ver),
+ GNUNET_JSON_spec_string ("currency",
+ &vi->currency),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("bank_name",
+ &vi->bank_name),
+ &bank_name_missing),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (JSON_OBJECT != json_typeof (resp_obj))
+ {
+ GNUNET_break_op (0);
+ return TALER_EC_GENERIC_JSON_INVALID;
+ }
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (resp_obj,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return TALER_EC_GENERIC_JSON_INVALID;
+ }
+
+ /* Set default fot optional values */
+ if (bank_name_missing)
+ {
+ vi->bank_name = GNUNET_strdup("Taler Bank");
+ }
+
+ /* Version comparison */
+ vi->version = ver;
+ *vc = TALER_BANK_VC_MATCH;
+ if (TALER_PROTOCOL_CURRENT < pv.current)
+ {
+ *vc |= TALER_BANK_VC_NEWER;
+ if (TALER_PROTOCOL_CURRENT < pv.current - pv.age)
+ *vc |= TALER_BANK_VC_INCOMPATIBLE;
+ }
+ if (TALER_PROTOCOL_CURRENT > pv.current)
+ {
+ *vc |= TALER_BANK_VC_OLDER;
+ if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > pv.current)
+ *vc |= TALER_BANK_VC_INCOMPATIBLE;
+ }
+
+ struct GNUNET_JSON_Specification spec2[] = {
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount ("min_wire_transfer_amount",
+ vi->currency,
+ &vi->min_wire_transfer_amount),
+ NULL),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount ("max_wire_transfer_amount",
+ vi->currency,
+ &vi->max_wire_transfer_amount),
+ NULL),
+ TALER_JSON_spec_currency_specification ("currency_specification",
+ vi->currency,
+ &vi->currency_specification),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount("wire_transfer_fees",
+ vi->currency,
+ &vi->wire_transfer_fees),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (resp_obj,
+ spec2,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return TALER_EC_GENERIC_JSON_INVALID;
+ }
+
+ return TALER_EC_NONE;
+}
+
+
+/**
+ * Callback used when http reply arived to a /config request.
+ *
+ * @param cls the `struct TALER_BANK_GetConfigHandle`
+ * @param response_code HTTP response code or 0 on error
+ * @param gresp_obj JSON result, NULL on error, must be a `const json_t *`
+ */
+static void
+response_cb(void *cls,
+ long response_code,
+ const void *gresp_obj)
+{
+ struct TALER_BANK_GetConfigHandle *bank = cls;
+ const json_t *resp_obj = gresp_obj;
+
+ struct TALER_BANK_ConfigResponse cr = {
+ .hr.response = resp_obj,
+ .hr.http_status = (unsigned int)response_code
+ };
+
+ bank->job = NULL; //job was successfull, curl job cancel not needed anymore in cleanup
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received config from URL `%s' with status %ld.\n",
+ bank->job_url,
+ response_code);
+
+ switch (response_code)
+ {
+ case 0:
+ GNUNET_break_op (0);
+ cr.hr.ec = TALER_EC_INVALID;
+ break;
+ case MHD_HTTP_OK:
+ if (NULL == resp_obj)
+ {
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ cr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ cr.hr.ec = decode_config_json (resp_obj,
+ &cr.details.ok.configi,
+ &cr.details.ok.version_compa);
+ if (TALER_EC_NONE != cr.hr.ec)
+ {
+ GNUNET_break_op (0);
+ cr.hr.http_status = 0;
+ break;
+ }
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ cr.hr.ec = TALER_JSON_get_error_code (resp_obj);
+ cr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
+ break;
+ default:
+ cr.hr.ec = TALER_JSON_get_error_code (resp_obj);
+ cr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) cr.hr.ec);
+ break;
+ }
+
+ bank->config_cb (bank->config_cb_cls, &cr);
+ TALER_BANK_get_config_cancel(bank);
+}
+
+
+struct TALER_BANK_GetConfigHandle *
+TALER_BANK_get_config ( struct GNUNET_CURL_Context *ctx,
+ const char *url,
+ TALER_BANK_ConfigCallback config_cb,
+ void *config_cb_cls)
+{
+ struct TALER_BANK_GetConfigHandle *bank;
+ CURL *eh;
+
+ bank = GNUNET_new(struct TALER_BANK_GetConfigHandle);
+ bank->config_cb = config_cb;
+ bank->config_cb_cls = config_cb_cls;
+ bank->ctx = ctx;
+ bank->job_url = TALER_url_join(url,"config",NULL);
+ if(NULL == bank->job_url)
+ {
+ GNUNET_break(0);
+ GNUNET_free(bank);
+ return NULL;
+ }
+
+ GNUNET_log( GNUNET_ERROR_TYPE_INFO,
+ "Requesting bank config with URL `%s'.\n",
+ bank->job_url);
+ eh = TALER_BANK_curl_easy_get_(bank->job_url);
+ if(NULL == eh)
+ {
+ GNUNET_break(0);
+ TALER_BANK_get_config_cancel(bank);
+ return NULL;
+ }
+ bank->job = GNUNET_CURL_job_add(bank->ctx,
+ eh,
+ &response_cb,
+ bank);
+ if(NULL == bank->job)
+ {
+ GNUNET_break(0);
+ TALER_BANK_get_config_cancel(bank);
+ return NULL;
+ }
+
+ return bank;
+}
+
+
+
+void
+TALER_BANK_get_config_cancel ( struct TALER_BANK_GetConfigHandle *bank)
+{
+ if(NULL != bank->job)
+ {
+ GNUNET_CURL_job_cancel(bank->job);
+ bank->job = NULL;
+ }
+ GNUNET_free(bank->job_url);
+ GNUNET_free(bank);
+}
+
diff --git a/src/lib/bank_api_get_config.h b/src/lib/bank_api_get_config.h
@@ -0,0 +1,213 @@
+/*
+ This file is part of TALER cash2ecash
+ Copyright (C) 2026 GNUnet e.V.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file bank_api_get_config.h
+ * @brief Implementation of the GET /config request of the bank's HTTP API
+ * @author Reto Tellenbach
+ */
+
+#ifndef BANK_API_GET_CONFIG_H
+#define BANK_API_GET_CONFIG_H
+
+#include "../taler/taler_digitizer_service.h"
+
+
+/**
+ * @brief Information we get from the bank about itself. and is needed for the digitizer
+ */
+struct TALER_BANK_ConfigInformation
+{
+
+ /**
+ * Supported Taler protocol version by the bank.
+ * String in the format current:revision:age using the
+ * semantics of GNU libtool. See
+ * https://www.gnu.org/software/libtool/manual/html_node/Versioning.html#Versioning
+ */
+ const char *version;
+
+ /**
+ * Currency used by this bank.
+ */
+ const char *currency;
+
+ /**
+ * Minimum wire transfer amount allowed. Only applies to bank transactions and withdrawals.
+ */
+ struct TALER_Amount min_wire_transfer_amount;
+
+ /**
+ * Maximum wire transfer amount allowed. Only applies to bank transactions and withdrawals.
+ */
+ struct TALER_Amount max_wire_transfer_amount;
+
+ /**
+ * How the bank SPA should render this currency.
+ */
+ struct TALER_CurrencySpecification currency_specification;
+
+ /**
+ * Bank display name to be used in user interfaces.
+ * For consistency use "Taler Bank" if missing.
+ */
+ const char *bank_name;
+
+ /**
+ * Wire transfer execution fees. Only applies to bank transactions and withdrawals.
+ */
+ struct TALER_Amount wire_transfer_fees;
+
+ // /**
+ // * Name of api
+ // */
+ // const char *api_name;
+
+
+ // /**
+ // * Advertised base URL to use when you sharing an URL with another program.
+ // */
+ // const char *base_url;
+
+ // /** If 'true' the server provides local currency conversion support
+ // * If 'false' some parts of the API are not supported and return 501
+ // */
+ // const bool allow_conversion;
+
+ // /** If 'true' anyone can register
+ // * If 'false' only admin can
+ // */
+ // const bool allow_registrations;
+
+ // /**
+ // * If 'true' account can delete themselves
+ // * If 'false' only admin can delete accounts
+ // */
+ // const bool allow_deletions;
+
+ // /**
+ // * If 'true' anyone can edit their name
+ // * If 'false' only admin can
+ // */
+ // const bool allow_edit_name;
+
+ // /**
+ // * If 'true' anyone can edit their cashout account
+ // * If 'false' only admin can
+ // */
+ // const bool allow_edit_cashout_payto_uri;
+
+ // /**
+ // * Default debt limit for newly created accounts
+ // */
+ // const struct TALER_AmountNBO default_debit_threshold;
+
+ // /**
+ // * Stand in string for the TAN channel. Not used in the callbacks
+ // * when used needs to be addapted
+ // * TAN channels supported by the server
+ // */
+ // const char *supported_tan_channels;
+
+ // /**
+ // * Wire transfer type supported by the bank.
+ // * Defaults to 'iban' is missing
+ // */
+ // const char *wire_type;
+
+};
+
+/**
+ * Response details for a config request
+ */
+struct TALER_BANK_ConfigResponse
+{
+
+ /**
+ * HTTP response
+ */
+ struct TALER_BANK_HttpResponse hr;
+
+ /**
+ * Details returned depending on the @e http_status.
+ */
+ union
+ {
+
+ /**
+ * Details if status was request was succesfull
+ */
+ struct
+ {
+
+ /**
+ * Protocol compatibility evaluation.
+ */
+ enum TALER_BANK_VersionCompatibility version_compa;
+
+ /**
+ * Config data returned by /config.
+ */
+ struct TALER_BANK_ConfigInformation configi;
+
+ } ok;
+
+ } details;
+
+};
+
+
+/**
+ * Function called with information about the bank.
+ *
+ * @param cls closure
+ * @param vr response data
+ */
+typedef void
+(*TALER_BANK_ConfigCallback) (
+ void *cls,
+ const struct TALER_BANK_ConfigResponse *vr);
+
+
+/**
+ * Handle for the get config request.
+ */
+struct TALER_BANK_GetConfigHandle;
+
+
+/**
+ * Obtain config inforamtion about the connected Bank
+ * @param ctx
+ * @param url
+ * @return NULL on failure
+ */
+struct TALER_BANK_GetConfigHandle *
+TALER_BANK_get_config ( struct GNUNET_CURL_Context *ctx,
+ const char *url,
+ TALER_BANK_ConfigCallback config_cb,
+ void *config_cb_cls);
+
+/**
+ * Cancel config request. Handles the GNUNet canelation.
+ */
+void
+TALER_BANK_get_config_cancel ( struct TALER_BANK_GetConfigHandle *bank);
+
+
+#endif //BANK_API_GET_CONFIG_H
+\ No newline at end of file
diff --git a/src/taler-digitizer.c b/src/taler-digitizer.c
@@ -0,0 +1,287 @@
+/*
+ This file is part of TALER cash2ecash
+ Copyright (C) 2026 GNUnet e.V.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file taler-digitizer.c
+ * @brief runs the logic for the embeded Cash Digitizer machine
+ * @author Reto Tellenbach
+ */
+
+
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_digitizer_util.h"
+#include "lib/bank_api_get_config.h"
+
+
+/**
+ * Time unit for PERSON_WITHDRAL_PERIOD config.
+ * Normal in Days but can be changed for testing
+ */
+#define DIGITIZER_PERSON_WITHDRAWL_PERIOD_TIME_UNIT GNUNET_TIME_UNIT_DAYS
+
+/**
+ * Global return value
+ */
+static int global_ret;
+
+/**
+ * Global option '-d' to enable diagnostics set.
+ */
+static int enable_diagnostics;
+
+/**
+ * Taler Backend url read from configuration file
+ */
+static char *cfg_backend_base_url;
+
+/**
+ * Currency read from configuration file
+ */
+static char *cfg_currency;
+
+/**
+ * Minimum balance read from configuration file
+ */
+static unsigned long long cfg_backend_min_balance;
+
+/**
+ * Per-person withdrawal limit read from configuration file
+ */
+static unsigned long long cfg_person_withdrawllimit;
+
+/**
+ * Per-person withdrawal period read from configuration file
+ */
+static struct GNUNET_TIME_Relative cfg_person_withdrawl_period;
+
+/**
+ * KYC functionality flag read from configuration file
+ */
+static enum GNUNET_GenericReturnValue cfg_kyc_functionality;
+
+/**
+ * Handle to the context for interacting with the bank.
+ */
+static struct GNUNET_CURL_Context *curl_ctx;
+
+/**
+ * Scheduler context for running the @e ctx.
+ */
+static struct GNUNET_CURL_RescheduleContext *reschedule_ctx;
+
+/**
+ * Handle for get_config request
+ */
+static struct TALER_BANK_GetConfigHandle *get_config_handle;
+
+
+static void
+on_config_received (void *cls,
+ const struct TALER_BANK_ConfigResponse *vr)
+{
+ (void) cls;
+ (void) vr;
+
+ get_config_handle = NULL;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Config Callback\n");
+
+ GNUNET_SCHEDULER_shutdown ();
+}
+
+
+/**
+ * @brief Cleanup when no task is scheduled anymore
+ *
+ * @param cls closure
+ */
+static void
+shutdown_task (void *cls)
+{
+ (void)cls;
+
+ if (NULL != get_config_handle)
+ {
+ TALER_BANK_get_config_cancel (get_config_handle);
+ get_config_handle = NULL;
+ }
+ if (NULL != reschedule_ctx)
+ {
+ GNUNET_CURL_gnunet_rc_destroy (reschedule_ctx);
+ reschedule_ctx = NULL;
+ }
+ if (NULL != curl_ctx)
+ {
+ GNUNET_CURL_fini (curl_ctx);
+ curl_ctx = NULL;
+ }
+}
+
+
+/**
+ * @brief Start the application
+ *
+ * @param cls closure
+ * @param args arguments left
+ * @param cfgfile config file name
+ * @param cfg handle for the configuration
+ */
+static void
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ (void) cls;
+ (void) args;
+ (void) cfgfile;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Parse Configuration\n");
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "taler-digitizer",
+ "BACKEND_BASE_URL",
+ &cfg_backend_base_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler-digitizer",
+ "BACKEND_BASE_URL");
+ global_ret = EXIT_FAILURE;
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "taler-digitizer",
+ "CURRENCY",
+ &cfg_currency))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler-digitizer",
+ "CURRENCY");
+ global_ret = EXIT_FAILURE;
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "taler-digitizer",
+ "BANK_MIN_BALANCE",
+ &cfg_backend_min_balance))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler-digitizer",
+ "BANK_MIN_BALANCE");
+ global_ret = EXIT_FAILURE;
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "taler-digitizer",
+ "PERSON_WITHDRAWLLIMIT",
+ &cfg_person_withdrawllimit))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler-digitizer",
+ "PERSON_WITHDRAWLLIMIT");
+ global_ret = EXIT_FAILURE;
+ return;
+ }
+
+ unsigned long long person_withdrawl_period_number;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "taler-digitizer",
+ "PERSON_WITHDRAL_PERIOD",
+ &person_withdrawl_period_number))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler-digitizer",
+ "PERSON_WITHDRAL_PERIOD");
+ global_ret = EXIT_FAILURE;
+ return;
+ }
+ cfg_person_withdrawl_period = GNUNET_TIME_relative_multiply (
+ DIGITIZER_PERSON_WITHDRAWL_PERIOD_TIME_UNIT,
+ person_withdrawl_period_number);
+
+ cfg_kyc_functionality = GNUNET_CONFIGURATION_get_value_yesno (cfg,
+ "taler-digitizer",
+ "KYC_FUNCTIONALITY");
+ if (GNUNET_SYSERR == cfg_kyc_functionality)
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler-digitizer",
+ "KYC_FUNCTIONALITY");
+ global_ret = EXIT_FAILURE;
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Config URL: %s\n",
+ cfg_backend_base_url);
+
+ curl_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
+ &reschedule_ctx);
+ reschedule_ctx = GNUNET_CURL_gnunet_rc_create (curl_ctx);
+
+ GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+ NULL);
+
+ get_config_handle = TALER_BANK_get_config (curl_ctx,
+ cfg_backend_base_url,
+ &on_config_received,
+ NULL);
+
+
+ return;
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ int ret;
+
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_option_flag ('d',
+ "enable-diagnostics",
+ "enable diagnostics for debuging",
+ &enable_diagnostics),
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ ret = GNUNET_PROGRAM_run (TALER_DIGITIZER_project_data (),
+ argc,
+ argv,
+ "taler-digitizer",
+ "This is an application for the Cash Digitizer."
+ " It accepts cash and transfers it to the Taler Wallet.\n",
+ options,
+ &run,
+ NULL);
+
+ if (GNUNET_NO == ret)
+ return 0;
+ if (GNUNET_OK != ret)
+ return 1;
+ return global_ret;
+}
+\ No newline at end of file
diff --git a/src/taler/taler_digitizer_service.h b/src/taler/taler_digitizer_service.h
@@ -0,0 +1,118 @@
+/*
+ This file is part of TALER cash2ecash
+ Copyright (C) 2026 GNUnet e.V.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file include/taler/taler_bank_service.h
+ * @brief C interface for taler libs used by the digitizer
+ * @author Reto Tellenbach
+ */
+
+#ifndef _TALER_DIGITIZER_SERVICE_H
+#define _TALER_DIGITIZER_SERVICE_H
+
+
+#include <taler/taler_bank_service.h>
+#include <taler/taler_util.h>
+#include "../lib/bank_api_get_config.h"
+
+/**
+ * How compatible are the protocol version of the bank and this
+ * client? The bits (1,2,4) can be used to test if the auditor's
+ * version is incompatible, older or newer respectively.
+ */
+enum TALER_BANK_VersionCompatibility
+{
+
+ /**
+ * The bank runs exactly the same protocol version.
+ */
+ TALER_BANK_VC_MATCH = 0,
+
+ /**
+ * The bank is too old or too new to be compatible with this
+ * implementation (bit)
+ */
+ TALER_BANK_VC_INCOMPATIBLE = 1,
+
+ /**
+ * The bank is older than this implementation (bit)
+ */
+ TALER_BANK_VC_OLDER = 2,
+
+ /**
+ * The bank is too old to be compatible with
+ * this implementation.
+ */
+ TALER_BANK_VC_INCOMPATIBLE_OUTDATED
+ = TALER_BANK_VC_INCOMPATIBLE
+ | TALER_BANK_VC_OLDER,
+
+ /**
+ * The bank is more recent than this implementation (bit).
+ */
+ TALER_BANK_VC_NEWER = 4,
+
+ /**
+ * The bank is too recent for this implementation.
+ */
+ TALER_BANK_VC_INCOMPATIBLE_NEWER
+ = TALER_BANK_VC_INCOMPATIBLE
+ | TALER_BANK_VC_NEWER,
+
+ /**
+ * We could not even parse the version data.
+ */
+ TALER_BANK_VC_PROTOCOL_ERROR = 8
+
+};
+
+
+/**
+ * General information about the HTTP response we obtained
+ * from the bank for a request.
+ */
+struct TALER_BANK_HttpResponse
+{
+
+ /**
+ * Full response, NULL if body was not in JSON format.
+ */
+ const json_t *response;
+
+ /**
+ * Set to the human-readable 'hint' that is optionally
+ * provided by the exchange together with errors. NULL
+ * if no hint was provided or if there was no error.
+ */
+ const char *hint;
+
+ /**
+ * HTTP status code for the response.
+ */
+ unsigned int http_status;
+
+ /**
+ * Taler error code, #TALER_EC_NONE on success.
+ */
+ enum TALER_ErrorCode ec;
+
+};
+
+
+#endif
+\ No newline at end of file
diff --git a/src/taler_digitizer_util.h b/src/taler_digitizer_util.h
@@ -0,0 +1,56 @@
+/*
+ This file is part of TALER cash2ecash
+ Copyright (C) 2026 GNUnet e.V.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file taler-digitizer_util.h
+ * @brief Interface for common utility functions, and base project settings
+ * @author Reto Tellenbach
+ */
+#ifndef TALER_DIGITIZER_UTIL_H
+#define TALER_DIGITIZER_UTIL_H
+
+#include <gnunet/gnunet_util_lib.h>
+
+/**
+ * Default project data. When shipping use a seperate os_installation.c which sets values at installation.
+ */
+static const struct GNUNET_OS_ProjectData digitizer_pd = {
+ .base_config_varname = "TALER_DIGITIZER_PREFIX",
+ .bug_email = "taler@lists.gnu.org",
+ .homepage = "http://www.gnu.org/s/taler/",
+ .config_file = "taler-digitizer.conf",
+ .user_config_file = "~/.config/taler-digitizer.conf",
+ .version = "0.1.0",
+ .is_gnu = 0,
+ .gettext_domain = NULL,
+ .gettext_path = NULL,
+};
+
+/**
+ * Return default project data.
+ */
+const struct GNUNET_OS_ProjectData *
+TALER_DIGITIZER_project_data (void)
+{
+ return &digitizer_pd;
+}
+
+
+
+#endif
diff --git a/taler-digitizer.conf b/taler-digitizer.conf
@@ -0,0 +1,34 @@
+[taler-digitizer]
+BACKEND_BASE_URL = https://exchange.demo.taler.net/
+CURRENCY = KUDOS
+
+#BANK_ACCOUNT = sdflksdflsdkjf
+
+# Balance required to start a Transaction
+BANK_MIN_BALANCE = 1000
+
+# Withdrawl limitation per person, for a limited time period.
+# This can only be enforced with KYC functionality
+PERSON_WITHDRAWLLIMIT = 200
+PERSON_WITHDRAL_PERIOD = 10
+
+
+#BACKEND_AUTHORIZATION = Bearer secret-token:sandbox
+KYC_FUNCTIONALITY = NO
+
+# Name of the framebuffer to use for the QR code.
+FRAMEBUFFER_DEVICE = /dev/fb1
+
+# Name of the backlight file for the framebuffer
+FRAMEBUFFER_BACKLIGHT = /sys/class/backlight/soc:backlight/brightness
+
+[coin-acceptor]
+ENABLE = YES
+GPIO_CHIP = /dev/gpiochip0
+GPIO_PIN = 16
+bigest_denomination = 5
+
+
+[bill-acceptor]
+ENABLE = NO
+bigest_denomination = 100