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

Generated by: LCOV version 2.0-1