exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

json_helper.c (63842B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 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 <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file json/json_helper.c
     18  * @brief helper functions to generate specifications to parse
     19  *        Taler-specific JSON objects with libgnunetjson
     20  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
     21  * @author Christian Grothoff
     22  */
     23 #include <gnunet/gnunet_util_lib.h>
     24 #include "taler/taler_util.h"
     25 #include "taler/taler_json_lib.h"
     26 
     27 
     28 /**
     29  * Convert string value to numeric cipher value.
     30  *
     31  * @param cipher_s input string
     32  * @return numeric cipher value
     33  */
     34 static enum GNUNET_CRYPTO_BlindSignatureAlgorithm
     35 string_to_cipher (const char *cipher_s)
     36 {
     37   if ((0 == strcasecmp (cipher_s,
     38                         "RSA")) ||
     39       (0 == strcasecmp (cipher_s,
     40                         "RSA+age_restricted")))
     41     return GNUNET_CRYPTO_BSA_RSA;
     42   if ((0 == strcasecmp (cipher_s,
     43                         "CS")) ||
     44       (0 == strcasecmp (cipher_s,
     45                         "CS+age_restricted")))
     46     return GNUNET_CRYPTO_BSA_CS;
     47   return GNUNET_CRYPTO_BSA_INVALID;
     48 }
     49 
     50 
     51 json_t *
     52 TALER_JSON_from_amount (const struct TALER_Amount *amount)
     53 {
     54   char *amount_str = TALER_amount_to_string (amount);
     55 
     56   GNUNET_assert (NULL != amount_str);
     57   {
     58     json_t *j = json_string (amount_str);
     59 
     60     GNUNET_free (amount_str);
     61     return j;
     62   }
     63 }
     64 
     65 
     66 /**
     67  * Parse given JSON object to Amount
     68  *
     69  * @param cls closure, expected currency, or NULL
     70  * @param root the json object representing data
     71  * @param[out] spec where to write the data
     72  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     73  */
     74 static enum GNUNET_GenericReturnValue
     75 parse_amount (void *cls,
     76               json_t *root,
     77               struct GNUNET_JSON_Specification *spec)
     78 {
     79   const char *currency = cls;
     80   struct TALER_Amount *r_amount = spec->ptr;
     81 
     82   (void) cls;
     83   if (! json_is_string (root))
     84   {
     85     GNUNET_break_op (0);
     86     return GNUNET_SYSERR;
     87   }
     88   if (GNUNET_OK !=
     89       TALER_string_to_amount (json_string_value (root),
     90                               r_amount))
     91   {
     92     GNUNET_break_op (0);
     93     return GNUNET_SYSERR;
     94   }
     95   if ( (NULL != currency) &&
     96        (0 !=
     97         strcasecmp (currency,
     98                     r_amount->currency)) )
     99   {
    100     GNUNET_break_op (0);
    101     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    102                 "Expected currency `%s', but amount used currency `%s' in field `%s'\n",
    103                 currency,
    104                 r_amount->currency,
    105                 spec->field);
    106     return GNUNET_SYSERR;
    107   }
    108   return GNUNET_OK;
    109 }
    110 
    111 
    112 struct GNUNET_JSON_Specification
    113 TALER_JSON_spec_amount (const char *name,
    114                         const char *currency,
    115                         struct TALER_Amount *r_amount)
    116 {
    117   struct GNUNET_JSON_Specification ret = {
    118     .parser = &parse_amount,
    119     .cleaner = NULL,
    120     .cls = (void *) currency,
    121     .field = name,
    122     .ptr = r_amount,
    123     .ptr_size = 0,
    124     .size_ptr = NULL
    125   };
    126 
    127   GNUNET_assert (NULL != currency);
    128   return ret;
    129 }
    130 
    131 
    132 struct GNUNET_JSON_Specification
    133 TALER_JSON_spec_amount_any (const char *name,
    134                             struct TALER_Amount *r_amount)
    135 {
    136   struct GNUNET_JSON_Specification ret = {
    137     .parser = &parse_amount,
    138     .cleaner = NULL,
    139     .cls = NULL,
    140     .field = name,
    141     .ptr = r_amount,
    142     .ptr_size = 0,
    143     .size_ptr = NULL
    144   };
    145 
    146   return ret;
    147 }
    148 
    149 
    150 /**
    151  * Closure for parsing amount arrays.
    152  */
    153 struct AmountArrayCtx
    154 {
    155   /**
    156    * Pointer where to store the resulting array length.
    157    */
    158   size_t *len;
    159 };
    160 
    161 
    162 /**
    163  * Parse a JSON array of arbitrary amounts.
    164  */
    165 static enum GNUNET_GenericReturnValue
    166 parse_amount_any_array (void *cls,
    167                         json_t *root,
    168                         struct GNUNET_JSON_Specification *spec)
    169 {
    170   struct AmountArrayCtx *ctx = cls;
    171   struct TALER_Amount **out = spec->ptr;
    172 
    173   *out = NULL;
    174   if (NULL != ctx->len)
    175     *ctx->len = 0;
    176 
    177   if (! json_is_array (root))
    178   {
    179     GNUNET_break_op (0);
    180     return GNUNET_SYSERR;
    181   }
    182 
    183   {
    184     size_t len = json_array_size (root);
    185     json_t *entry;
    186     size_t idx;
    187 
    188     if (NULL != ctx->len)
    189       *ctx->len = len;
    190     if (0 == len)
    191     {
    192       *out = NULL;
    193       return GNUNET_OK;
    194     }
    195     *out = GNUNET_new_array (len,
    196                              struct TALER_Amount);
    197     json_array_foreach (root, idx, entry) {
    198       const char *amount_str;
    199 
    200       if (! json_is_string (entry))
    201       {
    202         GNUNET_break_op (0);
    203         return GNUNET_SYSERR;
    204       }
    205       amount_str = json_string_value (entry);
    206       if (GNUNET_OK !=
    207           TALER_string_to_amount (amount_str,
    208                                   &(*out)[idx]))
    209       {
    210         GNUNET_break_op (0);
    211         return GNUNET_SYSERR;
    212       }
    213     }
    214   }
    215   return GNUNET_OK;
    216 }
    217 
    218 
    219 /**
    220  * Cleanup helper for the amount array parser.
    221  */
    222 static void
    223 clean_amount_any_array (void *cls,
    224                         struct GNUNET_JSON_Specification *spec)
    225 {
    226   struct AmountArrayCtx *ctx = cls;
    227 
    228   if (NULL != spec->ptr)
    229   {
    230     GNUNET_free (*(void **) spec->ptr);
    231     *(void **) spec->ptr = NULL;
    232   }
    233   if ( (NULL != ctx) &&
    234        (NULL != ctx->len) )
    235     *ctx->len = 0;
    236   GNUNET_free (ctx);
    237 }
    238 
    239 
    240 struct GNUNET_JSON_Specification
    241 TALER_JSON_spec_amount_any_array (const char *field,
    242                                   size_t *amounts_len,
    243                                   struct TALER_Amount **amounts)
    244 {
    245   struct AmountArrayCtx *ctx;
    246 
    247   GNUNET_assert (NULL != amounts_len);
    248   GNUNET_assert (NULL != amounts);
    249   *amounts = NULL;
    250   *amounts_len = 0;
    251   ctx = GNUNET_new (struct AmountArrayCtx);
    252   ctx->len = amounts_len;
    253   {
    254     struct GNUNET_JSON_Specification ret = {
    255       .parser = &parse_amount_any_array,
    256       .cleaner = &clean_amount_any_array,
    257       .cls = ctx,
    258       .field = field,
    259       .ptr = amounts
    260     };
    261 
    262     return ret;
    263   }
    264 }
    265 
    266 
    267 /**
    268  * Parse a JSON array of amounts into a price list.
    269  *
    270  * @param cls closure, NULL
    271  * @param root the json array representing the price list
    272  * @param[out] spec where to write the data
    273  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    274  */
    275 static enum GNUNET_GenericReturnValue
    276 parse_amount_list (void *cls,
    277                    json_t *root,
    278                    struct GNUNET_JSON_Specification *spec)
    279 {
    280   struct TALER_AmountList *al = spec->ptr;
    281   size_t len;
    282   json_t *entry;
    283   size_t idx;
    284 
    285   (void) cls;
    286   al->tal = NULL;
    287   al->tal_len = 0;
    288   if (! json_is_array (root))
    289   {
    290     GNUNET_break_op (0);
    291     return GNUNET_SYSERR;
    292   }
    293   len = json_array_size (root);
    294   if (0 == len)
    295     return GNUNET_OK; /* empty price list: free */
    296   al->tal = GNUNET_new_array (len,
    297                               struct TALER_Amount);
    298   json_array_foreach (root, idx, entry)
    299   {
    300     struct TALER_Amount *a = &al->tal[idx];
    301 
    302     if (! json_is_string (entry))
    303     {
    304       GNUNET_break_op (0);
    305       TALER_amount_list_free (al);
    306       return GNUNET_SYSERR;
    307     }
    308     if (GNUNET_OK !=
    309         TALER_string_to_amount (json_string_value (entry),
    310                                 a))
    311     {
    312       GNUNET_break_op (0);
    313       TALER_amount_list_free (al);
    314       return GNUNET_SYSERR;
    315     }
    316     /* only entries below @a idx are initialized so far, and
    317        #TALER_amount_list_find() must not look at the rest */
    318     al->tal_len = idx;
    319     if (NULL !=
    320         TALER_amount_list_find (al,
    321                                 a->currency))
    322     {
    323       GNUNET_break_op (0);
    324       TALER_amount_list_free (al);
    325       return GNUNET_SYSERR;
    326     }
    327     al->tal_len = idx + 1;
    328   }
    329   return GNUNET_OK;
    330 }
    331 
    332 
    333 /**
    334  * Cleanup helper for the price list parser.
    335  *
    336  * @param cls closure, NULL
    337  * @param[out] spec where to free the data
    338  */
    339 static void
    340 clean_amount_list (void *cls,
    341                    struct GNUNET_JSON_Specification *spec)
    342 {
    343   (void) cls;
    344   TALER_amount_list_free (spec->ptr);
    345 }
    346 
    347 
    348 struct GNUNET_JSON_Specification
    349 TALER_JSON_spec_amount_list (const char *field,
    350                              struct TALER_AmountList *al)
    351 {
    352   struct GNUNET_JSON_Specification ret = {
    353     .parser = &parse_amount_list,
    354     .cleaner = &clean_amount_list,
    355     .cls = NULL,
    356     .field = field,
    357     .ptr = al
    358   };
    359 
    360   GNUNET_assert (NULL != al);
    361   al->tal = NULL;
    362   al->tal_len = 0;
    363   return ret;
    364 }
    365 
    366 
    367 /**
    368  * Parse given JSON object to currency spec.
    369  *
    370  * @param cls closure, NULL
    371  * @param root the json object representing data
    372  * @param[out] spec where to write the data
    373  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    374  */
    375 static enum GNUNET_GenericReturnValue
    376 parse_cspec (void *cls,
    377              json_t *root,
    378              struct GNUNET_JSON_Specification *spec)
    379 {
    380   struct TALER_CurrencySpecification *r_cspec = spec->ptr;
    381   const char *currency = spec->cls;
    382   const char *name;
    383   uint32_t fid;
    384   uint32_t fnd;
    385   uint32_t ftzd;
    386   const json_t *map;
    387   const json_t *ca = NULL;
    388   struct GNUNET_JSON_Specification gspec[] = {
    389     GNUNET_JSON_spec_string ("name",
    390                              &name),
    391     GNUNET_JSON_spec_uint32 ("num_fractional_input_digits",
    392                              &fid),
    393     GNUNET_JSON_spec_uint32 ("num_fractional_normal_digits",
    394                              &fnd),
    395     GNUNET_JSON_spec_uint32 ("num_fractional_trailing_zero_digits",
    396                              &ftzd),
    397     GNUNET_JSON_spec_object_const ("alt_unit_names",
    398                                    &map),
    399     GNUNET_JSON_spec_mark_optional (
    400       GNUNET_JSON_spec_array_const ("common_amounts",
    401                                     &ca),
    402       NULL),
    403     GNUNET_JSON_spec_end ()
    404   };
    405   const char *emsg;
    406   unsigned int eline;
    407 
    408   memset (r_cspec->currency,
    409           0,
    410           sizeof (r_cspec->currency));
    411   if (GNUNET_OK !=
    412       GNUNET_JSON_parse (root,
    413                          gspec,
    414                          &emsg,
    415                          &eline))
    416   {
    417     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    418                 "Failed to parse %s at %u: %s\n",
    419                 gspec[eline].field,
    420                 eline,
    421                 emsg);
    422     GNUNET_break_op (0);
    423     return GNUNET_SYSERR;
    424   }
    425   if (strlen (currency) >= TALER_CURRENCY_LEN)
    426   {
    427     GNUNET_break_op (0);
    428     return GNUNET_SYSERR;
    429   }
    430   if ( (fid > TALER_AMOUNT_FRAC_LEN) ||
    431        (fnd > TALER_AMOUNT_FRAC_LEN) ||
    432        (ftzd > TALER_AMOUNT_FRAC_LEN) )
    433   {
    434     GNUNET_break_op (0);
    435     return GNUNET_SYSERR;
    436   }
    437   if (GNUNET_OK !=
    438       TALER_check_currency (currency))
    439   {
    440     GNUNET_break_op (0);
    441     return GNUNET_SYSERR;
    442   }
    443   strcpy (r_cspec->currency,
    444           currency);
    445   if (GNUNET_OK !=
    446       TALER_check_currency_scale_map (map))
    447   {
    448     GNUNET_break_op (0);
    449     return GNUNET_SYSERR;
    450   }
    451   r_cspec->name = GNUNET_strdup (name);
    452   r_cspec->map_alt_unit_names = json_incref ((json_t *) map);
    453   if (NULL != ca)
    454   {
    455     size_t i;
    456     json_t *v;
    457 
    458     json_array_foreach ((json_t *) ca, i, v)
    459     {
    460       struct TALER_Amount val;
    461       const char *vstr;
    462 
    463       vstr = json_string_value (v);
    464       if ( (NULL == vstr) ||
    465            (GNUNET_OK !=
    466             TALER_string_to_amount (vstr,
    467                                     &val)) )
    468       {
    469         GNUNET_break_op (0);
    470         return GNUNET_SYSERR;
    471       }
    472       if (0 != strcasecmp (val.currency,
    473                            r_cspec->currency))
    474       {
    475         GNUNET_break_op (0);
    476         return GNUNET_SYSERR;
    477       }
    478       GNUNET_array_append (r_cspec->common_amounts,
    479                            r_cspec->num_common_amounts,
    480                            val);
    481     }
    482   }
    483   return GNUNET_OK;
    484 }
    485 
    486 
    487 /**
    488  * Cleanup data left from parsing encrypted contract.
    489  *
    490  * @param cls closure, NULL
    491  * @param[out] spec where to free the data
    492  */
    493 static void
    494 clean_cspec (void *cls,
    495              struct GNUNET_JSON_Specification *spec)
    496 {
    497   struct TALER_CurrencySpecification *cspec = spec->ptr;
    498 
    499   (void) cls;
    500   GNUNET_array_grow (cspec->common_amounts,
    501                      cspec->num_common_amounts,
    502                      0);
    503   GNUNET_free (cspec->name);
    504   json_decref (cspec->map_alt_unit_names);
    505 }
    506 
    507 
    508 struct GNUNET_JSON_Specification
    509 TALER_JSON_spec_currency_specification (
    510   const char *name,
    511   const char *currency,
    512   struct TALER_CurrencySpecification *r_cspec)
    513 {
    514   struct GNUNET_JSON_Specification ret = {
    515     .parser = &parse_cspec,
    516     .cleaner = &clean_cspec,
    517     .cls = (void *) currency,
    518     .field = name,
    519     .ptr = r_cspec,
    520     .ptr_size = sizeof (*r_cspec),
    521     .size_ptr = NULL
    522   };
    523 
    524   memset (r_cspec,
    525           0,
    526           sizeof (*r_cspec));
    527   return ret;
    528 }
    529 
    530 
    531 static enum GNUNET_GenericReturnValue
    532 parse_denomination_group (void *cls,
    533                           json_t *root,
    534                           struct GNUNET_JSON_Specification *spec)
    535 {
    536   struct TALER_DenominationGroup *group = spec->ptr;
    537   const char *cipher;
    538   const char *currency = cls;
    539   bool age_mask_missing = false;
    540   bool has_age_restricted_suffix = false;
    541   struct GNUNET_JSON_Specification gspec[] = {
    542     GNUNET_JSON_spec_string ("cipher",
    543                              &cipher),
    544     TALER_JSON_spec_amount ("value",
    545                             currency,
    546                             &group->value),
    547     TALER_JSON_SPEC_DENOM_FEES ("fee",
    548                                 currency,
    549                                 &group->fees),
    550     GNUNET_JSON_spec_mark_optional (
    551       GNUNET_JSON_spec_uint32 ("age_mask",
    552                                &group->age_mask.bits),
    553       &age_mask_missing),
    554     GNUNET_JSON_spec_end ()
    555   };
    556   const char *emsg;
    557   unsigned int eline;
    558 
    559   if (GNUNET_OK !=
    560       GNUNET_JSON_parse (root,
    561                          gspec,
    562                          &emsg,
    563                          &eline))
    564   {
    565     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    566                 "Failed to parse %s at %u: %s\n",
    567                 gspec[eline].field,
    568                 eline,
    569                 emsg);
    570     GNUNET_break_op (0);
    571     return GNUNET_SYSERR;
    572   }
    573 
    574   group->cipher = string_to_cipher (cipher);
    575   if (GNUNET_CRYPTO_BSA_INVALID == group->cipher)
    576   {
    577     GNUNET_break_op (0);
    578     return GNUNET_SYSERR;
    579   }
    580 
    581   /* age_mask and suffix must be consistent */
    582   has_age_restricted_suffix =
    583     (NULL != strstr (cipher, "+age_restricted"));
    584   if (has_age_restricted_suffix && age_mask_missing)
    585   {
    586     GNUNET_break_op (0);
    587     return GNUNET_SYSERR;
    588   }
    589 
    590   if (age_mask_missing)
    591     group->age_mask.bits = 0;
    592 
    593   return GNUNET_OK;
    594 }
    595 
    596 
    597 struct GNUNET_JSON_Specification
    598 TALER_JSON_spec_denomination_group (const char *name,
    599                                     const char *currency,
    600                                     struct TALER_DenominationGroup *group)
    601 {
    602   struct GNUNET_JSON_Specification ret = {
    603     .cls = (void *) currency,
    604     .parser = &parse_denomination_group,
    605     .field = name,
    606     .ptr = group,
    607     .ptr_size = sizeof(*group)
    608   };
    609 
    610   return ret;
    611 }
    612 
    613 
    614 /**
    615  * Parse given JSON object to an encrypted contract.
    616  *
    617  * @param cls closure, NULL
    618  * @param root the json object representing data
    619  * @param[out] spec where to write the data
    620  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    621  */
    622 static enum GNUNET_GenericReturnValue
    623 parse_econtract (void *cls,
    624                  json_t *root,
    625                  struct GNUNET_JSON_Specification *spec)
    626 {
    627   struct TALER_EncryptedContract *econtract = spec->ptr;
    628   struct GNUNET_JSON_Specification ispec[] = {
    629     GNUNET_JSON_spec_varsize ("econtract",
    630                               &econtract->econtract,
    631                               &econtract->econtract_size),
    632     GNUNET_JSON_spec_fixed_auto ("econtract_sig",
    633                                  &econtract->econtract_sig),
    634     GNUNET_JSON_spec_fixed_auto ("contract_pub",
    635                                  &econtract->contract_pub),
    636     GNUNET_JSON_spec_end ()
    637   };
    638   const char *emsg;
    639   unsigned int eline;
    640 
    641   (void) cls;
    642   if (GNUNET_OK !=
    643       GNUNET_JSON_parse (root,
    644                          ispec,
    645                          &emsg,
    646                          &eline))
    647   {
    648     GNUNET_break_op (0);
    649     return GNUNET_SYSERR;
    650   }
    651   return GNUNET_OK;
    652 }
    653 
    654 
    655 /**
    656  * Cleanup data left from parsing encrypted contract.
    657  *
    658  * @param cls closure, NULL
    659  * @param[out] spec where to free the data
    660  */
    661 static void
    662 clean_econtract (void *cls,
    663                  struct GNUNET_JSON_Specification *spec)
    664 {
    665   struct TALER_EncryptedContract *econtract = spec->ptr;
    666 
    667   (void) cls;
    668   GNUNET_free (econtract->econtract);
    669 }
    670 
    671 
    672 struct GNUNET_JSON_Specification
    673 TALER_JSON_spec_econtract (const char *name,
    674                            struct TALER_EncryptedContract *econtract)
    675 {
    676   struct GNUNET_JSON_Specification ret = {
    677     .parser = &parse_econtract,
    678     .cleaner = &clean_econtract,
    679     .field = name,
    680     .ptr = econtract
    681   };
    682 
    683   return ret;
    684 }
    685 
    686 
    687 /**
    688  * Parse given JSON object to an age commitmnet
    689  *
    690  * @param cls closure, NULL
    691  * @param root the json object representing data
    692  * @param[out] spec where to write the data
    693  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    694  */
    695 static enum GNUNET_GenericReturnValue
    696 parse_age_commitment (void *cls,
    697                       json_t *root,
    698                       struct GNUNET_JSON_Specification *spec)
    699 {
    700   struct TALER_AgeCommitment *age_commitment = spec->ptr;
    701   json_t *pk;
    702   unsigned int idx;
    703   size_t num;
    704 
    705   (void) cls;
    706   if ( (NULL == root) ||
    707        (! json_is_array (root)))
    708   {
    709     GNUNET_break_op (0);
    710     return GNUNET_SYSERR;
    711   }
    712 
    713   num = json_array_size (root);
    714   if (32 <= num || 0 == num)
    715   {
    716     GNUNET_break_op (0);
    717     return GNUNET_SYSERR;
    718   }
    719 
    720   age_commitment->num = num;
    721   age_commitment->pubs =
    722     GNUNET_new_array (num,
    723                       struct TALER_AgeCommitmentPublicKeyP);
    724 
    725   json_array_foreach (root, idx, pk) {
    726     const char *emsg;
    727     unsigned int eline;
    728     struct GNUNET_JSON_Specification pkspec[] = {
    729       GNUNET_JSON_spec_fixed_auto (
    730         NULL,
    731         &age_commitment->pubs[idx].pub),
    732       GNUNET_JSON_spec_end ()
    733     };
    734 
    735     if (GNUNET_OK !=
    736         GNUNET_JSON_parse (pk,
    737                            pkspec,
    738                            &emsg,
    739                            &eline))
    740     {
    741       GNUNET_break_op (0);
    742       GNUNET_free (age_commitment->pubs);
    743       age_commitment->num = 0;
    744       return GNUNET_SYSERR;
    745     }
    746   };
    747 
    748   return GNUNET_OK;
    749 }
    750 
    751 
    752 /**
    753  * Cleanup data left from parsing age commitment
    754  *
    755  * @param cls closure, NULL
    756  * @param[out] spec where to free the data
    757  */
    758 static void
    759 clean_age_commitment (void *cls,
    760                       struct GNUNET_JSON_Specification *spec)
    761 {
    762   struct TALER_AgeCommitment *age_commitment = spec->ptr;
    763 
    764   (void) cls;
    765   if ( (NULL == age_commitment) ||
    766        (NULL == age_commitment->pubs) )
    767     return;
    768   age_commitment->num = 0;
    769   GNUNET_free (age_commitment->pubs);
    770 }
    771 
    772 
    773 struct GNUNET_JSON_Specification
    774 TALER_JSON_spec_age_commitment (const char *name,
    775                                 struct TALER_AgeCommitment *age_commitment)
    776 {
    777   struct GNUNET_JSON_Specification ret = {
    778     .parser = &parse_age_commitment,
    779     .cleaner = &clean_age_commitment,
    780     .field = name,
    781     .ptr = age_commitment
    782   };
    783 
    784   return ret;
    785 }
    786 
    787 
    788 struct GNUNET_JSON_Specification
    789 TALER_JSON_spec_token_issue_sig (const char *field,
    790                                  struct TALER_TokenIssueSignature *sig)
    791 {
    792   sig->signature = NULL;
    793   return GNUNET_JSON_spec_unblinded_signature (field,
    794                                                &sig->signature);
    795 }
    796 
    797 
    798 struct GNUNET_JSON_Specification
    799 TALER_JSON_spec_blinded_token_issue_sig (
    800   const char *field,
    801   struct TALER_BlindedTokenIssueSignature *sig)
    802 {
    803   sig->signature = NULL;
    804   return GNUNET_JSON_spec_blinded_signature (field,
    805                                              &sig->signature);
    806 }
    807 
    808 
    809 struct GNUNET_JSON_Specification
    810 TALER_JSON_spec_token_envelope (const char *field,
    811                                 struct TALER_TokenEnvelope *env)
    812 {
    813   env->blinded_pub = NULL;
    814   return GNUNET_JSON_spec_blinded_message (field,
    815                                            &env->blinded_pub);
    816 }
    817 
    818 
    819 /**
    820  * Parse given JSON object to denomination public key.
    821  *
    822  * @param cls closure, NULL
    823  * @param root the json object representing data
    824  * @param[out] spec where to write the data
    825  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    826  */
    827 static enum GNUNET_GenericReturnValue
    828 parse_denom_pub (void *cls,
    829                  json_t *root,
    830                  struct GNUNET_JSON_Specification *spec)
    831 {
    832   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
    833   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
    834   const char *cipher;
    835   bool age_mask_missing = false;
    836   struct GNUNET_JSON_Specification dspec[] = {
    837     GNUNET_JSON_spec_string ("cipher",
    838                              &cipher),
    839     GNUNET_JSON_spec_mark_optional (
    840       GNUNET_JSON_spec_uint32 ("age_mask",
    841                                &denom_pub->age_mask.bits),
    842       &age_mask_missing),
    843     GNUNET_JSON_spec_end ()
    844   };
    845   const char *emsg;
    846   unsigned int eline;
    847 
    848   (void) cls;
    849   if (GNUNET_OK !=
    850       GNUNET_JSON_parse (root,
    851                          dspec,
    852                          &emsg,
    853                          &eline))
    854   {
    855     GNUNET_break_op (0);
    856     return GNUNET_SYSERR;
    857   }
    858 
    859   if (age_mask_missing)
    860     denom_pub->age_mask.bits = 0;
    861   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    862   bsign_pub->rc = 1;
    863   bsign_pub->cipher = string_to_cipher (cipher);
    864   switch (bsign_pub->cipher)
    865   {
    866   case GNUNET_CRYPTO_BSA_INVALID:
    867     break;
    868   case GNUNET_CRYPTO_BSA_RSA:
    869     {
    870       struct GNUNET_JSON_Specification ispec[] = {
    871         GNUNET_JSON_spec_rsa_public_key (
    872           "rsa_pub",
    873           &bsign_pub->details.rsa_public_key),
    874         GNUNET_JSON_spec_end ()
    875       };
    876 
    877       if (GNUNET_OK !=
    878           GNUNET_JSON_parse (root,
    879                              ispec,
    880                              &emsg,
    881                              &eline))
    882       {
    883         GNUNET_break_op (0);
    884         GNUNET_free (bsign_pub);
    885         return GNUNET_SYSERR;
    886       }
    887       GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key,
    888                                          &bsign_pub->pub_key_hash);
    889       denom_pub->bsign_pub_key = bsign_pub;
    890       return GNUNET_OK;
    891     }
    892   case GNUNET_CRYPTO_BSA_CS:
    893     {
    894       struct GNUNET_JSON_Specification ispec[] = {
    895         GNUNET_JSON_spec_fixed ("cs_pub",
    896                                 &bsign_pub->details.cs_public_key,
    897                                 sizeof (bsign_pub->details.cs_public_key)),
    898         GNUNET_JSON_spec_end ()
    899       };
    900 
    901       if (GNUNET_OK !=
    902           GNUNET_JSON_parse (root,
    903                              ispec,
    904                              &emsg,
    905                              &eline))
    906       {
    907         GNUNET_break_op (0);
    908         GNUNET_free (bsign_pub);
    909         return GNUNET_SYSERR;
    910       }
    911       GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
    912                           sizeof(bsign_pub->details.cs_public_key),
    913                           &bsign_pub->pub_key_hash);
    914       denom_pub->bsign_pub_key = bsign_pub;
    915       return GNUNET_OK;
    916     }
    917   }
    918   GNUNET_break_op (0);
    919   GNUNET_free (bsign_pub);
    920   return GNUNET_SYSERR;
    921 }
    922 
    923 
    924 /**
    925  * Cleanup data left from parsing denomination public key.
    926  *
    927  * @param cls closure, NULL
    928  * @param[out] spec where to free the data
    929  */
    930 static void
    931 clean_denom_pub (void *cls,
    932                  struct GNUNET_JSON_Specification *spec)
    933 {
    934   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
    935 
    936   (void) cls;
    937   TALER_denom_pub_free (denom_pub);
    938 }
    939 
    940 
    941 struct GNUNET_JSON_Specification
    942 TALER_JSON_spec_denom_pub (const char *field,
    943                            struct TALER_DenominationPublicKey *pk)
    944 {
    945   struct GNUNET_JSON_Specification ret = {
    946     .parser = &parse_denom_pub,
    947     .cleaner = &clean_denom_pub,
    948     .field = field,
    949     .ptr = pk
    950   };
    951 
    952   pk->bsign_pub_key = NULL;
    953   return ret;
    954 }
    955 
    956 
    957 /**
    958  * Parse given JSON object to token issue public key.
    959  *
    960  * @param cls closure, NULL
    961  * @param root the json object representing data
    962  * @param[out] spec where to write the data
    963  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    964  */
    965 static enum GNUNET_GenericReturnValue
    966 parse_token_pub (void *cls,
    967                  json_t *root,
    968                  struct GNUNET_JSON_Specification *spec)
    969 {
    970   struct TALER_TokenIssuePublicKey *token_pub = spec->ptr;
    971   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
    972   const char *cipher;
    973   struct GNUNET_JSON_Specification dspec[] = {
    974     GNUNET_JSON_spec_string ("cipher",
    975                              &cipher),
    976     GNUNET_JSON_spec_end ()
    977   };
    978   const char *emsg;
    979   unsigned int eline;
    980 
    981   (void) cls;
    982   if (GNUNET_OK !=
    983       GNUNET_JSON_parse (root,
    984                          dspec,
    985                          &emsg,
    986                          &eline))
    987   {
    988     GNUNET_break_op (0);
    989     return GNUNET_SYSERR;
    990   }
    991 
    992   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    993   bsign_pub->rc = 1;
    994   bsign_pub->cipher = string_to_cipher (cipher);
    995   switch (bsign_pub->cipher)
    996   {
    997   case GNUNET_CRYPTO_BSA_INVALID:
    998     break;
    999   case GNUNET_CRYPTO_BSA_RSA:
   1000     {
   1001       struct GNUNET_JSON_Specification ispec[] = {
   1002         GNUNET_JSON_spec_rsa_public_key (
   1003           "rsa_pub",
   1004           &bsign_pub->details.rsa_public_key),
   1005         GNUNET_JSON_spec_end ()
   1006       };
   1007 
   1008       if (GNUNET_OK !=
   1009           GNUNET_JSON_parse (root,
   1010                              ispec,
   1011                              &emsg,
   1012                              &eline))
   1013       {
   1014         GNUNET_break_op (0);
   1015         GNUNET_free (bsign_pub);
   1016         return GNUNET_SYSERR;
   1017       }
   1018       GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key,
   1019                                          &bsign_pub->pub_key_hash);
   1020       token_pub->public_key = bsign_pub;
   1021       return GNUNET_OK;
   1022     }
   1023   case GNUNET_CRYPTO_BSA_CS:
   1024     {
   1025       struct GNUNET_JSON_Specification ispec[] = {
   1026         GNUNET_JSON_spec_fixed ("cs_pub",
   1027                                 &bsign_pub->details.cs_public_key,
   1028                                 sizeof (bsign_pub->details.cs_public_key)),
   1029         GNUNET_JSON_spec_end ()
   1030       };
   1031 
   1032       if (GNUNET_OK !=
   1033           GNUNET_JSON_parse (root,
   1034                              ispec,
   1035                              &emsg,
   1036                              &eline))
   1037       {
   1038         GNUNET_break_op (0);
   1039         GNUNET_free (bsign_pub);
   1040         return GNUNET_SYSERR;
   1041       }
   1042       GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
   1043                           sizeof(bsign_pub->details.cs_public_key),
   1044                           &bsign_pub->pub_key_hash);
   1045       token_pub->public_key = bsign_pub;
   1046       return GNUNET_OK;
   1047     }
   1048   }
   1049   GNUNET_break_op (0);
   1050   GNUNET_free (bsign_pub);
   1051   return GNUNET_SYSERR;
   1052 }
   1053 
   1054 
   1055 /**
   1056  * Cleanup data left from parsing token issue public key.
   1057  *
   1058  * @param cls closure, NULL
   1059  * @param[out] spec where to free the data
   1060  */
   1061 static void
   1062 clean_token_pub (void *cls,
   1063                  struct GNUNET_JSON_Specification *spec)
   1064 {
   1065   struct TALER_TokenIssuePublicKey *token_pub = spec->ptr;
   1066 
   1067   (void) cls;
   1068   TALER_token_issue_pub_free (token_pub);
   1069 }
   1070 
   1071 
   1072 struct GNUNET_JSON_Specification
   1073 TALER_JSON_spec_token_pub (const char *field,
   1074                            struct TALER_TokenIssuePublicKey *pk)
   1075 {
   1076   struct GNUNET_JSON_Specification ret = {
   1077     .field = field,
   1078     .parser = &parse_token_pub,
   1079     .cleaner = &clean_token_pub,
   1080     .ptr = pk
   1081   };
   1082 
   1083   pk->public_key = NULL;
   1084   return ret;
   1085 }
   1086 
   1087 
   1088 /**
   1089  * Parse given JSON object partially into a denomination public key.
   1090  *
   1091  * Depending on the cipher in cls, it parses the corresponding public key type.
   1092  *
   1093  * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
   1094  * @param root the json object representing data
   1095  * @param[out] spec where to write the data
   1096  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1097  */
   1098 static enum GNUNET_GenericReturnValue
   1099 parse_denom_pub_cipher (void *cls,
   1100                         json_t *root,
   1101                         struct GNUNET_JSON_Specification *spec)
   1102 {
   1103   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
   1104   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
   1105     (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls;
   1106   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
   1107   const char *emsg;
   1108   unsigned int eline;
   1109 
   1110   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
   1111   bsign_pub->cipher = cipher;
   1112   bsign_pub->rc = 1;
   1113   switch (cipher)
   1114   {
   1115   case GNUNET_CRYPTO_BSA_INVALID:
   1116     break;
   1117   case GNUNET_CRYPTO_BSA_RSA:
   1118     {
   1119       struct GNUNET_JSON_Specification ispec[] = {
   1120         GNUNET_JSON_spec_rsa_public_key (
   1121           "rsa_pub",
   1122           &bsign_pub->details.rsa_public_key),
   1123         GNUNET_JSON_spec_end ()
   1124       };
   1125 
   1126       if (GNUNET_OK !=
   1127           GNUNET_JSON_parse (root,
   1128                              ispec,
   1129                              &emsg,
   1130                              &eline))
   1131       {
   1132         GNUNET_break_op (0);
   1133         GNUNET_free (bsign_pub);
   1134         return GNUNET_SYSERR;
   1135       }
   1136       GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key,
   1137                                          &bsign_pub->pub_key_hash);
   1138       denom_pub->bsign_pub_key = bsign_pub;
   1139       return GNUNET_OK;
   1140     }
   1141   case GNUNET_CRYPTO_BSA_CS:
   1142     {
   1143       struct GNUNET_JSON_Specification ispec[] = {
   1144         GNUNET_JSON_spec_fixed ("cs_pub",
   1145                                 &bsign_pub->details.cs_public_key,
   1146                                 sizeof (bsign_pub->details.cs_public_key)),
   1147         GNUNET_JSON_spec_end ()
   1148       };
   1149 
   1150       if (GNUNET_OK !=
   1151           GNUNET_JSON_parse (root,
   1152                              ispec,
   1153                              &emsg,
   1154                              &eline))
   1155       {
   1156         GNUNET_break_op (0);
   1157         GNUNET_free (bsign_pub);
   1158         return GNUNET_SYSERR;
   1159       }
   1160       GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
   1161                           sizeof(bsign_pub->details.cs_public_key),
   1162                           &bsign_pub->pub_key_hash);
   1163       denom_pub->bsign_pub_key = bsign_pub;
   1164       return GNUNET_OK;
   1165     }
   1166   }
   1167   GNUNET_break_op (0);
   1168   GNUNET_free (bsign_pub);
   1169   return GNUNET_SYSERR;
   1170 }
   1171 
   1172 
   1173 struct GNUNET_JSON_Specification
   1174 TALER_JSON_spec_denom_pub_cipher (
   1175   const char *field,
   1176   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
   1177   struct TALER_DenominationPublicKey *pk)
   1178 {
   1179   struct GNUNET_JSON_Specification ret = {
   1180     .parser = &parse_denom_pub_cipher,
   1181     .cleaner = &clean_denom_pub,
   1182     .field = field,
   1183     .cls = (void *) cipher,
   1184     .ptr = pk
   1185   };
   1186 
   1187   pk->bsign_pub_key = NULL;
   1188   return ret;
   1189 }
   1190 
   1191 
   1192 struct GNUNET_JSON_Specification
   1193 TALER_JSON_spec_denom_sig (const char *field,
   1194                            struct TALER_DenominationSignature *sig)
   1195 {
   1196   sig->unblinded_sig = NULL;
   1197   return GNUNET_JSON_spec_unblinded_signature (field,
   1198                                                &sig->unblinded_sig);
   1199 }
   1200 
   1201 
   1202 struct GNUNET_JSON_Specification
   1203 TALER_JSON_spec_blinded_denom_sig (
   1204   const char *field,
   1205   struct TALER_BlindedDenominationSignature *sig)
   1206 {
   1207   sig->blinded_sig = NULL;
   1208   return GNUNET_JSON_spec_blinded_signature (field,
   1209                                              &sig->blinded_sig);
   1210 }
   1211 
   1212 
   1213 struct GNUNET_JSON_Specification
   1214 TALER_JSON_spec_blinded_planchet (
   1215   const char *field,
   1216   struct TALER_BlindedPlanchet *blinded_planchet)
   1217 {
   1218   blinded_planchet->blinded_message = NULL;
   1219   return GNUNET_JSON_spec_blinded_message (field,
   1220                                            &blinded_planchet->blinded_message);
   1221 }
   1222 
   1223 
   1224 /**
   1225  * Parse given JSON object to exchange withdraw values (/csr).
   1226  *
   1227  * @param cls closure, NULL
   1228  * @param root the json object representing data
   1229  * @param[out] spec where to write the data
   1230  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1231  */
   1232 static enum GNUNET_GenericReturnValue
   1233 parse_exchange_blinding_values (void *cls,
   1234                                 json_t *root,
   1235                                 struct GNUNET_JSON_Specification *spec)
   1236 {
   1237   struct TALER_ExchangeBlindingValues *ewv = spec->ptr;
   1238   struct GNUNET_CRYPTO_BlindingInputValues *bi;
   1239   const char *cipher;
   1240   struct GNUNET_JSON_Specification dspec[] = {
   1241     GNUNET_JSON_spec_string ("cipher",
   1242                              &cipher),
   1243     GNUNET_JSON_spec_end ()
   1244   };
   1245   const char *emsg;
   1246   unsigned int eline;
   1247   enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci;
   1248 
   1249   (void) cls;
   1250   if (GNUNET_OK !=
   1251       GNUNET_JSON_parse (root,
   1252                          dspec,
   1253                          &emsg,
   1254                          &eline))
   1255   {
   1256     GNUNET_break_op (0);
   1257     return GNUNET_SYSERR;
   1258   }
   1259   ci = string_to_cipher (cipher);
   1260   switch (ci)
   1261   {
   1262   case GNUNET_CRYPTO_BSA_INVALID:
   1263     break;
   1264   case GNUNET_CRYPTO_BSA_RSA:
   1265     ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs;
   1266     return GNUNET_OK;
   1267   case GNUNET_CRYPTO_BSA_CS:
   1268     bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
   1269     bi->cipher = GNUNET_CRYPTO_BSA_CS;
   1270     bi->rc = 1;
   1271     {
   1272       struct GNUNET_JSON_Specification ispec[] = {
   1273         GNUNET_JSON_spec_fixed (
   1274           "r_pub_0",
   1275           &bi->details.cs_values.r_pub[0],
   1276           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
   1277         GNUNET_JSON_spec_fixed (
   1278           "r_pub_1",
   1279           &bi->details.cs_values.r_pub[1],
   1280           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
   1281         GNUNET_JSON_spec_end ()
   1282       };
   1283 
   1284       if (GNUNET_OK !=
   1285           GNUNET_JSON_parse (root,
   1286                              ispec,
   1287                              &emsg,
   1288                              &eline))
   1289       {
   1290         GNUNET_break_op (0);
   1291         GNUNET_free (bi);
   1292         return GNUNET_SYSERR;
   1293       }
   1294       ewv->blinding_inputs = bi;
   1295       return GNUNET_OK;
   1296     }
   1297   }
   1298   GNUNET_break_op (0);
   1299   return GNUNET_SYSERR;
   1300 }
   1301 
   1302 
   1303 /**
   1304  * Cleanup data left from parsing withdraw values
   1305  *
   1306  * @param cls closure, NULL
   1307  * @param[out] spec where to free the data
   1308  */
   1309 static void
   1310 clean_exchange_blinding_values (
   1311   void *cls,
   1312   struct GNUNET_JSON_Specification *spec)
   1313 {
   1314   struct TALER_ExchangeBlindingValues *ewv = spec->ptr;
   1315 
   1316   (void) cls;
   1317   TALER_denom_ewv_free (ewv);
   1318 }
   1319 
   1320 
   1321 struct GNUNET_JSON_Specification
   1322 TALER_JSON_spec_exchange_blinding_values (
   1323   const char *field,
   1324   struct TALER_ExchangeBlindingValues *ewv)
   1325 {
   1326   struct GNUNET_JSON_Specification ret = {
   1327     .parser = &parse_exchange_blinding_values,
   1328     .cleaner = &clean_exchange_blinding_values,
   1329     .field = field,
   1330     .ptr = ewv
   1331   };
   1332 
   1333   ewv->blinding_inputs = NULL;
   1334   return ret;
   1335 }
   1336 
   1337 
   1338 /**
   1339  * Closure for #parse_i18n_string.
   1340  */
   1341 struct I18nContext
   1342 {
   1343   /**
   1344    * Language pattern to match.
   1345    */
   1346   char *lp;
   1347 
   1348   /**
   1349    * Name of the field to match.
   1350    */
   1351   const char *field;
   1352 };
   1353 
   1354 
   1355 /**
   1356  * Parse given JSON object to internationalized string.
   1357  *
   1358  * @param cls closure, our `struct I18nContext *`
   1359  * @param root the json object representing data
   1360  * @param[out] spec where to write the data
   1361  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1362  */
   1363 static enum GNUNET_GenericReturnValue
   1364 parse_i18n_string (void *cls,
   1365                    json_t *root,
   1366                    struct GNUNET_JSON_Specification *spec)
   1367 {
   1368   struct I18nContext *ctx = cls;
   1369   json_t *i18n;
   1370   json_t *val;
   1371 
   1372   {
   1373     char *i18nf;
   1374 
   1375     GNUNET_asprintf (&i18nf,
   1376                      "%s_i18n",
   1377                      ctx->field);
   1378     i18n = json_object_get (root,
   1379                             i18nf);
   1380     GNUNET_free (i18nf);
   1381   }
   1382 
   1383   val = json_object_get (root,
   1384                          ctx->field);
   1385   if ( (NULL != i18n) &&
   1386        (NULL != ctx->lp) )
   1387   {
   1388     double best = 0.0;
   1389     json_t *pos;
   1390     const char *lang;
   1391 
   1392     json_object_foreach (i18n, lang, pos)
   1393     {
   1394       double score;
   1395 
   1396       score = TALER_pattern_matches (ctx->lp,
   1397                                      lang);
   1398       if (score > best)
   1399       {
   1400         best = score;
   1401         val = pos;
   1402       }
   1403     }
   1404   }
   1405 
   1406   {
   1407     const char *str;
   1408 
   1409     str = json_string_value (val);
   1410     *(const char **) spec->ptr = str;
   1411   }
   1412   return GNUNET_OK;
   1413 }
   1414 
   1415 
   1416 /**
   1417  * Function called to clean up data from earlier parsing.
   1418  *
   1419  * @param cls closure
   1420  * @param spec our specification entry with data to clean.
   1421  */
   1422 static void
   1423 i18n_cleaner (void *cls,
   1424               struct GNUNET_JSON_Specification *spec)
   1425 {
   1426   struct I18nContext *ctx = cls;
   1427 
   1428   (void) spec;
   1429   if (NULL != ctx)
   1430   {
   1431     GNUNET_free (ctx->lp);
   1432     GNUNET_free (ctx);
   1433   }
   1434 }
   1435 
   1436 
   1437 struct GNUNET_JSON_Specification
   1438 TALER_JSON_spec_i18n_string (const char *name,
   1439                              const char *language_pattern,
   1440                              const char **strptr)
   1441 {
   1442   struct I18nContext *ctx = GNUNET_new (struct I18nContext);
   1443   struct GNUNET_JSON_Specification ret = {
   1444     .parser = &parse_i18n_string,
   1445     .cleaner = &i18n_cleaner,
   1446     .cls = ctx,
   1447     .field = NULL, /* we want the main object */
   1448     .ptr = strptr,
   1449     .ptr_size = 0,
   1450     .size_ptr = NULL
   1451   };
   1452 
   1453   ctx->lp = (NULL != language_pattern)
   1454     ? GNUNET_strdup (language_pattern)
   1455     : NULL;
   1456   ctx->field = name;
   1457   *strptr = NULL;
   1458   return ret;
   1459 }
   1460 
   1461 
   1462 struct GNUNET_JSON_Specification
   1463 TALER_JSON_spec_i18n_str (const char *name,
   1464                           const char **strptr)
   1465 {
   1466   const char *lang = getenv ("LANG");
   1467   const char *dot;
   1468   char *l;
   1469   struct GNUNET_JSON_Specification ret;
   1470 
   1471   if (NULL != lang)
   1472   {
   1473     dot = strchr (lang,
   1474                   '.');
   1475     if (NULL == dot)
   1476       l = GNUNET_strdup (lang);
   1477     else
   1478       l = GNUNET_strndup (lang,
   1479                           dot - lang);
   1480   }
   1481   else
   1482   {
   1483     l = NULL;
   1484   }
   1485   ret = TALER_JSON_spec_i18n_string (name,
   1486                                      l,
   1487                                      strptr);
   1488   GNUNET_free (l);
   1489   return ret;
   1490 }
   1491 
   1492 
   1493 /**
   1494  * Parse given JSON object with Taler error code.
   1495  *
   1496  * @param cls closure, NULL
   1497  * @param root the json object representing data
   1498  * @param[out] spec where to write the data
   1499  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1500  */
   1501 static enum GNUNET_GenericReturnValue
   1502 parse_ec (void *cls,
   1503           json_t *root,
   1504           struct GNUNET_JSON_Specification *spec)
   1505 {
   1506   enum TALER_ErrorCode *ec = spec->ptr;
   1507   json_int_t num;
   1508 
   1509   (void) cls;
   1510   if (! json_is_integer (root))
   1511   {
   1512     GNUNET_break_op (0);
   1513     return GNUNET_SYSERR;
   1514   }
   1515   num = json_integer_value (root);
   1516   if (num < 0)
   1517   {
   1518     GNUNET_break_op (0);
   1519     *ec = TALER_EC_INVALID;
   1520     return GNUNET_SYSERR;
   1521   }
   1522   *ec = (enum TALER_ErrorCode) num;
   1523   return GNUNET_OK;
   1524 }
   1525 
   1526 
   1527 struct GNUNET_JSON_Specification
   1528 TALER_JSON_spec_ec (const char *field,
   1529                     enum TALER_ErrorCode *ec)
   1530 {
   1531   struct GNUNET_JSON_Specification ret = {
   1532     .parser = &parse_ec,
   1533     .field = field,
   1534     .ptr = ec
   1535   };
   1536 
   1537   *ec = TALER_EC_NONE;
   1538   return ret;
   1539 }
   1540 
   1541 
   1542 /**
   1543  * Parse given JSON object to web URL.
   1544  *
   1545  * @param cls closure, NULL
   1546  * @param root the json object representing data
   1547  * @param[out] spec where to write the data
   1548  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1549  */
   1550 static enum GNUNET_GenericReturnValue
   1551 parse_web_url (void *cls,
   1552                json_t *root,
   1553                struct GNUNET_JSON_Specification *spec)
   1554 {
   1555   const char *str;
   1556 
   1557   (void) cls;
   1558   str = json_string_value (root);
   1559   if (NULL == str)
   1560   {
   1561     GNUNET_break_op (0);
   1562     return GNUNET_SYSERR;
   1563   }
   1564   if (! TALER_is_web_url (str))
   1565   {
   1566     GNUNET_break_op (0);
   1567     return GNUNET_SYSERR;
   1568   }
   1569   *(const char **) spec->ptr = str;
   1570   return GNUNET_OK;
   1571 }
   1572 
   1573 
   1574 struct GNUNET_JSON_Specification
   1575 TALER_JSON_spec_web_url (const char *field,
   1576                          const char **url)
   1577 {
   1578   struct GNUNET_JSON_Specification ret = {
   1579     .parser = &parse_web_url,
   1580     .field = field,
   1581     .ptr = url
   1582   };
   1583 
   1584   *url = NULL;
   1585   return ret;
   1586 }
   1587 
   1588 
   1589 /**
   1590  * Parse given JSON object to web URL, and make a copy.
   1591  *
   1592  * @param cls closure, NULL
   1593  * @param root the json object representing data
   1594  * @param[out] spec where to write the data
   1595  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1596  */
   1597 static enum GNUNET_GenericReturnValue
   1598 parse_web_url_copy (void *cls,
   1599                     json_t *root,
   1600                     struct GNUNET_JSON_Specification *spec)
   1601 {
   1602   const char *str;
   1603 
   1604   (void) cls;
   1605   str = json_string_value (root);
   1606   if (NULL == str)
   1607   {
   1608     GNUNET_break_op (0);
   1609     return GNUNET_SYSERR;
   1610   }
   1611   if (! TALER_is_web_url (str))
   1612   {
   1613     GNUNET_break_op (0);
   1614     return GNUNET_SYSERR;
   1615   }
   1616   *(char **) spec->ptr = GNUNET_strdup (str);
   1617   return GNUNET_OK;
   1618 }
   1619 
   1620 
   1621 struct GNUNET_JSON_Specification
   1622 TALER_JSON_spec_web_url_copy (const char *field,
   1623                               char **url)
   1624 {
   1625   struct GNUNET_JSON_Specification ret = {
   1626     .parser = &parse_web_url_copy,
   1627     .field = field,
   1628     .ptr = url
   1629   };
   1630 
   1631   *url = NULL;
   1632   return ret;
   1633 }
   1634 
   1635 
   1636 /**
   1637  * Parse given JSON object to slug.
   1638  *
   1639  * @param cls closure, NULL
   1640  * @param root the json object representing data
   1641  * @param[out] spec where to write the data
   1642  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1643  */
   1644 static enum GNUNET_GenericReturnValue
   1645 parse_slug (void *cls,
   1646             json_t *root,
   1647             struct GNUNET_JSON_Specification *spec)
   1648 {
   1649   const char *str;
   1650 
   1651   (void) cls;
   1652   str = json_string_value (root);
   1653   if (NULL == str)
   1654   {
   1655     GNUNET_break_op (0);
   1656     return GNUNET_SYSERR;
   1657   }
   1658   if (! TALER_is_slug (str))
   1659   {
   1660     GNUNET_break_op (0);
   1661     return GNUNET_SYSERR;
   1662   }
   1663   *(const char **) spec->ptr = str;
   1664   return GNUNET_OK;
   1665 }
   1666 
   1667 
   1668 struct GNUNET_JSON_Specification
   1669 TALER_JSON_spec_slug (const char *field,
   1670                       const char **slug)
   1671 {
   1672   struct GNUNET_JSON_Specification ret = {
   1673     .parser = &parse_slug,
   1674     .field = field,
   1675     .ptr = slug
   1676   };
   1677 
   1678   *slug = NULL;
   1679   return ret;
   1680 }
   1681 
   1682 
   1683 /**
   1684  * Parse given JSON object to slug.
   1685  *
   1686  * @param cls closure, NULL
   1687  * @param root the json object representing data
   1688  * @param[out] spec where to write the data
   1689  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1690  */
   1691 static enum GNUNET_GenericReturnValue
   1692 parse_slug_copy (void *cls,
   1693                  json_t *root,
   1694                  struct GNUNET_JSON_Specification *spec)
   1695 {
   1696   const char *str;
   1697 
   1698   (void) cls;
   1699   str = json_string_value (root);
   1700   if (NULL == str)
   1701   {
   1702     GNUNET_break_op (0);
   1703     return GNUNET_SYSERR;
   1704   }
   1705   if (! TALER_is_slug (str))
   1706   {
   1707     GNUNET_break_op (0);
   1708     return GNUNET_SYSERR;
   1709   }
   1710   *(char **) spec->ptr = GNUNET_strdup (str);
   1711   return GNUNET_OK;
   1712 }
   1713 
   1714 
   1715 struct GNUNET_JSON_Specification
   1716 TALER_JSON_spec_slug_copy (const char *field,
   1717                            char **slug)
   1718 {
   1719   struct GNUNET_JSON_Specification ret = {
   1720     .parser = &parse_slug_copy,
   1721     .field = field,
   1722     .ptr = slug
   1723   };
   1724 
   1725   *slug = NULL;
   1726   return ret;
   1727 }
   1728 
   1729 
   1730 /**
   1731  * Parse given JSON object to a session ID.
   1732  *
   1733  * @param cls closure, NULL
   1734  * @param root the json object representing data
   1735  * @param[out] spec where to write the data
   1736  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1737  */
   1738 static enum GNUNET_GenericReturnValue
   1739 parse_session_id (void *cls,
   1740                   json_t *root,
   1741                   struct GNUNET_JSON_Specification *spec)
   1742 {
   1743   const char *str;
   1744 
   1745   (void) cls;
   1746   str = json_string_value (root);
   1747   if (NULL == str)
   1748   {
   1749     GNUNET_break_op (0);
   1750     return GNUNET_SYSERR;
   1751   }
   1752   if (! TALER_is_session_id (str))
   1753   {
   1754     GNUNET_break_op (0);
   1755     return GNUNET_SYSERR;
   1756   }
   1757   *(const char **) spec->ptr = str;
   1758   return GNUNET_OK;
   1759 }
   1760 
   1761 
   1762 struct GNUNET_JSON_Specification
   1763 TALER_JSON_spec_session_id (const char *field,
   1764                             const char **session_id)
   1765 {
   1766   struct GNUNET_JSON_Specification ret = {
   1767     .parser = &parse_session_id,
   1768     .field = field,
   1769     .ptr = session_id
   1770   };
   1771 
   1772   *session_id = NULL;
   1773   return ret;
   1774 }
   1775 
   1776 
   1777 /**
   1778  * Parse given JSON object to a session ID that must not be empty.
   1779  *
   1780  * @param cls closure, NULL
   1781  * @param root the json object representing data
   1782  * @param[out] spec where to write the data
   1783  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1784  */
   1785 static enum GNUNET_GenericReturnValue
   1786 parse_nonempty_session_id (void *cls,
   1787                            json_t *root,
   1788                            struct GNUNET_JSON_Specification *spec)
   1789 {
   1790   if (GNUNET_OK !=
   1791       parse_session_id (cls,
   1792                         root,
   1793                         spec))
   1794     return GNUNET_SYSERR;
   1795   if ('\0' == (*(const char **) spec->ptr)[0])
   1796   {
   1797     GNUNET_break_op (0);
   1798     return GNUNET_SYSERR;
   1799   }
   1800   return GNUNET_OK;
   1801 }
   1802 
   1803 
   1804 struct GNUNET_JSON_Specification
   1805 TALER_JSON_spec_nonempty_session_id (const char *field,
   1806                                      const char **session_id)
   1807 {
   1808   struct GNUNET_JSON_Specification ret = {
   1809     .parser = &parse_nonempty_session_id,
   1810     .field = field,
   1811     .ptr = session_id
   1812   };
   1813 
   1814   *session_id = NULL;
   1815   return ret;
   1816 }
   1817 
   1818 
   1819 /**
   1820  * Parse given JSON object to payto:// URI.
   1821  *
   1822  * @param cls closure, NULL
   1823  * @param root the json object representing data
   1824  * @param[out] spec where to write the data
   1825  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1826  */
   1827 static enum GNUNET_GenericReturnValue
   1828 parse_full_payto_uri (void *cls,
   1829                       json_t *root,
   1830                       struct GNUNET_JSON_Specification *spec)
   1831 {
   1832   struct TALER_FullPayto *payto_uri = spec->ptr;
   1833   const char *str;
   1834   char *err;
   1835 
   1836   (void) cls;
   1837   str = json_string_value (root);
   1838   if (NULL == str)
   1839   {
   1840     GNUNET_break_op (0);
   1841     return GNUNET_SYSERR;
   1842   }
   1843   payto_uri->full_payto = (char *) str;
   1844   err = TALER_payto_validate (*payto_uri);
   1845   if (NULL != err)
   1846   {
   1847     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1848                 "payto:// malformed: %s\n",
   1849                 err);
   1850     GNUNET_free (err);
   1851     payto_uri->full_payto = NULL;
   1852     return GNUNET_SYSERR;
   1853   }
   1854   return GNUNET_OK;
   1855 }
   1856 
   1857 
   1858 struct GNUNET_JSON_Specification
   1859 TALER_JSON_spec_full_payto_uri (
   1860   const char *field,
   1861   struct TALER_FullPayto *payto_uri)
   1862 {
   1863   struct GNUNET_JSON_Specification ret = {
   1864     .parser = &parse_full_payto_uri,
   1865     .field = field,
   1866     .ptr = payto_uri
   1867   };
   1868 
   1869   payto_uri->full_payto = NULL;
   1870   return ret;
   1871 }
   1872 
   1873 
   1874 /**
   1875  * Parse given JSON object to payto:// URI.
   1876  *
   1877  * @param cls closure, NULL
   1878  * @param root the json object representing data
   1879  * @param[out] spec where to write the data
   1880  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1881  */
   1882 static enum GNUNET_GenericReturnValue
   1883 parse_normalized_payto_uri (void *cls,
   1884                             json_t *root,
   1885                             struct GNUNET_JSON_Specification *spec)
   1886 {
   1887   struct TALER_NormalizedPayto *payto_uri = spec->ptr;
   1888   const char *str;
   1889 
   1890   (void) cls;
   1891   str = json_string_value (root);
   1892   if (NULL == str)
   1893   {
   1894     GNUNET_break_op (0);
   1895     return GNUNET_SYSERR;
   1896   }
   1897   payto_uri->normalized_payto = (char *) str;
   1898   {
   1899     char *err;
   1900 
   1901     err = TALER_normalized_payto_validate (*payto_uri);
   1902     if (NULL != err)
   1903     {
   1904       GNUNET_break_op (0);
   1905       GNUNET_free (err);
   1906       payto_uri->normalized_payto = NULL;
   1907       return GNUNET_SYSERR;
   1908     }
   1909   }
   1910   return GNUNET_OK;
   1911 }
   1912 
   1913 
   1914 struct GNUNET_JSON_Specification
   1915 TALER_JSON_spec_normalized_payto_uri (
   1916   const char *field,
   1917   struct TALER_NormalizedPayto *payto_uri)
   1918 {
   1919   struct GNUNET_JSON_Specification ret = {
   1920     .parser = &parse_normalized_payto_uri,
   1921     .field = field,
   1922     .ptr = payto_uri
   1923   };
   1924 
   1925   payto_uri->normalized_payto = NULL;
   1926   return ret;
   1927 }
   1928 
   1929 
   1930 /**
   1931  * Parse given JSON object with protocol version.
   1932  *
   1933  * @param cls closure, NULL
   1934  * @param root the json object representing data
   1935  * @param[out] spec where to write the data
   1936  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1937  */
   1938 static enum GNUNET_GenericReturnValue
   1939 parse_protocol_version (void *cls,
   1940                         json_t *root,
   1941                         struct GNUNET_JSON_Specification *spec)
   1942 {
   1943   struct TALER_JSON_ProtocolVersion *pv = spec->ptr;
   1944   const char *ver;
   1945   char dummy;
   1946 
   1947   (void) cls;
   1948   if (! json_is_string (root))
   1949   {
   1950     GNUNET_break_op (0);
   1951     return GNUNET_SYSERR;
   1952   }
   1953   ver = json_string_value (root);
   1954   if (3 != sscanf (ver,
   1955                    "%u:%u:%u%c",
   1956                    &pv->current,
   1957                    &pv->revision,
   1958                    &pv->age,
   1959                    &dummy))
   1960   {
   1961     GNUNET_break_op (0);
   1962     return GNUNET_SYSERR;
   1963   }
   1964   return GNUNET_OK;
   1965 }
   1966 
   1967 
   1968 struct GNUNET_JSON_Specification
   1969 TALER_JSON_spec_version (const char *field,
   1970                          struct TALER_JSON_ProtocolVersion *ver)
   1971 {
   1972   struct GNUNET_JSON_Specification ret = {
   1973     .parser = &parse_protocol_version,
   1974     .field = field,
   1975     .ptr = ver
   1976   };
   1977 
   1978   return ret;
   1979 }
   1980 
   1981 
   1982 /**
   1983  * Parse given JSON object to an OTP key.
   1984  *
   1985  * @param cls closure, NULL
   1986  * @param root the json object representing data
   1987  * @param[out] spec where to write the data
   1988  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1989  */
   1990 static enum GNUNET_GenericReturnValue
   1991 parse_otp_key (void *cls,
   1992                json_t *root,
   1993                struct GNUNET_JSON_Specification *spec)
   1994 {
   1995   const char *pos_key;
   1996 
   1997   (void) cls;
   1998   pos_key = json_string_value (root);
   1999   if (NULL == pos_key)
   2000   {
   2001     GNUNET_break_op (0);
   2002     return GNUNET_SYSERR;
   2003   }
   2004   {
   2005     size_t pos_key_length = strlen (pos_key);
   2006     void *key; /* pos_key in binary */
   2007     size_t key_len; /* length of the key */
   2008     int dret;
   2009 
   2010     key_len = pos_key_length * 5 / 8;
   2011     key = GNUNET_malloc (key_len);
   2012     dret = TALER_rfc3548_base32decode (pos_key,
   2013                                        pos_key_length,
   2014                                        key,
   2015                                        key_len);
   2016     if (-1 == dret)
   2017     {
   2018       GNUNET_free (key);
   2019       GNUNET_break_op (0);
   2020       return GNUNET_SYSERR;
   2021     }
   2022     GNUNET_free (key);
   2023   }
   2024   *(const char **) spec->ptr = pos_key;
   2025   return GNUNET_OK;
   2026 }
   2027 
   2028 
   2029 struct GNUNET_JSON_Specification
   2030 TALER_JSON_spec_otp_key (const char *name,
   2031                          const char **otp_key)
   2032 {
   2033   struct GNUNET_JSON_Specification ret = {
   2034     .parser = &parse_otp_key,
   2035     .field = name,
   2036     .ptr = otp_key
   2037   };
   2038 
   2039   *otp_key = NULL;
   2040   return ret;
   2041 }
   2042 
   2043 
   2044 /**
   2045  * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm`
   2046  *
   2047  * @param cls closure, NULL
   2048  * @param root the json object representing data
   2049  * @param[out] spec where to write the data
   2050  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   2051  */
   2052 static enum GNUNET_GenericReturnValue
   2053 parse_otp_type (void *cls,
   2054                 json_t *root,
   2055                 struct GNUNET_JSON_Specification *spec)
   2056 {
   2057   static const struct Entry
   2058   {
   2059     const char *name;
   2060     enum TALER_MerchantConfirmationAlgorithm val;
   2061   } lt [] = {
   2062     { .name = "NONE",
   2063       .val = TALER_MCA_NONE },
   2064     { .name = "TOTP_WITHOUT_PRICE",
   2065       .val = TALER_MCA_WITHOUT_PRICE },
   2066     { .name = "TOTP_WITH_PRICE",
   2067       .val = TALER_MCA_WITH_PRICE },
   2068     { .name = "ECDSA_CHALLENGE",
   2069       .val = TALER_MCA_ECDSA_CHALLENGE },
   2070     { .name = "EDDSA_CHALLENGE",
   2071       .val = TALER_MCA_EDDSA_CHALLENGE },
   2072     { .name = NULL,
   2073       .val = TALER_MCA_NONE },
   2074   };
   2075   enum TALER_MerchantConfirmationAlgorithm *res
   2076     = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr;
   2077 
   2078   (void) cls;
   2079   if (json_is_string (root))
   2080   {
   2081     const char *str;
   2082 
   2083     str = json_string_value (root);
   2084     if (NULL == str)
   2085     {
   2086       GNUNET_break_op (0);
   2087       return GNUNET_SYSERR;
   2088     }
   2089     for (unsigned int i = 0; NULL != lt[i].name; i++)
   2090     {
   2091       if (0 == strcasecmp (str,
   2092                            lt[i].name))
   2093       {
   2094         *res = lt[i].val;
   2095         return GNUNET_OK;
   2096       }
   2097     }
   2098     GNUNET_break_op (0);
   2099   }
   2100   if (json_is_integer (root))
   2101   {
   2102     json_int_t val;
   2103 
   2104     val = json_integer_value (root);
   2105     for (unsigned int i = 0; NULL != lt[i].name; i++)
   2106     {
   2107       if (val == lt[i].val)
   2108       {
   2109         *res = lt[i].val;
   2110         return GNUNET_OK;
   2111       }
   2112     }
   2113     GNUNET_break_op (0);
   2114     return GNUNET_SYSERR;
   2115   }
   2116   GNUNET_break_op (0);
   2117   return GNUNET_SYSERR;
   2118 }
   2119 
   2120 
   2121 struct GNUNET_JSON_Specification
   2122 TALER_JSON_spec_otp_type (const char *name,
   2123                           enum TALER_MerchantConfirmationAlgorithm *mca)
   2124 {
   2125   struct GNUNET_JSON_Specification ret = {
   2126     .parser = &parse_otp_type,
   2127     .field = name,
   2128     .ptr = mca
   2129   };
   2130 
   2131   *mca = TALER_MCA_NONE;
   2132   return ret;
   2133 }
   2134 
   2135 
   2136 /**
   2137  * Parse given JSON object to `enum TALER_KYCLOGIC_KycTriggerEvent`
   2138  *
   2139  * @param cls closure, NULL
   2140  * @param root the json object representing data
   2141  * @param[out] spec where to write the data
   2142  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   2143  */
   2144 static enum GNUNET_GenericReturnValue
   2145 parse_kycte (void *cls,
   2146              json_t *root,
   2147              struct GNUNET_JSON_Specification *spec)
   2148 {
   2149   static const struct Entry
   2150   {
   2151     const char *name;
   2152     enum TALER_KYCLOGIC_KycTriggerEvent val;
   2153   } lt [] = {
   2154     { .name = "NONE",
   2155       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   2156     { .name = "WITHDRAW",
   2157       .val = TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
   2158     { .name = "DEPOSIT",
   2159       .val = TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
   2160     { .name = "MERGE",
   2161       .val = TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
   2162     { .name = "BALANCE",
   2163       .val = TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
   2164     { .name = "CLOSE",
   2165       .val = TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
   2166     { .name = "AGGREGATE",
   2167       .val = TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE },
   2168     { .name = "TRANSACTION",
   2169       .val = TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION },
   2170     { .name = "REFUND",
   2171       .val = TALER_KYCLOGIC_KYC_TRIGGER_REFUND },
   2172     { .name = NULL,
   2173       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   2174   };
   2175   enum TALER_KYCLOGIC_KycTriggerEvent *res
   2176     = (enum TALER_KYCLOGIC_KycTriggerEvent *) spec->ptr;
   2177 
   2178   (void) cls;
   2179   if (json_is_string (root))
   2180   {
   2181     const char *str;
   2182 
   2183     str = json_string_value (root);
   2184     if (NULL == str)
   2185     {
   2186       GNUNET_break_op (0);
   2187       return GNUNET_SYSERR;
   2188     }
   2189     for (unsigned int i = 0; NULL != lt[i].name; i++)
   2190     {
   2191       if (0 == strcasecmp (str,
   2192                            lt[i].name))
   2193       {
   2194         *res = lt[i].val;
   2195         return GNUNET_OK;
   2196       }
   2197     }
   2198     GNUNET_break_op (0);
   2199     return GNUNET_SYSERR;
   2200   }
   2201   if (json_is_integer (root))
   2202   {
   2203     json_int_t val;
   2204 
   2205     val = json_integer_value (root);
   2206     for (unsigned int i = 0; NULL != lt[i].name; i++)
   2207     {
   2208       if (val == lt[i].val)
   2209       {
   2210         *res = lt[i].val;
   2211         return GNUNET_OK;
   2212       }
   2213     }
   2214     GNUNET_break_op (0);
   2215     return GNUNET_SYSERR;
   2216   }
   2217   GNUNET_break_op (0);
   2218   return GNUNET_SYSERR;
   2219 }
   2220 
   2221 
   2222 struct GNUNET_JSON_Specification
   2223 TALER_JSON_spec_kycte (const char *name,
   2224                        enum TALER_KYCLOGIC_KycTriggerEvent *kte)
   2225 {
   2226   struct GNUNET_JSON_Specification ret = {
   2227     .parser = &parse_kycte,
   2228     .field = name,
   2229     .ptr = kte
   2230   };
   2231 
   2232   *kte = TALER_KYCLOGIC_KYC_TRIGGER_NONE;
   2233   return ret;
   2234 }
   2235 
   2236 
   2237 /**
   2238  * Parser combinator of a tuple of parsers, for parsing
   2239  * an array of expected size and element types.
   2240  *
   2241  * @param cls closure, array of specs, NULL terminated
   2242  * @param root the json root
   2243  * @param[out] spec where to write the data
   2244  */
   2245 static enum GNUNET_GenericReturnValue
   2246 parse_tuple_of (void *cls,
   2247                 json_t *root,
   2248                 struct GNUNET_JSON_Specification *spec)
   2249 {
   2250   struct GNUNET_JSON_Specification *specs = cls;
   2251   static size_t max_specs = 100;
   2252   bool found_end = false;
   2253 
   2254   enum GNUNET_GenericReturnValue ret;
   2255 
   2256   if (! json_is_array (root))
   2257   {
   2258     return GNUNET_SYSERR;
   2259   }
   2260 
   2261   {
   2262     size_t num;
   2263     for (num = 0; num< max_specs; num++)
   2264     {
   2265       if (NULL == specs[num].parser)
   2266       {
   2267         found_end = true;
   2268         break;
   2269       }
   2270     }
   2271     GNUNET_assert (found_end);
   2272 
   2273     if (num != json_array_size (root))
   2274     {
   2275       GNUNET_break_op (0);
   2276       return GNUNET_SYSERR;
   2277     }
   2278   }
   2279 
   2280   {
   2281     json_t *j_entry;
   2282     size_t idx;
   2283 
   2284     json_array_foreach (root, idx, j_entry) {
   2285       ret = GNUNET_JSON_parse (j_entry,
   2286                                &specs[idx],
   2287                                NULL,
   2288                                NULL);
   2289       if (GNUNET_OK != ret)
   2290       {
   2291         GNUNET_break_op (0);
   2292         return GNUNET_SYSERR;
   2293       }
   2294     }
   2295   }
   2296 
   2297   return GNUNET_OK;
   2298 }
   2299 
   2300 
   2301 struct GNUNET_JSON_Specification
   2302 TALER_JSON_spec_tuple_of (
   2303   const char *field,
   2304   struct GNUNET_JSON_Specification specs[])
   2305 {
   2306   struct GNUNET_JSON_Specification ret = {
   2307     .parser = &parse_tuple_of,
   2308     .field = field,
   2309     .cls = specs
   2310   };
   2311 
   2312   return ret;
   2313 }
   2314 
   2315 
   2316 /**
   2317  * Parser for an array of unknown length but
   2318  * of elements of the same type with the same
   2319  * fixed length.
   2320  *
   2321  * @param cls closure, entry_size
   2322  * @param root the json root
   2323  * @param spec the output spec
   2324  */
   2325 static enum GNUNET_GenericReturnValue
   2326 parse_array_fixed (void *cls,
   2327                    json_t *root,
   2328                    struct GNUNET_JSON_Specification *spec)
   2329 {
   2330   enum GNUNET_GenericReturnValue ret;
   2331   size_t entry_size = (size_t) cls;
   2332   size_t num_entries;
   2333 
   2334   GNUNET_assert (0< entry_size);
   2335   num_entries = spec->ptr_size / entry_size;
   2336   GNUNET_assert (0 < num_entries);
   2337 
   2338 
   2339   if (! json_is_array (root))
   2340   {
   2341     GNUNET_break_op (0);
   2342     return GNUNET_SYSERR;
   2343   }
   2344   if (num_entries != json_array_size (root))
   2345   {
   2346     GNUNET_break_op (0);
   2347     return GNUNET_SYSERR;
   2348   }
   2349 
   2350   {
   2351     json_t *j_entry;
   2352     size_t idx;
   2353     void *ptr = spec->ptr;
   2354     void *end = spec->ptr + spec->ptr_size;
   2355 
   2356     json_array_foreach (root, idx, j_entry) {
   2357       struct GNUNET_JSON_Specification esp[] = {
   2358         GNUNET_JSON_spec_fixed (NULL,
   2359                                 ptr,
   2360                                 entry_size),
   2361         GNUNET_JSON_spec_end ()
   2362       };
   2363       GNUNET_assert (ptr < end);
   2364       ret = GNUNET_JSON_parse (j_entry,
   2365                                esp,
   2366                                NULL,
   2367                                NULL);
   2368       if (GNUNET_OK != ret)
   2369       {
   2370         GNUNET_break_op (0);
   2371         return GNUNET_SYSERR;
   2372       }
   2373       ptr += entry_size;
   2374     }
   2375   }
   2376   return GNUNET_OK;
   2377 }
   2378 
   2379 
   2380 struct GNUNET_JSON_Specification
   2381 TALER_JSON_spec_array_fixed (
   2382   const char *field,
   2383   size_t num_entries,
   2384   void *entries,
   2385   size_t entry_size)
   2386 {
   2387   struct GNUNET_JSON_Specification ret = {
   2388     .parser = &parse_array_fixed,
   2389     .ptr = entries,
   2390     .ptr_size = entry_size * num_entries,
   2391     .field = field,
   2392     .cls = (void *) entry_size,
   2393   };
   2394 
   2395   GNUNET_assert ((num_entries <= 1) ||
   2396                  (entry_size * num_entries > entry_size));
   2397   return ret;
   2398 }
   2399 
   2400 
   2401 /**
   2402  * Closure for the parser of arrays of fixed size data
   2403  * of unknown array length
   2404  */
   2405 struct closure_array_of_data
   2406 {
   2407   /**
   2408    * Fixed (known) size per entry
   2409    */
   2410   size_t entry_size;
   2411 
   2412   /**
   2413    * Pointer where to put the number of elements
   2414    * allocated, i.e. the number of elements in the
   2415    * json array.
   2416    */
   2417   size_t *num_entries;
   2418 };
   2419 
   2420 /**
   2421  * Parser for an array of data of known element size,
   2422  * but unknown array length
   2423  */
   2424 static enum GNUNET_GenericReturnValue
   2425 parse_array_of_data (void *cls,
   2426                      json_t *root,
   2427                      struct GNUNET_JSON_Specification *spec)
   2428 {
   2429   enum GNUNET_GenericReturnValue ret;
   2430   struct closure_array_of_data *info = cls;
   2431   size_t num_entries;
   2432 
   2433   if (! json_is_array (root))
   2434   {
   2435     GNUNET_break_op (0);
   2436     return GNUNET_SYSERR;
   2437   }
   2438   num_entries = json_array_size (root);
   2439   *info->num_entries = num_entries;
   2440   if (0 == num_entries)
   2441   {
   2442     *(char **) spec->ptr = NULL;
   2443     return GNUNET_OK;
   2444   }
   2445 
   2446   spec->ptr_size = num_entries * info->entry_size;
   2447   GNUNET_assert (spec->ptr_size > num_entries);
   2448   *((char **) spec->ptr) = GNUNET_malloc (spec->ptr_size);
   2449 
   2450   {
   2451     json_t *j_entry;
   2452     size_t idx;
   2453     char *ptr = *(char **) spec->ptr;
   2454     char *end = ptr + spec->ptr_size;
   2455 
   2456     json_array_foreach (root, idx, j_entry) {
   2457       struct GNUNET_JSON_Specification esp[] = {
   2458         GNUNET_JSON_spec_fixed (NULL,
   2459                                 ptr,
   2460                                 info->entry_size),
   2461         GNUNET_JSON_spec_end ()
   2462       };
   2463       GNUNET_assert (ptr < end);
   2464       ret = GNUNET_JSON_parse (j_entry,
   2465                                esp,
   2466                                NULL,
   2467                                NULL);
   2468       if (GNUNET_OK != ret)
   2469       {
   2470         GNUNET_break_op (0);
   2471         return GNUNET_SYSERR;
   2472       }
   2473       ptr += info->entry_size;
   2474     }
   2475   }
   2476   return GNUNET_OK;
   2477 }
   2478 
   2479 
   2480 /**
   2481  * Cleanup data left from parsing an array of fixed size (but unknown length).
   2482  *
   2483  * @param cls closure_of_array_data
   2484  * @param[out] spec where to free the data
   2485  */
   2486 static void
   2487 cleaner_array_of_data (void *cls,
   2488                        struct GNUNET_JSON_Specification *spec)
   2489 {
   2490   struct closure_array_of_data *info = cls;
   2491 
   2492   GNUNET_free (*(void **) spec->ptr);
   2493   GNUNET_free (info);
   2494 }
   2495 
   2496 
   2497 struct GNUNET_JSON_Specification
   2498 TALER_JSON_spec_array_of_data (
   2499   const char *field,
   2500   size_t entry_size,
   2501   size_t *num_entries,
   2502   void **entries)
   2503 {
   2504   struct closure_array_of_data *cls;
   2505 
   2506   GNUNET_assert (0< entry_size);
   2507   *entries = NULL;
   2508   *num_entries = 0;
   2509   cls = GNUNET_new (struct closure_array_of_data);
   2510   cls->num_entries = num_entries;
   2511   cls->entry_size = entry_size;
   2512   {
   2513     struct GNUNET_JSON_Specification ret = {
   2514       .parser = &parse_array_of_data,
   2515       .ptr = entries,
   2516       .field = field,
   2517       .cleaner = &cleaner_array_of_data,
   2518       .cls = (void *) cls,
   2519     };
   2520 
   2521     return ret;
   2522   }
   2523 }
   2524 
   2525 
   2526 struct GNUNET_JSON_Specification
   2527 TALER_JSON_spec_array_of_denom_pub_h (
   2528   const char *field,
   2529   size_t *num_entries,
   2530   struct TALER_DenominationHashP **entries)
   2531 {
   2532   *num_entries = 0;
   2533   *entries = NULL;
   2534   return TALER_JSON_spec_array_of_data (
   2535     field,
   2536     sizeof (struct TALER_DenominationHashP),
   2537     num_entries,
   2538     (void **) entries);
   2539 }
   2540 
   2541 
   2542 /**
   2543  * Parser for an array of blinded denomination signatures,
   2544  * of unknown array length
   2545  */
   2546 static enum GNUNET_GenericReturnValue
   2547 parse_array_of_blinded_denom_sigs (void *cls,
   2548                                    json_t *root,
   2549                                    struct GNUNET_JSON_Specification *spec)
   2550 {
   2551   enum GNUNET_GenericReturnValue ret;
   2552   struct TALER_BlindedDenominationSignature *sigs = spec->ptr;
   2553   size_t expected_num_entries = (size_t) cls;
   2554   size_t num_entries;
   2555 
   2556   if (! json_is_array (root))
   2557   {
   2558     GNUNET_break_op (0);
   2559     return GNUNET_SYSERR;
   2560   }
   2561   num_entries = json_array_size (root);
   2562   if (num_entries != expected_num_entries)
   2563   {
   2564     GNUNET_break_op (0);
   2565     return GNUNET_SYSERR;
   2566   }
   2567 
   2568   {
   2569     json_t *j_entry;
   2570     size_t idx;
   2571     struct TALER_BlindedDenominationSignature *ptr = sigs;
   2572 
   2573     json_array_foreach (root, idx, j_entry) {
   2574       struct GNUNET_JSON_Specification esp[] = {
   2575         TALER_JSON_spec_blinded_denom_sig (NULL,
   2576                                            ptr),
   2577         GNUNET_JSON_spec_end ()
   2578       };
   2579       ret = GNUNET_JSON_parse (j_entry,
   2580                                esp,
   2581                                NULL,
   2582                                NULL);
   2583       if (GNUNET_OK != ret)
   2584       {
   2585         GNUNET_break_op (0);
   2586         for (size_t i = 0; i < idx; i++)
   2587         {
   2588           TALER_blinded_denom_sig_free (&sigs[i]);
   2589           sigs[i].blinded_sig = NULL;
   2590         }
   2591         return GNUNET_SYSERR;
   2592       }
   2593       ptr++;
   2594     }
   2595   }
   2596   return GNUNET_OK;
   2597 }
   2598 
   2599 
   2600 /**
   2601  * Cleanup data left from parsing an array of blinded signatures.
   2602  *
   2603  * @param cls pointer to a size_t with the length of the array
   2604  * @param[out] spec where to free the data
   2605  */
   2606 static void
   2607 cleaner_array_of_blinded_denom_sigs (
   2608   void *cls,
   2609   struct GNUNET_JSON_Specification *spec)
   2610 {
   2611   struct TALER_BlindedDenominationSignature *sigs = spec->ptr;
   2612   size_t num_entries = (size_t) cls;
   2613 
   2614   for (size_t i = 0; i < num_entries; i++)
   2615   {
   2616     if (NULL != sigs[i].blinded_sig)
   2617     {
   2618       TALER_blinded_denom_sig_free (&sigs[i]);
   2619       sigs[i].blinded_sig = NULL;
   2620     }
   2621   }
   2622 }
   2623 
   2624 
   2625 struct GNUNET_JSON_Specification
   2626 TALER_JSON_spec_array_of_blinded_denom_sigs (
   2627   const char *field,
   2628   size_t num_entries,
   2629   struct TALER_BlindedDenominationSignature *entries)
   2630 {
   2631   struct GNUNET_JSON_Specification ret = {
   2632     .parser = &parse_array_of_blinded_denom_sigs,
   2633     .ptr = entries,
   2634     .field = field,
   2635     .cleaner = &cleaner_array_of_blinded_denom_sigs,
   2636     .cls = (void *) num_entries,
   2637   };
   2638 
   2639   for (size_t i = 0; i<num_entries; i++)
   2640     entries[i].blinded_sig = NULL;
   2641   return ret;
   2642 }
   2643 
   2644 
   2645 /* end of json/json_helper.c */