commit 6d9c605740f77f629152977900138a37af168392
parent 47590e7159d5be7b252160ede32a9810f222e9f6
Author: Christian Grothoff <christian@grothoff.org>
Date: Tue, 17 Jun 2025 17:02:44 +0200
draft API for #9027
Diffstat:
8 files changed, 489 insertions(+), 160 deletions(-)
diff --git a/configure.ac b/configure.ac
@@ -534,6 +534,7 @@ AC_CONFIG_FILES([Makefile
src/testing/Makefile
src/benchmark/Makefile
src/include/Makefile
+ src/include/taler-exchange/Makefile
src/json/Makefile
src/mhd/Makefile
src/pq/Makefile
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
@@ -1,4 +1,5 @@
# This Makefile.am is in the public domain
+SUBDIRS = taler-exchange .
talerincludedir = $(includedir)/taler
talerinclude_HEADERS = \
@@ -37,5 +38,4 @@ talerinclude_HEADERS += \
endif
EXTRA_DIST = \
- backoff.h \
- gauger.h
+ backoff.h
diff --git a/src/include/gauger.h b/src/include/gauger.h
@@ -1,110 +0,0 @@
-/** ---------------------------------------------------------------------------
- * This software is in the public domain, furnished "as is", without technical
- * support, and with no warranty, express or implied, as to its usefulness for
- * any purpose.
- *
- * gauger.h
- * Interface for C programs to log remotely to a gauger server
- *
- * Author: Bartlomiej Polot
- * -------------------------------------------------------------------------*/
-#ifndef __GAUGER_H__
-#define __GAUGER_H__
-
-#ifndef WINDOWS
-
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/wait.h>
-
-#define GAUGER(category, counter, value, unit) \
- { \
- const char *__gauger_v[10]; \
- char __gauger_s[32]; \
- pid_t __gauger_p; \
- if (! (__gauger_p = fork ())) { \
- if (! fork ()) { \
- sprintf (__gauger_s,"%Lf", (long double) (value)); \
- __gauger_v[0] = "gauger"; \
- __gauger_v[1] = "-n"; \
- __gauger_v[2] = (char *) counter; \
- __gauger_v[3] = "-d"; \
- __gauger_v[4] = __gauger_s; \
- __gauger_v[5] = "-u"; \
- __gauger_v[6] = (char *) unit; \
- __gauger_v[7] = "-c"; \
- __gauger_v[8] = (char *) category; \
- __gauger_v[9] = (char *) NULL; \
- execvp ("gauger", (char *const *) __gauger_v); \
- perror ("gauger"); \
- _exit (1); \
- }else{ \
- _exit (0); \
- } \
- }else{ \
- waitpid (__gauger_p,NULL,0); \
- } \
- }
-
-#define GAUGER_ID(category, counter, value, unit, id) \
- { \
- char*__gauger_v[12]; \
- char __gauger_s[32]; \
- pid_t __gauger_p; \
- if (! (__gauger_p = fork ())) { \
- if (! fork ()) { \
- sprintf (__gauger_s,"%Lf", (long double) (value)); \
- __gauger_v[0] = "gauger"; \
- __gauger_v[1] = "-n"; \
- __gauger_v[2] = (char *) counter; \
- __gauger_v[3] = "-d"; \
- __gauger_v[4] = __gauger_s; \
- __gauger_v[5] = "-u"; \
- __gauger_v[6] = (char *) unit; \
- __gauger_v[7] = "-i"; \
- __gauger_v[8] = id; \
- __gauger_v[9] = "-c"; \
- __gauger_v[10] = (char *) category; \
- __gauger_v[11] = (char *) NULL; \
- execvp ("gauger",__gauger_v); \
- perror ("gauger"); \
- _exit (1); \
- }else{ \
- _exit (0); \
- } \
- }else{ \
- waitpid (__gauger_p,NULL,0); \
- } \
- }
-
-#else /* WINDOWS */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <windef.h>
-
-#define GAUGER(category, counter, value, unit) \
- { \
- char __gauger_commandline[MAX_PATH]; \
- \
- snprintf (__gauger_commandline, MAX_PATH, \
- "gauger.py -n \"%s\" -d \"%Lf\" -u \"%s\" -c \"%s\"", \
- counter, (long double) (value), unit, category); \
- __gauger_commandline[MAX_PATH - 1] = '\0'; \
- system (__gauger_commandline); \
- }
-
-#define GAUGER_ID(category, counter, value, unit, id) \
- { \
- char __gauger_commandline[MAX_PATH]; \
- \
- snprintf (__gauger_commandline, MAX_PATH, \
- "gauger.py -n \"%s\" -d \"%Lf\" -u \"%s\" -i \"%s\" -c \"%s\"", \
- counter, (long double) (value), unit, id, category); \
- __gauger_commandline[MAX_PATH - 1] = '\0'; \
- system (__gauger_commandline); \
- }
-
-#endif // WINDOWS
-
-#endif
diff --git a/src/include/taler-exchange/Makefile.am b/src/include/taler-exchange/Makefile.am
@@ -0,0 +1,6 @@
+# This Makefile.am is in the public domain
+talerincludedir = $(includedir)/taler/taler-exchange
+
+talerinclude_HEADERS = \
+ aml_legitimizations_get.h \
+ common.h
diff --git a/src/include/taler-exchange/aml_legitimizations_get.h b/src/include/taler-exchange/aml_legitimizations_get.h
@@ -0,0 +1,401 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2025 Taler Systems SA
+
+ TALER 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, 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file include/taler-exchange/aml_legitimizations_get.h
+ * @brief C interface for the GET /aml/$OFFICER_PUB/legitimizations endpoint
+ * @author Christian Grothoff
+ */
+#ifndef _TALER_EXCHANGE__AML_LEGITIMIZATIONS_GET_H
+#define _TALER_EXCHANGE__AML_LEGITIMIZATIONS_GET_H
+
+#include <taler-exchange/common.h>
+
+/**
+ * Possible options we can set for the GET legitimizations request.
+ */
+enum TALER_EXCHANGE_AmlLegitimizationsGetOption
+{
+ /**
+ * End of list of options.
+ */
+ TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_END = 0,
+
+ /**
+ * Return at most N values, default is -20 to return
+ * the last 20 entries before start. Negative values
+ * to return before limit, positive to return after limit.
+ */
+ TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_LIMIT,
+
+ /**
+ * Row number threshold, defaults to INT64_MAX, namely
+ * the biggest row id possible in the database.
+ */
+ TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_OFFSET,
+
+ /**
+ * Filter by account using a normalized payto URI hash.
+ */
+ TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_H_PAYTO,
+
+ /**
+ * If set to #TALER_EXCHANGE_YNA_YES, only return active
+ * results, #TALER_EXCHANGE_YNA_NO, only return inactive
+ * results, #TALER_EXCHANGE_YNA_ALL, to return all
+ * decisions. Default is all.
+ */
+ TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_ACTIVE
+
+};
+
+
+/**
+ * Possible options we can set for the GET legitimizations request.
+ */
+struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue
+{
+
+ /**
+ * Type of the option being set.
+ */
+ enum TALER_EXCHANGE_AmlLegitimizationsGetOption option;
+
+ /**
+ * Specific option value.
+ */
+ union
+ {
+
+ /**
+ * Value of if @e option is TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_LIMIT.
+ */
+ int64_t limit;
+
+ /**
+ * Value of if @e option is TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_OFFSET.
+ * Note that in practice the maximum value is INT64_MAX, even though
+ * this value is unsigned.
+ */
+ uint64_t offset;
+
+ /**
+ * Value of if @e option is TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_H_PAYTO.
+ */
+ const struct TALER_NormalizedPaytoHashP *h_payto;
+
+ /**
+ * Value of if @e option is TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_ACTIVE.
+ */
+ enum TALER_EXCHANGE_YesNoAll active;
+
+ } details;
+
+};
+
+
+/**
+ * Handle for an operation to GET /aml/$OFFICER_PUB/legitimizations.
+ */
+struct TALER_EXCHANGE_AmlLegitimizationsGetHandle;
+
+
+/**
+ * Set up GET /aml/$OPUB/legitimizations operation.
+ * Note that you must explicitly start the operation after
+ * possibly setting options.
+ *
+ * @param ctx the context
+ * @param url base URL of the exchange
+ * @param officer_priv private key of the officer
+ * @return handle to operation
+ */
+struct TALER_EXCHANGE_AmlLegitimizationsGetHandle *
+TALER_EXCHANGE_aml_legitimizations_get_create (
+ struct GNUNET_CURL_Context *ctx,
+ const char *url,
+ const struct TALER_AmlOfficerPrivateKeyP *officer_priv);
+
+
+/**
+ * Terminate the list of the options.
+ *
+ * @return the terminating object of struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue
+ */
+#define TALER_EXCHANGE_aml_legitimizations_get_option_end_() \
+ (const struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue) \
+ { \
+ .option = TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_END \
+ }
+
+/**
+ * Set limit @a l on the number of results to return.
+ *
+ * @param l limit on the number of results to return
+ * @return representation of the option as a struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue
+ */
+#define TALER_EXCHANGE_aml_legitimizations_get_option_limit_(l) \
+ (const struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue) \
+ { \
+ .option = TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_LIMIT, \
+ .details.limit = (l) \
+ }
+
+
+/**
+ * Set row offset from which to return results.
+ *
+ * @param o offset to use
+ * @return representation of the option as a struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue
+ */
+#define TALER_EXCHANGE_aml_legitimizations_get_option_offset_(o) \
+ (const struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue) \
+ { \
+ .option = TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_OFFSET, \
+ .details.offset = (o) \
+ }
+
+
+/**
+ * Set filter on which account to filter legitimization measures by.
+ *
+ * @param p normalized payto URI hash of the account to filter by
+ * @return representation of the option as a struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue
+ */
+#define TALER_EXCHANGE_aml_legitimizations_get_option_h_payto_(p) \
+ (const struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue) \
+ { \
+ .option = TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_H_PAYTO, \
+ .details.h_payto = (p) \
+ }
+
+/**
+ * Set filter on active (or inactive) results.
+ *
+ * @param a activity filter to use
+ * @return representation of the option as a struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue
+ */
+#define TALER_EXCHANGE_aml_legitimizations_get_option_active_(a) \
+ (const struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue) \
+ { \
+ .option = TALER_EXCHANGE_AML_LEGITIMIZATIONS_GET_OPTION_ACTIVE, \
+ .details.active = (o) \
+ }
+
+
+enum TALER_ErrorCode
+TALER_EXCHANGE_aml_legitimizations_get_set_options_ (
+ struct TALER_EXCHANGE_AmlLegitimizationsGetHandle *algh,
+ unsigned int num_options,
+ struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue options[
+ static num_options]);
+
+
+/**
+ * Set the requested options for the operation.
+ *
+ * If any option fail other options may be or may be not applied.
+ *
+ * It should be used with helpers that creates required options, for example:
+ *
+ * TALER_EXCHANGE_aml_legitimizations_get_set_options (
+ * algh,
+ * TALER_EXCHANGE_aml_legitimizations_get_option_h_payto_(&h_payto));
+ *
+ * @param algh the request to set the options for
+ * @param ... the list of the options, each option must be created
+ * by helpers TALER_EXCHANGE_aml_legitimizations_get_option_NAME(VALUE)
+ * @return ::TALER_EC_NONE on success,
+ * error code otherwise
+ */
+#define TALER_EXCHANGE_aml_legitimizations_get_set_options(algh,...) \
+ TALER_EXCHANGE_aml_legitimizations_get_set_options_ ( \
+ algh, \
+ ((const struct TALER_EXCHANGE_AmlLegitimizationsGetOptionValue[]) \
+ {__VA_ARGS__, TALER_EXCHANGE_aml_legitimizations_get_option_end_ () } \
+ ), \
+ TALER_EXCHANGE_COMMON_OPTIONS_ARRAY_MAX_SIZE)
+
+
+/**
+ * Information about legitimization measures that apply to the
+ * customer at a particular point in time.
+ */
+struct TALER_EXCHANGE_AmlLegitimizationsGetMeasureInformation
+{
+ /**
+ * Name of the KYC check.
+ */
+ const char *check_name;
+
+ /**
+ * Name of the AML program to run on the KYC check's result.
+ */
+ const char *prog_name;
+
+ /**
+ * Context for the check and AML program. Can be NULL!
+ */
+ const json_t *context;
+
+ /**
+ * Type of operation that triggered this measure,
+ * #TALER_KYCLOGIC_KYC_TRIGGER_NONE if unknown / not applicable.
+ */
+ enum TALER_KYCLOGIC_KycTriggerEvent operation_type;
+
+ /**
+ * True if the customer can voluntarily do this measure.
+ */
+ bool voluntary;
+};
+
+
+/**
+ * Entry in the set of legitimization measures that are returned
+ * by the server in a single request.
+ */
+struct TALER_EXCHANGE_AmlLegitimizationsGetMeasureDetails
+{
+ /**
+ * Account the measure applies to.
+ */
+ struct TALER_NormalizedPaytoHashP h_payto;
+
+ /**
+ * Row ID of the measure in the exchange.
+ */
+ uint64_t rowid;
+
+ /**
+ * When was the measure started/triggered?
+ */
+ struct GNUNET_TIME_Timestamp start_time;
+
+ /**
+ * Length of the @e mi array.
+ */
+ size_t mi_length;
+
+ /**
+ * Array of legitimization measures that are to be applied.
+ */
+ struct TALER_EXCHANGE_AmlLegitimizationsGetMeasureInformation *mi;
+
+ /**
+ * True if the entries in the
+ * the @e mi are expected to be all satisfied,
+ * false if the customer has to chose one of them.
+ */
+ bool is_and_combinator;
+
+ /**
+ * Was some operation categorically forbidden and hence
+ * the customer cannot even do something here? If true,
+ * then the @e mi array will be empty.
+ */
+ bool verboten;
+
+ /**
+ * Was this measure finished by the customer (or obsoleted
+ * by a subsequent other measure taken)?
+ */
+ bool is_finished;
+};
+
+/**
+ * Information returned from the exchange for a
+ * GET /aml/$OFFICER_PUB/legitimizations request.
+ */
+struct TALER_EXCHANGE_AmlLegitimizationsGetResult
+{
+ /**
+ * HTTP response data
+ */
+ struct TALER_EXCHANGE_HttpResponse hr;
+
+ /**
+ * Details depending on the HTTP status code.
+ */
+ union
+ {
+
+ /**
+ * Details on #MHD_HTTP_OK.
+ */
+ struct
+ {
+ /**
+ * Length of the @e measures array.
+ */
+ size_t measures_length;
+
+ /**
+ * Legitimization measures that apply to the account(s).
+ */
+ const struct TALER_EXCHANGE_AmlLegitimizationsGetMeasureDetails *measures;
+
+ } ok;
+
+ } details;
+};
+
+
+#ifndef TALER_EXCHANGE__AML_LEGITIMIZATIONS_GET_RESULT_CLOSURE
+/**
+ * Type of the closure used by
+ * the #TALER_EXCHANGE_AmlLegitimizationsGetCallback.
+ */
+#define TALER_EXCHANGE__AML_LEGITIMIZATIONS_GET_RESULT_CLOSURE void
+#endif
+
+/**
+ * Type of the function that receives the result of a
+ * GET /aml/$OFFICER_PUB/legitimizations request.
+ *
+ * @param cls closure
+ * @param result result returned by the HTTP server
+ */
+typedef void
+(*TALER_EXCHANGE_AmlLegitimizationsGetCallback)(
+ TALER_EXCHANGE__AML_LEGITIMIZATIONS_GET_RESULT_CLOSURE *cls,
+ const struct TALER_EXCHANGE_AmlLegitimizationsGetResult *result);
+
+
+/**
+ * Start GET /aml/$OPUB/legitimizations operation.
+ *
+ * @param[in,out] algh operation to start
+ * @param cb function to call with the exchange's result
+ * @param cb_cls closure for @a cb
+ */
+void
+TALER_EXCHANGE_aml_legitimizations_get_start (
+ struct TALER_EXCHANGE_AmlLegitimizationsGetHandle *algh,
+ TALER_EXCHANGE_AmlLegitimizationsGetCallback cb,
+ TALER_EXCHANGE__AML_LEGITIMIZATIONS_GET_RESULT_CLOSURE *cb_cls);
+
+
+/**
+ * Cancel GET /aml/$OPUB/legitimizations operation.
+ *
+ * @param[in] algh operation to cancel
+ */
+void
+TALER_EXCHANGE_aml_legitimizations_get_cancel (
+ struct TALER_EXCHANGE_AmlLegitimizationsGetHandle *algh);
+
+
+#endif
diff --git a/src/include/taler-exchange/common.h b/src/include/taler-exchange/common.h
@@ -0,0 +1,74 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2025 Taler Systems SA
+
+ TALER 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, 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+/**
+ * @file include/taler-exchange/common.h
+ * @brief C interface of libtalerexchange, a C library to use exchange's HTTP API
+ * This library is not thread-safe, all APIs must only be used from a single thread.
+ * This library calls abort() if it runs out of memory. Be aware of these limitations.
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ * @author Christian Grothoff
+ * @author Özgür Kesim
+ */
+#ifndef _TALER_EXCHANGE__COMMON_H
+#define _TALER_EXCHANGE__COMMON_H
+
+#include <jansson.h>
+#include "taler_util.h"
+#include "taler_error_codes.h"
+#include <gnunet/gnunet_curl_lib.h>
+
+
+/**
+ * General information about the HTTP response we obtained
+ * from the exchange for a request.
+ */
+struct TALER_EXCHANGE_HttpResponse
+{
+
+ /**
+ * The complete JSON reply. NULL if we failed to parse the
+ * reply (too big, invalid JSON).
+ */
+ const json_t *reply;
+
+ /**
+ * 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. 0 if the
+ * HTTP request failed and we did not get any answer, or
+ * if the answer was invalid and we set @a ec to a
+ * client-side error code.
+ */
+ unsigned int http_status;
+
+ /**
+ * Taler error code. #TALER_EC_NONE if everything was
+ * OK. Usually set to the "code" field of an error
+ * response, but may be set to values created at the
+ * client side, for example when the response was
+ * not in JSON format or was otherwise ill-formed.
+ */
+ enum TALER_ErrorCode ec;
+
+};
+
+
+#endif
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
@@ -25,17 +25,14 @@
#ifndef _TALER_EXCHANGE_SERVICE_H
#define _TALER_EXCHANGE_SERVICE_H
-#include <jansson.h>
-#include "taler_util.h"
-#include "taler_error_codes.h"
-#include <gnunet/gnunet_curl_lib.h>
-
+#include <taler-exchange/common.h>
+#include <taler-exchange/aml_legitimizations_get.h>
/**
* Version of the Taler Exchange API, in hex.
* Thus 0.8.4-1 = 0x00080401.
*/
-#define TALER_EXCHANGE_API_VERSION 0x00100006
+#define TALER_EXCHANGE_API_VERSION 0x00100007
/**
* Information returned when a client needs to pass
@@ -772,46 +769,6 @@ enum TALER_EXCHANGE_VersionCompatibility
/**
- * General information about the HTTP response we obtained
- * from the exchange for a request.
- */
-struct TALER_EXCHANGE_HttpResponse
-{
-
- /**
- * The complete JSON reply. NULL if we failed to parse the
- * reply (too big, invalid JSON).
- */
- const json_t *reply;
-
- /**
- * 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. 0 if the
- * HTTP request failed and we did not get any answer, or
- * if the answer was invalid and we set @a ec to a
- * client-side error code.
- */
- unsigned int http_status;
-
- /**
- * Taler error code. #TALER_EC_NONE if everything was
- * OK. Usually set to the "code" field of an error
- * response, but may be set to values created at the
- * client side, for example when the response was
- * not in JSON format or was otherwise ill-formed.
- */
- enum TALER_ErrorCode ec;
-
-};
-
-
-/**
* Response from /keys.
*/
struct TALER_EXCHANGE_KeysResponse
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
@@ -790,8 +790,8 @@ enum TALER_EXCHANGE_YesNoAll
TALER_EXCHANGE_YNA_YES = 1,
/**
- * If condition is no.
- */
+ * If condition is no.
+ */
TALER_EXCHANGE_YNA_NO = 2,
/**