LCOV - code coverage report
Current view: top level - lib - exchange_api_get-aml-OFFICER_PUB-decisions.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 73.2 % 254 186
Test Date: 2026-04-14 15:39:31 Functions: 100.0 % 8 8

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2023, 2024, 2026 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11              :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see
      15              :   <http://www.gnu.org/licenses/>
      16              : */
      17              : /**
      18              :  * @file lib/exchange_api_get-aml-OFFICER_PUB-decisions.c
      19              :  * @brief Implementation of the /aml/$OFFICER_PUB/decisions request
      20              :  * @author Christian Grothoff
      21              :  */
      22              : #include <microhttpd.h> /* just for HTTP status codes */
      23              : #include <gnunet/gnunet_util_lib.h>
      24              : #include <gnunet/gnunet_curl_lib.h>
      25              : #include "taler/taler_json_lib.h"
      26              : #include "taler/exchange/get-aml-OFFICER_PUB-decisions.h"
      27              : #include "exchange_api_handle.h"
      28              : #include "taler/taler_signatures.h"
      29              : #include "exchange_api_curl_defaults.h"
      30              : 
      31              : 
      32              : /**
      33              :  * @brief A GET /aml/$OFFICER_PUB/decisions Handle
      34              :  */
      35              : struct TALER_EXCHANGE_GetAmlDecisionsHandle
      36              : {
      37              : 
      38              :   /**
      39              :    * The base URL of the exchange.
      40              :    */
      41              :   char *base_url;
      42              : 
      43              :   /**
      44              :    * The full URL for this request, set during _start.
      45              :    */
      46              :   char *url;
      47              : 
      48              :   /**
      49              :    * Handle for the request.
      50              :    */
      51              :   struct GNUNET_CURL_Job *job;
      52              : 
      53              :   /**
      54              :    * Function to call with the result.
      55              :    */
      56              :   TALER_EXCHANGE_GetAmlDecisionsCallback cb;
      57              : 
      58              :   /**
      59              :    * Closure for @e cb.
      60              :    */
      61              :   TALER_EXCHANGE_GET_AML_DECISIONS_RESULT_CLOSURE *cb_cls;
      62              : 
      63              :   /**
      64              :    * Reference to the execution context.
      65              :    */
      66              :   struct GNUNET_CURL_Context *ctx;
      67              : 
      68              :   /**
      69              :    * Public key of the AML officer.
      70              :    */
      71              :   struct TALER_AmlOfficerPublicKeyP officer_pub;
      72              : 
      73              :   /**
      74              :    * Private key of the AML officer (for signing).
      75              :    */
      76              :   struct TALER_AmlOfficerPrivateKeyP officer_priv;
      77              : 
      78              :   /**
      79              :    * Signature of the AML officer.
      80              :    */
      81              :   struct TALER_AmlOfficerSignatureP officer_sig;
      82              : 
      83              :   /**
      84              :    * Options for the request.
      85              :    */
      86              :   struct
      87              :   {
      88              :     /**
      89              :      * Limit on number of results (-20 by default).
      90              :      */
      91              :     int64_t limit;
      92              : 
      93              :     /**
      94              :      * Row offset threshold (INT64_MAX by default).
      95              :      */
      96              :     uint64_t offset;
      97              : 
      98              :     /**
      99              :      * Optional account filter; NULL if not set.
     100              :      */
     101              :     const struct TALER_NormalizedPaytoHashP *h_payto;
     102              : 
     103              :     /**
     104              :      * Filter for active decisions (YNA_ALL by default).
     105              :      */
     106              :     enum TALER_EXCHANGE_YesNoAll active;
     107              : 
     108              :     /**
     109              :      * Filter for investigation status (YNA_ALL by default).
     110              :      */
     111              :     enum TALER_EXCHANGE_YesNoAll investigation;
     112              :   } options;
     113              : 
     114              :   /**
     115              :    * Flat array of all KYC rules across all decisions (allocated during parse).
     116              :    */
     117              :   struct TALER_EXCHANGE_GetAmlDecisionsKycRule *all_rules;
     118              : 
     119              :   /**
     120              :    * Flat array of all measure string pointers across all rules (allocated during parse).
     121              :    */
     122              :   const char **all_mp;
     123              : 
     124              : };
     125              : 
     126              : 
     127              : /**
     128              :  * Parse the limits/rules object.
     129              :  *
     130              :  * @param[in,out] adgh handle (used for allocation tracking)
     131              :  * @param jlimits JSON object with legitimization rule set data
     132              :  * @param[out] limits where to write the parsed rule set
     133              :  * @param[in,out] rule_off current offset into adgh->all_rules (advanced)
     134              :  * @param[in,out] mp_off current offset into adgh->all_mp (advanced)
     135              :  * @return #GNUNET_OK on success
     136              :  */
     137              : static enum GNUNET_GenericReturnValue
     138            6 : parse_limits (
     139              :   struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh,
     140              :   const json_t *jlimits,
     141              :   struct TALER_EXCHANGE_GetAmlDecisionsLegitimizationRuleSet *limits,
     142              :   size_t *rule_off,
     143              :   size_t *mp_off)
     144              : {
     145              :   const json_t *jrules;
     146              :   const json_t *jcustom_measures;
     147              :   struct GNUNET_JSON_Specification spec[] = {
     148            6 :     GNUNET_JSON_spec_timestamp ("expiration_time",
     149              :                                 &limits->expiration_time),
     150            6 :     GNUNET_JSON_spec_mark_optional (
     151              :       GNUNET_JSON_spec_string ("successor_measure",
     152              :                                &limits->successor_measure),
     153              :       NULL),
     154            6 :     GNUNET_JSON_spec_array_const ("rules",
     155              :                                   &jrules),
     156            6 :     GNUNET_JSON_spec_mark_optional (
     157              :       GNUNET_JSON_spec_object_const ("custom_measures",
     158              :                                      &jcustom_measures),
     159              :       NULL),
     160            6 :     GNUNET_JSON_spec_end ()
     161              :   };
     162              : 
     163            6 :   if (GNUNET_OK !=
     164            6 :       GNUNET_JSON_parse (jlimits,
     165              :                          spec,
     166              :                          NULL,
     167              :                          NULL))
     168              :   {
     169            0 :     GNUNET_break_op (0);
     170            0 :     return GNUNET_SYSERR;
     171              :   }
     172            6 :   limits->custom_measures = jcustom_measures;
     173              : 
     174              :   {
     175            6 :     size_t rule_count = json_array_size (jrules);
     176            6 :     size_t rule_start = *rule_off;
     177              : 
     178            6 :     limits->rules = &adgh->all_rules[rule_start];
     179            6 :     limits->rules_length = rule_count;
     180              : 
     181              :     {
     182              :       const json_t *jrule;
     183              :       size_t ridx;
     184              : 
     185           37 :       json_array_foreach ((json_t *) jrules, ridx, jrule)
     186              :       {
     187           31 :         struct TALER_EXCHANGE_GetAmlDecisionsKycRule *r
     188           31 :           = &adgh->all_rules[*rule_off];
     189              :         const json_t *jsmeasures;
     190              :         struct GNUNET_JSON_Specification rspec[] = {
     191           31 :           TALER_JSON_spec_kycte ("operation_type",
     192              :                                  &r->operation_type),
     193           31 :           GNUNET_JSON_spec_mark_optional (
     194              :             GNUNET_JSON_spec_string ("rule_name",
     195              :                                      &r->rule_name),
     196              :             NULL),
     197           31 :           TALER_JSON_spec_amount_any ("threshold",
     198              :                                       &r->threshold),
     199           31 :           GNUNET_JSON_spec_relative_time ("timeframe",
     200              :                                           &r->timeframe),
     201           31 :           GNUNET_JSON_spec_array_const ("measures",
     202              :                                         &jsmeasures),
     203           31 :           GNUNET_JSON_spec_mark_optional (
     204              :             GNUNET_JSON_spec_bool ("exposed",
     205              :                                    &r->exposed),
     206              :             NULL),
     207           31 :           GNUNET_JSON_spec_mark_optional (
     208              :             GNUNET_JSON_spec_bool ("is_and_combinator",
     209              :                                    &r->is_and_combinator),
     210              :             NULL),
     211           31 :           GNUNET_JSON_spec_int64 ("display_priority",
     212              :                                   &r->display_priority),
     213           31 :           GNUNET_JSON_spec_end ()
     214              :         };
     215              : 
     216           31 :         if (GNUNET_OK !=
     217           31 :             GNUNET_JSON_parse (jrule,
     218              :                                rspec,
     219              :                                NULL,
     220              :                                NULL))
     221              :         {
     222            0 :           GNUNET_break_op (0);
     223            0 :           return GNUNET_SYSERR;
     224              :         }
     225              : 
     226              :         {
     227           31 :           size_t mlen = json_array_size (jsmeasures);
     228           31 :           size_t mp_start = *mp_off;
     229              : 
     230           31 :           r->measures = &adgh->all_mp[mp_start];
     231           31 :           r->measures_length = mlen;
     232              : 
     233              :           {
     234              :             size_t midx;
     235              :             const json_t *jm;
     236              : 
     237           61 :             json_array_foreach (jsmeasures, midx, jm)
     238              :             {
     239           30 :               const char *sval = json_string_value (jm);
     240              : 
     241           30 :               if (NULL == sval)
     242              :               {
     243            0 :                 GNUNET_break_op (0);
     244            0 :                 return GNUNET_SYSERR;
     245              :               }
     246           30 :               adgh->all_mp[*mp_off] = sval;
     247           30 :               (*mp_off)++;
     248              :             }
     249              :           }
     250              :         }
     251              : 
     252           31 :         (*rule_off)++;
     253              :       }
     254              :     }
     255              :   }
     256              : 
     257            6 :   return GNUNET_OK;
     258              : }
     259              : 
     260              : 
     261              : /**
     262              :  * Parse AML decision records.
     263              :  *
     264              :  * @param[in,out] adgh handle (for allocations)
     265              :  * @param jrecords JSON array of decision records
     266              :  * @param records_ar_length length of @a records_ar
     267              :  * @param[out] records_ar caller-allocated array to fill
     268              :  * @return #GNUNET_OK on success
     269              :  */
     270              : static enum GNUNET_GenericReturnValue
     271            2 : parse_aml_decisions (
     272              :   struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh,
     273              :   const json_t *jrecords,
     274              :   size_t records_ar_length,
     275              :   struct TALER_EXCHANGE_GetAmlDecisionsDecision *records_ar)
     276              : {
     277            2 :   size_t rule_off = 0;
     278            2 :   size_t mp_off = 0;
     279              :   const json_t *obj;
     280              :   size_t idx;
     281              : 
     282            8 :   json_array_foreach ((json_t *) jrecords, idx, obj)
     283              :   {
     284            6 :     struct TALER_EXCHANGE_GetAmlDecisionsDecision *decision = &records_ar[idx];
     285              :     const json_t *jlimits;
     286              :     struct GNUNET_JSON_Specification spec[] = {
     287            6 :       GNUNET_JSON_spec_fixed_auto ("h_payto",
     288              :                                    &decision->h_payto),
     289            6 :       GNUNET_JSON_spec_mark_optional (
     290              :         GNUNET_JSON_spec_string ("full_payto",
     291              :                                  &decision->full_payto),
     292              :         NULL),
     293            6 :       GNUNET_JSON_spec_mark_optional (
     294              :         GNUNET_JSON_spec_bool ("is_wallet",
     295              :                                &decision->is_wallet),
     296              :         NULL),
     297            6 :       GNUNET_JSON_spec_uint64 ("rowid",
     298              :                                &decision->rowid),
     299            6 :       GNUNET_JSON_spec_mark_optional (
     300              :         GNUNET_JSON_spec_string ("justification",
     301              :                                  &decision->justification),
     302              :         NULL),
     303            6 :       GNUNET_JSON_spec_timestamp ("decision_time",
     304              :                                   &decision->decision_time),
     305            6 :       GNUNET_JSON_spec_mark_optional (
     306              :         GNUNET_JSON_spec_object_const ("properties",
     307              :                                        &decision->properties),
     308              :         NULL),
     309            6 :       GNUNET_JSON_spec_object_const ("limits",
     310              :                                      &jlimits),
     311            6 :       GNUNET_JSON_spec_bool ("to_investigate",
     312              :                              &decision->to_investigate),
     313            6 :       GNUNET_JSON_spec_bool ("is_active",
     314              :                              &decision->is_active),
     315            6 :       GNUNET_JSON_spec_end ()
     316              :     };
     317              : 
     318            6 :     GNUNET_assert (idx < records_ar_length);
     319            6 :     if (GNUNET_OK !=
     320            6 :         GNUNET_JSON_parse (obj,
     321              :                            spec,
     322              :                            NULL,
     323              :                            NULL))
     324              :     {
     325            0 :       GNUNET_break_op (0);
     326            0 :       return GNUNET_SYSERR;
     327              :     }
     328              : 
     329            6 :     if (GNUNET_OK !=
     330            6 :         parse_limits (adgh,
     331              :                       jlimits,
     332              :                       &decision->limits,
     333              :                       &rule_off,
     334              :                       &mp_off))
     335              :     {
     336            0 :       GNUNET_break_op (0);
     337            0 :       return GNUNET_SYSERR;
     338              :     }
     339              :   }
     340            2 :   return GNUNET_OK;
     341              : }
     342              : 
     343              : 
     344              : /**
     345              :  * Parse the provided decision data from the "200 OK" response.
     346              :  *
     347              :  * @param[in,out] adgh handle (callback may be zero'ed out)
     348              :  * @param json json reply with the data
     349              :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     350              :  */
     351              : static enum GNUNET_GenericReturnValue
     352            2 : parse_get_aml_decisions_ok (struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh,
     353              :                             const json_t *json)
     354              : {
     355            2 :   struct TALER_EXCHANGE_GetAmlDecisionsResponse lr = {
     356              :     .hr.reply = json,
     357              :     .hr.http_status = MHD_HTTP_OK
     358              :   };
     359              :   const json_t *jrecords;
     360              :   struct GNUNET_JSON_Specification spec[] = {
     361            2 :     GNUNET_JSON_spec_array_const ("records",
     362              :                                   &jrecords),
     363            2 :     GNUNET_JSON_spec_end ()
     364              :   };
     365              : 
     366            2 :   if (GNUNET_OK !=
     367            2 :       GNUNET_JSON_parse (json,
     368              :                          spec,
     369              :                          NULL,
     370              :                          NULL))
     371              :   {
     372            0 :     GNUNET_break_op (0);
     373            0 :     return GNUNET_SYSERR;
     374              :   }
     375              : 
     376            2 :   lr.details.ok.records_length = json_array_size (jrecords);
     377              : 
     378              :   /* First pass: count total rules and measures across all records */
     379              :   {
     380            2 :     size_t total_rules = 0;
     381            2 :     size_t total_measures = 0;
     382              :     const json_t *obj;
     383              :     size_t idx;
     384              : 
     385            8 :     json_array_foreach ((json_t *) jrecords, idx, obj)
     386              :     {
     387            6 :       const json_t *jlimits = json_object_get (obj, "limits");
     388              :       const json_t *jrules;
     389              : 
     390            6 :       if (NULL == jlimits)
     391            0 :         continue;
     392            6 :       jrules = json_object_get (jlimits, "rules");
     393            6 :       if (NULL == jrules)
     394            0 :         continue;
     395            6 :       total_rules += json_array_size (jrules);
     396              : 
     397              :       {
     398              :         const json_t *jrule;
     399              :         size_t ridx;
     400              : 
     401           37 :         json_array_foreach ((json_t *) jrules, ridx, jrule)
     402              :         {
     403           31 :           const json_t *jmeasures = json_object_get (jrule, "measures");
     404              : 
     405           31 :           if (NULL != jmeasures)
     406           31 :             total_measures += json_array_size (jmeasures);
     407              :         }
     408              :       }
     409              :     }
     410              : 
     411            2 :     adgh->all_rules = GNUNET_new_array (
     412              :       GNUNET_NZL (total_rules),
     413              :       struct TALER_EXCHANGE_GetAmlDecisionsKycRule);
     414            2 :     adgh->all_mp = GNUNET_new_array (
     415              :       GNUNET_NZL (total_measures),
     416              :       const char *);
     417              :   }
     418              : 
     419            2 :   {
     420            2 :     struct TALER_EXCHANGE_GetAmlDecisionsDecision records[
     421            2 :       GNUNET_NZL (lr.details.ok.records_length)];
     422              :     enum GNUNET_GenericReturnValue ret;
     423              : 
     424            2 :     memset (records,
     425              :             0,
     426              :             sizeof (records));
     427            2 :     lr.details.ok.records = records;
     428            2 :     ret = parse_aml_decisions (adgh,
     429              :                                jrecords,
     430              :                                lr.details.ok.records_length,
     431              :                                records);
     432            2 :     if (GNUNET_OK == ret)
     433              :     {
     434            2 :       adgh->cb (adgh->cb_cls,
     435              :                 &lr);
     436            2 :       adgh->cb = NULL;
     437              :     }
     438            2 :     GNUNET_free (adgh->all_rules);
     439            2 :     adgh->all_rules = NULL;
     440            2 :     GNUNET_free (adgh->all_mp);
     441            2 :     adgh->all_mp = NULL;
     442            2 :     return ret;
     443              :   }
     444              : }
     445              : 
     446              : 
     447              : /**
     448              :  * Function called when we're done processing the
     449              :  * HTTP /aml/$OFFICER_PUB/decisions request.
     450              :  *
     451              :  * @param cls the `struct TALER_EXCHANGE_GetAmlDecisionsHandle`
     452              :  * @param response_code HTTP response code, 0 on error
     453              :  * @param response parsed JSON result, NULL on error
     454              :  */
     455              : static void
     456            4 : handle_get_aml_decisions_finished (void *cls,
     457              :                                    long response_code,
     458              :                                    const void *response)
     459              : {
     460            4 :   struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh = cls;
     461            4 :   const json_t *j = response;
     462            4 :   struct TALER_EXCHANGE_GetAmlDecisionsResponse lr = {
     463              :     .hr.reply = j,
     464            4 :     .hr.http_status = (unsigned int) response_code
     465              :   };
     466              : 
     467            4 :   adgh->job = NULL;
     468            4 :   switch (response_code)
     469              :   {
     470            0 :   case 0:
     471            0 :     lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     472            0 :     break;
     473            2 :   case MHD_HTTP_OK:
     474            2 :     if (GNUNET_OK !=
     475            2 :         parse_get_aml_decisions_ok (adgh,
     476              :                                     j))
     477              :     {
     478            0 :       GNUNET_break_op (0);
     479            0 :       lr.hr.http_status = 0;
     480            0 :       lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     481            0 :       break;
     482              :     }
     483            2 :     GNUNET_assert (NULL == adgh->cb);
     484            2 :     TALER_EXCHANGE_get_aml_decisions_cancel (adgh);
     485            2 :     return;
     486            1 :   case MHD_HTTP_NO_CONTENT:
     487            1 :     break;
     488            0 :   case MHD_HTTP_BAD_REQUEST:
     489            0 :     json_dumpf (j,
     490              :                 stderr,
     491              :                 JSON_INDENT (2));
     492            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     493            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     494            0 :     break;
     495            1 :   case MHD_HTTP_FORBIDDEN:
     496            1 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     497            1 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     498            1 :     break;
     499            0 :   case MHD_HTTP_NOT_FOUND:
     500            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     501            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     502            0 :     break;
     503            0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     504            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     505            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     506            0 :     break;
     507            0 :   default:
     508              :     /* unexpected response code */
     509            0 :     GNUNET_break_op (0);
     510            0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     511            0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     512            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     513              :                 "Unexpected response code %u/%d for GET AML decisions\n",
     514              :                 (unsigned int) response_code,
     515              :                 (int) lr.hr.ec);
     516            0 :     break;
     517              :   }
     518            2 :   if (NULL != adgh->cb)
     519            2 :     adgh->cb (adgh->cb_cls,
     520              :               &lr);
     521            2 :   TALER_EXCHANGE_get_aml_decisions_cancel (adgh);
     522              : }
     523              : 
     524              : 
     525              : struct TALER_EXCHANGE_GetAmlDecisionsHandle *
     526            4 : TALER_EXCHANGE_get_aml_decisions_create (
     527              :   struct GNUNET_CURL_Context *ctx,
     528              :   const char *url,
     529              :   const struct TALER_AmlOfficerPrivateKeyP *officer_priv)
     530              : {
     531              :   struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh;
     532              : 
     533            4 :   adgh = GNUNET_new (struct TALER_EXCHANGE_GetAmlDecisionsHandle);
     534            4 :   adgh->ctx = ctx;
     535            4 :   adgh->base_url = GNUNET_strdup (url);
     536            4 :   adgh->officer_priv = *officer_priv;
     537            4 :   GNUNET_CRYPTO_eddsa_key_get_public (&officer_priv->eddsa_priv,
     538              :                                       &adgh->officer_pub.eddsa_pub);
     539            4 :   adgh->options.limit = -20;
     540            4 :   adgh->options.offset = INT64_MAX;
     541            4 :   adgh->options.active = TALER_EXCHANGE_YNA_ALL;
     542            4 :   adgh->options.investigation = TALER_EXCHANGE_YNA_ALL;
     543            4 :   return adgh;
     544              : }
     545              : 
     546              : 
     547              : enum GNUNET_GenericReturnValue
     548            7 : TALER_EXCHANGE_get_aml_decisions_set_options_ (
     549              :   struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh,
     550              :   unsigned int num_options,
     551              :   const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue options[])
     552              : {
     553           10 :   for (unsigned int i = 0; i < num_options; i++)
     554              :   {
     555           10 :     const struct TALER_EXCHANGE_GetAmlDecisionsOptionValue *opt = &options[i];
     556              : 
     557           10 :     switch (opt->option)
     558              :     {
     559            3 :     case TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_END:
     560            3 :       return GNUNET_OK;
     561            0 :     case TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_LIMIT:
     562            0 :       adgh->options.limit = opt->details.limit;
     563            0 :       break;
     564            4 :     case TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_OFFSET:
     565            4 :       if (opt->details.offset > INT64_MAX)
     566              :       {
     567            4 :         GNUNET_break (0);
     568            4 :         return GNUNET_NO;
     569              :       }
     570            0 :       adgh->options.offset = opt->details.offset;
     571            0 :       break;
     572            3 :     case TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_H_PAYTO:
     573            3 :       adgh->options.h_payto = opt->details.h_payto;
     574            3 :       break;
     575            0 :     case TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_ACTIVE:
     576            0 :       adgh->options.active = opt->details.active;
     577            0 :       break;
     578            0 :     case TALER_EXCHANGE_GET_AML_DECISIONS_OPTION_INVESTIGATION:
     579            0 :       adgh->options.investigation = opt->details.investigation;
     580            0 :       break;
     581            0 :     default:
     582            0 :       GNUNET_break (0);
     583            0 :       return GNUNET_SYSERR;
     584              :     }
     585              :   }
     586            0 :   return GNUNET_OK;
     587              : }
     588              : 
     589              : 
     590              : enum TALER_ErrorCode
     591            4 : TALER_EXCHANGE_get_aml_decisions_start (
     592              :   struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh,
     593              :   TALER_EXCHANGE_GetAmlDecisionsCallback cb,
     594              :   TALER_EXCHANGE_GET_AML_DECISIONS_RESULT_CLOSURE *cb_cls)
     595              : {
     596              :   CURL *eh;
     597              :   char arg_str[sizeof (struct TALER_AmlOfficerPublicKeyP) * 2 + 32];
     598            4 :   struct curl_slist *job_headers = NULL;
     599              : 
     600            4 :   adgh->cb = cb;
     601            4 :   adgh->cb_cls = cb_cls;
     602              : 
     603              :   /* Build AML officer signature */
     604            4 :   TALER_officer_aml_query_sign (&adgh->officer_priv,
     605              :                                 &adgh->officer_sig);
     606              : 
     607              :   /* Build the path component: aml/{officer_pub}/decisions */
     608              :   {
     609              :     char pub_str[sizeof (adgh->officer_pub) * 2];
     610              :     char *end;
     611              : 
     612            4 :     end = GNUNET_STRINGS_data_to_string (
     613            4 :       &adgh->officer_pub,
     614              :       sizeof (adgh->officer_pub),
     615              :       pub_str,
     616              :       sizeof (pub_str));
     617            4 :     *end = '\0';
     618            4 :     GNUNET_snprintf (arg_str,
     619              :                      sizeof (arg_str),
     620              :                      "aml/%s/decisions",
     621              :                      pub_str);
     622              :   }
     623              : 
     624              :   /* Build URL with optional query parameters */
     625              :   {
     626              :     char limit_s[24];
     627              :     char offset_s[24];
     628              :     char payto_s[sizeof (*adgh->options.h_payto) * 2 + 1];
     629            4 :     int64_t limit = adgh->options.limit;
     630            4 :     uint64_t offset = adgh->options.offset;
     631            4 :     bool omit_limit = (-20 == limit);
     632            4 :     bool omit_offset = ( ( (limit < 0) && ((uint64_t) INT64_MAX == offset) ) ||
     633            0 :                          ( (limit > 0) && (0 == offset) ) );
     634              : 
     635            4 :     GNUNET_snprintf (limit_s,
     636              :                      sizeof (limit_s),
     637              :                      "%lld",
     638              :                      (long long) limit);
     639            4 :     GNUNET_snprintf (offset_s,
     640              :                      sizeof (offset_s),
     641              :                      "%llu",
     642              :                      (unsigned long long) offset);
     643              : 
     644            4 :     if (NULL != adgh->options.h_payto)
     645              :     {
     646              :       char *end;
     647              : 
     648            3 :       end = GNUNET_STRINGS_data_to_string (
     649            3 :         adgh->options.h_payto,
     650              :         sizeof (*adgh->options.h_payto),
     651              :         payto_s,
     652              :         sizeof (payto_s) - 1);
     653            3 :       *end = '\0';
     654              :     }
     655              : 
     656           12 :     adgh->url = TALER_url_join (
     657            4 :       adgh->base_url,
     658              :       arg_str,
     659              :       "limit",
     660              :       omit_limit ? NULL : limit_s,
     661              :       "offset",
     662              :       omit_offset ? NULL : offset_s,
     663              :       "h_payto",
     664            4 :       (NULL != adgh->options.h_payto) ? payto_s : NULL,
     665              :       "active",
     666            4 :       (TALER_EXCHANGE_YNA_ALL != adgh->options.active)
     667            0 :       ? TALER_yna_to_string (adgh->options.active)
     668              :       : NULL,
     669              :       "investigation",
     670            4 :       (TALER_EXCHANGE_YNA_ALL != adgh->options.investigation)
     671            0 :       ? TALER_yna_to_string (adgh->options.investigation)
     672              :       : NULL,
     673              :       NULL);
     674              :   }
     675              : 
     676            4 :   if (NULL == adgh->url)
     677            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     678              : 
     679            4 :   eh = TALER_EXCHANGE_curl_easy_get_ (adgh->url);
     680            4 :   if (NULL == eh)
     681              :   {
     682            0 :     GNUNET_break (0);
     683            0 :     GNUNET_free (adgh->url);
     684            0 :     adgh->url = NULL;
     685            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     686              :   }
     687              : 
     688              :   /* Build job headers with AML officer signature */
     689              :   {
     690              :     char *hdr;
     691              :     char sig_str[sizeof (adgh->officer_sig) * 2];
     692              :     char *end;
     693              : 
     694            4 :     end = GNUNET_STRINGS_data_to_string (
     695            4 :       &adgh->officer_sig,
     696              :       sizeof (adgh->officer_sig),
     697              :       sig_str,
     698              :       sizeof (sig_str));
     699            4 :     *end = '\0';
     700              : 
     701            4 :     GNUNET_asprintf (&hdr,
     702              :                      "%s: %s",
     703              :                      TALER_AML_OFFICER_SIGNATURE_HEADER,
     704              :                      sig_str);
     705            4 :     job_headers = curl_slist_append (NULL,
     706              :                                      hdr);
     707            4 :     GNUNET_free (hdr);
     708              :   }
     709              : 
     710            4 :   adgh->job = GNUNET_CURL_job_add2 (adgh->ctx,
     711              :                                     eh,
     712              :                                     job_headers,
     713              :                                     &handle_get_aml_decisions_finished,
     714              :                                     adgh);
     715            4 :   curl_slist_free_all (job_headers);
     716              : 
     717            4 :   if (NULL == adgh->job)
     718              :   {
     719            0 :     GNUNET_free (adgh->url);
     720            0 :     adgh->url = NULL;
     721            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     722              :   }
     723            4 :   return TALER_EC_NONE;
     724              : }
     725              : 
     726              : 
     727              : void
     728            4 : TALER_EXCHANGE_get_aml_decisions_cancel (
     729              :   struct TALER_EXCHANGE_GetAmlDecisionsHandle *adgh)
     730              : {
     731            4 :   if (NULL != adgh->job)
     732              :   {
     733            0 :     GNUNET_CURL_job_cancel (adgh->job);
     734            0 :     adgh->job = NULL;
     735              :   }
     736            4 :   GNUNET_free (adgh->all_rules);
     737            4 :   GNUNET_free (adgh->all_mp);
     738            4 :   GNUNET_free (adgh->url);
     739            4 :   GNUNET_free (adgh->base_url);
     740            4 :   GNUNET_free (adgh);
     741            4 : }
     742              : 
     743              : 
     744              : /* end of exchange_api_get-aml-OFFICER_PUB-decisions.c */
        

Generated by: LCOV version 2.0-1