LCOV - code coverage report
Current view: top level - lib - exchange_api_get_aml_measures.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 220 0.0 %
Date: 2025-06-05 21:03:14 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2023, 2024 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_measures.c
      19             :  * @brief Implementation of the GET /aml/$OFFICER_PUB/measures request
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "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_exchange_service.h"
      27             : #include "taler_json_lib.h"
      28             : #include "exchange_api_handle.h"
      29             : #include "taler_signatures.h"
      30             : #include "exchange_api_curl_defaults.h"
      31             : 
      32             : 
      33             : /**
      34             :  * Scrap buffer of temporary arrays.
      35             :  */
      36             : struct Scrap
      37             : {
      38             :   /**
      39             :    * Kept in DLL.
      40             :    */
      41             :   struct Scrap *next;
      42             : 
      43             :   /**
      44             :    * Kept in DLL.
      45             :    */
      46             :   struct Scrap *prev;
      47             : 
      48             :   /**
      49             :    * Pointer to our allocation.
      50             :    */
      51             :   const char **ptr;
      52             : };
      53             : 
      54             : 
      55             : /**
      56             :  * @brief A GET /aml/$OFFICER_PUB/measures Handle
      57             :  */
      58             : struct TALER_EXCHANGE_AmlGetMeasuresHandle
      59             : {
      60             : 
      61             :   /**
      62             :    * The url for this request.
      63             :    */
      64             :   char *url;
      65             : 
      66             :   /**
      67             :    * Handle for the request.
      68             :    */
      69             :   struct GNUNET_CURL_Job *job;
      70             : 
      71             :   /**
      72             :    * Function to call with the result.
      73             :    */
      74             :   TALER_EXCHANGE_AmlMeasuresCallback measures_cb;
      75             : 
      76             :   /**
      77             :    * Closure for @e measures_cb.
      78             :    */
      79             :   void *measures_cb_cls;
      80             : 
      81             :   /**
      82             :    * HTTP headers for the job.
      83             :    */
      84             :   struct curl_slist *job_headers;
      85             : 
      86             :   /**
      87             :    * Head of scrap list.
      88             :    */
      89             :   struct Scrap *scrap_head;
      90             : 
      91             :   /**
      92             :    * Tail of scrap list.
      93             :    */
      94             :   struct Scrap *scrap_tail;
      95             : };
      96             : 
      97             : 
      98             : /**
      99             :  * Parse AML measures.
     100             :  *
     101             :  * @param jroots JSON object with measure data
     102             :  * @param[out] roots where to write the result
     103             :  * @return #GNUNET_OK on success
     104             :  */
     105             : static enum GNUNET_GenericReturnValue
     106           0 : parse_aml_roots (
     107             :   const json_t *jroots,
     108             :   struct TALER_EXCHANGE_AvailableAmlMeasures *roots)
     109             : {
     110             :   const json_t *obj;
     111             :   const char *name;
     112           0 :   size_t idx = 0;
     113             : 
     114           0 :   json_object_foreach ((json_t *) jroots, name, obj)
     115             :   {
     116           0 :     struct TALER_EXCHANGE_AvailableAmlMeasures *root
     117           0 :       = &roots[idx++];
     118             :     struct GNUNET_JSON_Specification spec[] = {
     119           0 :       GNUNET_JSON_spec_string ("check_name",
     120             :                                &root->check_name),
     121           0 :       GNUNET_JSON_spec_string ("prog_name",
     122             :                                &root->prog_name),
     123           0 :       GNUNET_JSON_spec_mark_optional (
     124             :         GNUNET_JSON_spec_object_const ("context",
     125             :                                        &root->context),
     126             :         NULL),
     127           0 :       GNUNET_JSON_spec_end ()
     128             :     };
     129             : 
     130           0 :     if (GNUNET_OK !=
     131           0 :         GNUNET_JSON_parse (obj,
     132             :                            spec,
     133             :                            NULL,
     134             :                            NULL))
     135             :     {
     136           0 :       GNUNET_break_op (0);
     137           0 :       return GNUNET_SYSERR;
     138             :     }
     139           0 :     root->measure_name = name;
     140             :   }
     141           0 :   return GNUNET_OK;
     142             : }
     143             : 
     144             : 
     145             : /**
     146             :  * Create array of length @a len in scrap book.
     147             :  *
     148             :  * @param[in,out] lh context for allocations
     149             :  * @param len length of array
     150             :  * @return scrap array
     151             :  */
     152             : static const char **
     153           0 : make_scrap (
     154             :   struct TALER_EXCHANGE_AmlGetMeasuresHandle *lh,
     155             :   unsigned int len)
     156             : {
     157           0 :   struct Scrap *s = GNUNET_new (struct Scrap);
     158             : 
     159           0 :   s->ptr = GNUNET_new_array (len,
     160             :                              const char *);
     161           0 :   GNUNET_CONTAINER_DLL_insert (lh->scrap_head,
     162             :                                lh->scrap_tail,
     163             :                                s);
     164           0 :   return s->ptr;
     165             : }
     166             : 
     167             : 
     168             : /**
     169             :  * Free all scrap space.
     170             :  *
     171             :  * @param[in,out] lh scrap context
     172             :  */
     173             : static void
     174           0 : free_scrap (struct TALER_EXCHANGE_AmlGetMeasuresHandle *lh)
     175             : {
     176             :   struct Scrap *s;
     177             : 
     178           0 :   while (NULL != (s = lh->scrap_head))
     179             :   {
     180           0 :     GNUNET_CONTAINER_DLL_remove (lh->scrap_head,
     181             :                                  lh->scrap_tail,
     182             :                                  s);
     183           0 :     GNUNET_free (s->ptr);
     184           0 :     GNUNET_free (s);
     185             :   }
     186           0 : }
     187             : 
     188             : 
     189             : /**
     190             :  * Convert JSON array of strings to string array.
     191             :  *
     192             :  * @param j JSON array to convert
     193             :  * @param[out] a array to initialize
     194             :  * @return true on success
     195             :  */
     196             : static bool
     197           0 : j_to_a (const json_t *j,
     198             :         const char **a)
     199             : {
     200             :   const json_t *e;
     201             :   size_t idx;
     202             : 
     203           0 :   json_array_foreach ((json_t *) j, idx, e)
     204             :   {
     205           0 :     if (NULL == (a[idx] = json_string_value (e)))
     206           0 :       return false;
     207             :   }
     208           0 :   return true;
     209             : }
     210             : 
     211             : 
     212             : /**
     213             :  * Parse AML programs.
     214             :  *
     215             :  * @param[in,out] lh context for allocations
     216             :  * @param jprogs JSON object with program data
     217             :  * @param[out] progs where to write the result
     218             :  * @return #GNUNET_OK on success
     219             :  */
     220             : static enum GNUNET_GenericReturnValue
     221           0 : parse_aml_programs (
     222             :   struct TALER_EXCHANGE_AmlGetMeasuresHandle *lh,
     223             :   const json_t *jprogs,
     224             :   struct TALER_EXCHANGE_AvailableAmlPrograms *progs)
     225             : {
     226             :   const json_t *obj;
     227             :   const char *name;
     228           0 :   size_t idx = 0;
     229             : 
     230           0 :   json_object_foreach ((json_t *) jprogs, name, obj)
     231             :   {
     232           0 :     struct TALER_EXCHANGE_AvailableAmlPrograms *prog
     233           0 :       = &progs[idx++];
     234             :     const json_t *jcontext;
     235             :     const json_t *jinputs;
     236             :     struct GNUNET_JSON_Specification spec[] = {
     237           0 :       GNUNET_JSON_spec_string ("description",
     238             :                                &prog->description),
     239           0 :       GNUNET_JSON_spec_array_const ("context",
     240             :                                     &jcontext),
     241           0 :       GNUNET_JSON_spec_array_const ("inputs",
     242             :                                     &jinputs),
     243           0 :       GNUNET_JSON_spec_end ()
     244             :     };
     245             :     unsigned int len;
     246             :     const char **ptr;
     247             : 
     248           0 :     if (GNUNET_OK !=
     249           0 :         GNUNET_JSON_parse (obj,
     250             :                            spec,
     251             :                            NULL,
     252             :                            NULL))
     253             :     {
     254           0 :       GNUNET_break_op (0);
     255           0 :       return GNUNET_SYSERR;
     256             :     }
     257           0 :     prog->prog_name = name;
     258             :     prog->contexts_length
     259           0 :       = (unsigned int) json_array_size (jcontext);
     260             :     prog->inputs_length
     261           0 :       = (unsigned int) json_array_size (jinputs);
     262           0 :     len = prog->contexts_length + prog->inputs_length;
     263           0 :     if ( ((unsigned long long) len) !=
     264           0 :          (unsigned long long) json_array_size (jcontext)
     265           0 :          + (unsigned long long) json_array_size (jinputs) )
     266             :     {
     267           0 :       GNUNET_break_op (0);
     268           0 :       return GNUNET_SYSERR;
     269             :     }
     270           0 :     ptr = make_scrap (lh,
     271             :                       len);
     272           0 :     prog->contexts = ptr;
     273           0 :     if (! j_to_a (jcontext,
     274             :                   prog->contexts))
     275             :     {
     276           0 :       GNUNET_break_op (0);
     277           0 :       return GNUNET_SYSERR;
     278             :     }
     279           0 :     prog->inputs = &ptr[prog->contexts_length];
     280           0 :     if (! j_to_a (jinputs,
     281             :                   prog->inputs))
     282             :     {
     283           0 :       GNUNET_break_op (0);
     284           0 :       return GNUNET_SYSERR;
     285             :     }
     286             :   }
     287           0 :   return GNUNET_OK;
     288             : }
     289             : 
     290             : 
     291             : /**
     292             :  * Parse AML measures.
     293             :  *
     294             :  * @param[in,out] lh context for allocations
     295             :  * @param jchecks JSON object with measure data
     296             :  * @param[out] checks where to write the result
     297             :  * @return #GNUNET_OK on success
     298             :  */
     299             : static enum GNUNET_GenericReturnValue
     300           0 : parse_aml_checks (
     301             :   struct TALER_EXCHANGE_AmlGetMeasuresHandle *lh,
     302             :   const json_t *jchecks,
     303             :   struct TALER_EXCHANGE_AvailableKycChecks *checks)
     304             : {
     305             :   const json_t *obj;
     306             :   const char *name;
     307           0 :   size_t idx = 0;
     308             : 
     309           0 :   json_object_foreach ((json_t *) jchecks, name, obj)
     310             :   {
     311           0 :     struct TALER_EXCHANGE_AvailableKycChecks *check
     312           0 :       = &checks[idx++];
     313             :     const json_t *jrequires;
     314             :     const json_t *joutputs;
     315             :     struct GNUNET_JSON_Specification spec[] = {
     316           0 :       GNUNET_JSON_spec_string ("description",
     317             :                                &check->description),
     318           0 :       GNUNET_JSON_spec_mark_optional (
     319             :         GNUNET_JSON_spec_object_const ("description_i18n",
     320             :                                        &check->description_i18n),
     321             :         NULL),
     322           0 :       GNUNET_JSON_spec_array_const ("requires",
     323             :                                     &jrequires),
     324           0 :       GNUNET_JSON_spec_array_const ("outputs",
     325             :                                     &joutputs),
     326           0 :       GNUNET_JSON_spec_string ("fallback",
     327             :                                &check->fallback),
     328           0 :       GNUNET_JSON_spec_end ()
     329             :     };
     330             :     unsigned int len;
     331             :     const char **ptr;
     332             : 
     333           0 :     if (GNUNET_OK !=
     334           0 :         GNUNET_JSON_parse (obj,
     335             :                            spec,
     336             :                            NULL,
     337             :                            NULL))
     338             :     {
     339           0 :       GNUNET_break_op (0);
     340           0 :       return GNUNET_SYSERR;
     341             :     }
     342           0 :     check->check_name = name;
     343             : 
     344             :     check->requires_length
     345           0 :       = (unsigned int) json_array_size (jrequires);
     346             :     check->outputs_length
     347           0 :       = (unsigned int) json_array_size (joutputs);
     348           0 :     len = check->requires_length + check->outputs_length;
     349           0 :     if ( ((unsigned long long) len) !=
     350           0 :          (unsigned long long) json_array_size (jrequires)
     351           0 :          + (unsigned long long) json_array_size (joutputs) )
     352             :     {
     353           0 :       GNUNET_break_op (0);
     354           0 :       return GNUNET_SYSERR;
     355             :     }
     356           0 :     ptr = make_scrap (lh,
     357             :                       len);
     358           0 :     check->requires = ptr;
     359           0 :     if (! j_to_a (jrequires,
     360             :                   check->requires))
     361             :     {
     362           0 :       GNUNET_break_op (0);
     363           0 :       return GNUNET_SYSERR;
     364             :     }
     365           0 :     check->outputs = &ptr[check->requires_length];
     366           0 :     if (! j_to_a (joutputs,
     367             :                   check->outputs))
     368             :     {
     369           0 :       GNUNET_break_op (0);
     370           0 :       return GNUNET_SYSERR;
     371             :     }
     372             :   }
     373           0 :   return GNUNET_OK;
     374             : }
     375             : 
     376             : 
     377             : /**
     378             :  * Parse the provided decision data from the "200 OK" response.
     379             :  *
     380             :  * @param[in,out] lh handle (callback may be zero'ed out)
     381             :  * @param json json reply with the data for one coin
     382             :  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
     383             :  */
     384             : static enum GNUNET_GenericReturnValue
     385           0 : parse_measures_ok (struct TALER_EXCHANGE_AmlGetMeasuresHandle *lh,
     386             :                    const json_t *json)
     387             : {
     388           0 :   struct TALER_EXCHANGE_AmlGetMeasuresResponse lr = {
     389             :     .hr.reply = json,
     390             :     .hr.http_status = MHD_HTTP_OK
     391             :   };
     392             :   const json_t *jroots;
     393             :   const json_t *jprograms;
     394             :   const json_t *jchecks;
     395             :   struct GNUNET_JSON_Specification spec[] = {
     396           0 :     GNUNET_JSON_spec_object_const ("roots",
     397             :                                    &jroots),
     398           0 :     GNUNET_JSON_spec_object_const ("programs",
     399             :                                    &jprograms),
     400           0 :     GNUNET_JSON_spec_object_const ("checks",
     401             :                                    &jchecks),
     402           0 :     GNUNET_JSON_spec_end ()
     403             :   };
     404             : 
     405           0 :   if (GNUNET_OK !=
     406           0 :       GNUNET_JSON_parse (json,
     407             :                          spec,
     408             :                          NULL,
     409             :                          NULL))
     410             :   {
     411           0 :     GNUNET_break_op (0);
     412           0 :     return GNUNET_SYSERR;
     413             :   }
     414             :   lr.details.ok.roots_length
     415           0 :     = (unsigned int) json_object_size (jroots);
     416             :   lr.details.ok.programs_length
     417           0 :     = (unsigned int) json_object_size (jprograms);
     418             :   lr.details.ok.checks_length
     419           0 :     = (unsigned int) json_object_size (jchecks);
     420           0 :   if ( ( ((size_t) lr.details.ok.roots_length)
     421           0 :          != json_object_size (jroots)) ||
     422           0 :        ( ((size_t) lr.details.ok.programs_length)
     423           0 :          != json_object_size (jprograms)) ||
     424           0 :        ( ((size_t) lr.details.ok.checks_length)
     425           0 :          != json_object_size (jchecks)) )
     426             :   {
     427           0 :     GNUNET_break_op (0);
     428           0 :     return GNUNET_SYSERR;
     429             :   }
     430             : 
     431           0 :   {
     432           0 :     struct TALER_EXCHANGE_AvailableAmlMeasures roots[
     433           0 :       GNUNET_NZL (lr.details.ok.roots_length)];
     434           0 :     struct TALER_EXCHANGE_AvailableAmlPrograms progs[
     435           0 :       GNUNET_NZL (lr.details.ok.programs_length)];
     436           0 :     struct TALER_EXCHANGE_AvailableKycChecks checks[
     437           0 :       GNUNET_NZL (lr.details.ok.checks_length)];
     438             :     enum GNUNET_GenericReturnValue ret;
     439             : 
     440           0 :     memset (roots,
     441             :             0,
     442             :             sizeof (roots));
     443           0 :     memset (progs,
     444             :             0,
     445             :             sizeof (progs));
     446           0 :     memset (checks,
     447             :             0,
     448             :             sizeof (checks));
     449           0 :     lr.details.ok.roots = roots;
     450           0 :     lr.details.ok.programs = progs;
     451           0 :     lr.details.ok.checks = checks;
     452           0 :     ret = parse_aml_roots (jroots,
     453             :                            roots);
     454           0 :     if (GNUNET_OK == ret)
     455           0 :       ret = parse_aml_programs (lh,
     456             :                                 jprograms,
     457             :                                 progs);
     458           0 :     if (GNUNET_OK == ret)
     459           0 :       ret = parse_aml_checks (lh,
     460             :                               jchecks,
     461             :                               checks);
     462           0 :     if (GNUNET_OK == ret)
     463             :     {
     464           0 :       lh->measures_cb (lh->measures_cb_cls,
     465             :                        &lr);
     466           0 :       lh->measures_cb = NULL;
     467             :     }
     468           0 :     free_scrap (lh);
     469           0 :     return ret;
     470             :   }
     471             : }
     472             : 
     473             : 
     474             : /**
     475             :  * Function called when we're done processing the
     476             :  * HTTP /aml/$OFFICER_PUB/measures request.
     477             :  *
     478             :  * @param cls the `struct TALER_EXCHANGE_AmlGetMeasuresHandle`
     479             :  * @param response_code HTTP response code, 0 on error
     480             :  * @param response parsed JSON result, NULL on error
     481             :  */
     482             : static void
     483           0 : handle_lookup_finished (void *cls,
     484             :                         long response_code,
     485             :                         const void *response)
     486             : {
     487           0 :   struct TALER_EXCHANGE_AmlGetMeasuresHandle *lh = cls;
     488           0 :   const json_t *j = response;
     489           0 :   struct TALER_EXCHANGE_AmlGetMeasuresResponse lr = {
     490             :     .hr.reply = j,
     491           0 :     .hr.http_status = (unsigned int) response_code
     492             :   };
     493             : 
     494           0 :   lh->job = NULL;
     495           0 :   switch (response_code)
     496             :   {
     497           0 :   case 0:
     498           0 :     lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     499           0 :     break;
     500           0 :   case MHD_HTTP_OK:
     501           0 :     if (GNUNET_OK !=
     502           0 :         parse_measures_ok (lh,
     503             :                            j))
     504             :     {
     505           0 :       GNUNET_break_op (0);
     506           0 :       lr.hr.http_status = 0;
     507           0 :       lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     508           0 :       break;
     509             :     }
     510           0 :     GNUNET_assert (NULL == lh->measures_cb);
     511           0 :     TALER_EXCHANGE_aml_get_measures_cancel (lh);
     512           0 :     return;
     513           0 :   case MHD_HTTP_NO_CONTENT:
     514           0 :     break;
     515           0 :   case MHD_HTTP_BAD_REQUEST:
     516           0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     517           0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     518             :     /* This should never happen, either us or the exchange is buggy
     519             :        (or API version conflict); just pass JSON reply to the application */
     520           0 :     break;
     521           0 :   case MHD_HTTP_FORBIDDEN:
     522           0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     523           0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     524             :     /* Nothing really to verify, exchange says this coin was not melted; we
     525             :        should pass the JSON reply to the application */
     526           0 :     break;
     527           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     528           0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     529           0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     530             :     /* Server had an internal issue; we should retry, but this API
     531             :        leaves this to the application */
     532           0 :     break;
     533           0 :   default:
     534             :     /* unexpected response code */
     535           0 :     GNUNET_break_op (0);
     536           0 :     lr.hr.ec = TALER_JSON_get_error_code (j);
     537           0 :     lr.hr.hint = TALER_JSON_get_error_hint (j);
     538           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     539             :                 "Unexpected response code %u/%d for get AML measures\n",
     540             :                 (unsigned int) response_code,
     541             :                 (int) lr.hr.ec);
     542           0 :     break;
     543             :   }
     544           0 :   if (NULL != lh->measures_cb)
     545           0 :     lh->measures_cb (lh->measures_cb_cls,
     546             :                      &lr);
     547           0 :   TALER_EXCHANGE_aml_get_measures_cancel (lh);
     548             : }
     549             : 
     550             : 
     551             : struct TALER_EXCHANGE_AmlGetMeasuresHandle *
     552           0 : TALER_EXCHANGE_aml_get_measures (
     553             :   struct GNUNET_CURL_Context *ctx,
     554             :   const char *exchange_url,
     555             :   const struct TALER_AmlOfficerPrivateKeyP *officer_priv,
     556             :   TALER_EXCHANGE_AmlMeasuresCallback cb,
     557             :   void *cb_cls)
     558             : {
     559             :   struct TALER_EXCHANGE_AmlGetMeasuresHandle *lh;
     560             :   CURL *eh;
     561             :   struct TALER_AmlOfficerPublicKeyP officer_pub;
     562             :   struct TALER_AmlOfficerSignatureP officer_sig;
     563             :   char arg_str[sizeof (struct TALER_AmlOfficerPublicKeyP) * 2
     564             :                + 32];
     565             : 
     566           0 :   GNUNET_CRYPTO_eddsa_key_get_public (&officer_priv->eddsa_priv,
     567             :                                       &officer_pub.eddsa_pub);
     568           0 :   TALER_officer_aml_query_sign (officer_priv,
     569             :                                 &officer_sig);
     570             :   {
     571             :     char pub_str[sizeof (officer_pub) * 2];
     572             :     char *end;
     573             : 
     574           0 :     end = GNUNET_STRINGS_data_to_string (
     575             :       &officer_pub,
     576             :       sizeof (officer_pub),
     577             :       pub_str,
     578             :       sizeof (pub_str));
     579           0 :     *end = '\0';
     580           0 :     GNUNET_snprintf (arg_str,
     581             :                      sizeof (arg_str),
     582             :                      "aml/%s/measures",
     583             :                      pub_str);
     584             :   }
     585           0 :   lh = GNUNET_new (struct TALER_EXCHANGE_AmlGetMeasuresHandle);
     586           0 :   lh->measures_cb = cb;
     587           0 :   lh->measures_cb_cls = cb_cls;
     588           0 :   lh->url = TALER_url_join (exchange_url,
     589             :                             arg_str,
     590             :                             NULL);
     591           0 :   if (NULL == lh->url)
     592             :   {
     593           0 :     GNUNET_free (lh);
     594           0 :     return NULL;
     595             :   }
     596           0 :   eh = TALER_EXCHANGE_curl_easy_get_ (lh->url);
     597           0 :   if (NULL == eh)
     598             :   {
     599           0 :     GNUNET_break (0);
     600           0 :     GNUNET_free (lh->url);
     601           0 :     GNUNET_free (lh);
     602           0 :     return NULL;
     603             :   }
     604             :   {
     605             :     char *hdr;
     606             :     char sig_str[sizeof (officer_sig) * 2];
     607             :     char *end;
     608             : 
     609           0 :     end = GNUNET_STRINGS_data_to_string (
     610             :       &officer_sig,
     611             :       sizeof (officer_sig),
     612             :       sig_str,
     613             :       sizeof (sig_str));
     614           0 :     *end = '\0';
     615             : 
     616           0 :     GNUNET_asprintf (&hdr,
     617             :                      "%s: %s",
     618             :                      TALER_AML_OFFICER_SIGNATURE_HEADER,
     619             :                      sig_str);
     620           0 :     lh->job_headers = curl_slist_append (NULL,
     621             :                                          hdr);
     622           0 :     GNUNET_free (hdr);
     623           0 :     lh->job_headers = curl_slist_append (lh->job_headers,
     624             :                                          "Content-type: application/json");
     625           0 :     lh->job = GNUNET_CURL_job_add2 (ctx,
     626             :                                     eh,
     627           0 :                                     lh->job_headers,
     628             :                                     &handle_lookup_finished,
     629             :                                     lh);
     630             :   }
     631           0 :   return lh;
     632             : }
     633             : 
     634             : 
     635             : void
     636           0 : TALER_EXCHANGE_aml_get_measures_cancel (
     637             :   struct TALER_EXCHANGE_AmlGetMeasuresHandle *lh)
     638             : {
     639           0 :   if (NULL != lh->job)
     640             :   {
     641           0 :     GNUNET_CURL_job_cancel (lh->job);
     642           0 :     lh->job = NULL;
     643             :   }
     644           0 :   curl_slist_free_all (lh->job_headers);
     645           0 :   GNUNET_free (lh->url);
     646           0 :   GNUNET_free (lh);
     647           0 : }
     648             : 
     649             : 
     650             : /* end of exchange_api_get_aml_measures.c */

Generated by: LCOV version 1.16