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 (63184B)


      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       denom_pub->bsign_pub_key = bsign_pub;
    888       return GNUNET_OK;
    889     }
    890   case GNUNET_CRYPTO_BSA_CS:
    891     {
    892       struct GNUNET_JSON_Specification ispec[] = {
    893         GNUNET_JSON_spec_fixed ("cs_pub",
    894                                 &bsign_pub->details.cs_public_key,
    895                                 sizeof (bsign_pub->details.cs_public_key)),
    896         GNUNET_JSON_spec_end ()
    897       };
    898 
    899       if (GNUNET_OK !=
    900           GNUNET_JSON_parse (root,
    901                              ispec,
    902                              &emsg,
    903                              &eline))
    904       {
    905         GNUNET_break_op (0);
    906         GNUNET_free (bsign_pub);
    907         return GNUNET_SYSERR;
    908       }
    909       denom_pub->bsign_pub_key = bsign_pub;
    910       return GNUNET_OK;
    911     }
    912   }
    913   GNUNET_break_op (0);
    914   GNUNET_free (bsign_pub);
    915   return GNUNET_SYSERR;
    916 }
    917 
    918 
    919 /**
    920  * Cleanup data left from parsing denomination public key.
    921  *
    922  * @param cls closure, NULL
    923  * @param[out] spec where to free the data
    924  */
    925 static void
    926 clean_denom_pub (void *cls,
    927                  struct GNUNET_JSON_Specification *spec)
    928 {
    929   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
    930 
    931   (void) cls;
    932   TALER_denom_pub_free (denom_pub);
    933 }
    934 
    935 
    936 struct GNUNET_JSON_Specification
    937 TALER_JSON_spec_denom_pub (const char *field,
    938                            struct TALER_DenominationPublicKey *pk)
    939 {
    940   struct GNUNET_JSON_Specification ret = {
    941     .parser = &parse_denom_pub,
    942     .cleaner = &clean_denom_pub,
    943     .field = field,
    944     .ptr = pk
    945   };
    946 
    947   pk->bsign_pub_key = NULL;
    948   return ret;
    949 }
    950 
    951 
    952 /**
    953  * Parse given JSON object to token issue public key.
    954  *
    955  * @param cls closure, NULL
    956  * @param root the json object representing data
    957  * @param[out] spec where to write the data
    958  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    959  */
    960 static enum GNUNET_GenericReturnValue
    961 parse_token_pub (void *cls,
    962                  json_t *root,
    963                  struct GNUNET_JSON_Specification *spec)
    964 {
    965   struct TALER_TokenIssuePublicKey *token_pub = spec->ptr;
    966   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
    967   const char *cipher;
    968   struct GNUNET_JSON_Specification dspec[] = {
    969     GNUNET_JSON_spec_string ("cipher",
    970                              &cipher),
    971     GNUNET_JSON_spec_end ()
    972   };
    973   const char *emsg;
    974   unsigned int eline;
    975 
    976   (void) cls;
    977   if (GNUNET_OK !=
    978       GNUNET_JSON_parse (root,
    979                          dspec,
    980                          &emsg,
    981                          &eline))
    982   {
    983     GNUNET_break_op (0);
    984     return GNUNET_SYSERR;
    985   }
    986 
    987   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    988   bsign_pub->rc = 1;
    989   bsign_pub->cipher = string_to_cipher (cipher);
    990   switch (bsign_pub->cipher)
    991   {
    992   case GNUNET_CRYPTO_BSA_INVALID:
    993     break;
    994   case GNUNET_CRYPTO_BSA_RSA:
    995     {
    996       struct GNUNET_JSON_Specification ispec[] = {
    997         GNUNET_JSON_spec_rsa_public_key (
    998           "rsa_pub",
    999           &bsign_pub->details.rsa_public_key),
   1000         GNUNET_JSON_spec_end ()
   1001       };
   1002 
   1003       if (GNUNET_OK !=
   1004           GNUNET_JSON_parse (root,
   1005                              ispec,
   1006                              &emsg,
   1007                              &eline))
   1008       {
   1009         GNUNET_break_op (0);
   1010         GNUNET_free (bsign_pub);
   1011         return GNUNET_SYSERR;
   1012       }
   1013       GNUNET_CRYPTO_rsa_public_key_hash (bsign_pub->details.rsa_public_key,
   1014                                          &bsign_pub->pub_key_hash);
   1015       token_pub->public_key = bsign_pub;
   1016       return GNUNET_OK;
   1017     }
   1018   case GNUNET_CRYPTO_BSA_CS:
   1019     {
   1020       struct GNUNET_JSON_Specification ispec[] = {
   1021         GNUNET_JSON_spec_fixed ("cs_pub",
   1022                                 &bsign_pub->details.cs_public_key,
   1023                                 sizeof (bsign_pub->details.cs_public_key)),
   1024         GNUNET_JSON_spec_end ()
   1025       };
   1026 
   1027       if (GNUNET_OK !=
   1028           GNUNET_JSON_parse (root,
   1029                              ispec,
   1030                              &emsg,
   1031                              &eline))
   1032       {
   1033         GNUNET_break_op (0);
   1034         GNUNET_free (bsign_pub);
   1035         return GNUNET_SYSERR;
   1036       }
   1037       GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
   1038                           sizeof(bsign_pub->details.cs_public_key),
   1039                           &bsign_pub->pub_key_hash);
   1040       token_pub->public_key = bsign_pub;
   1041       return GNUNET_OK;
   1042     }
   1043   }
   1044   GNUNET_break_op (0);
   1045   GNUNET_free (bsign_pub);
   1046   return GNUNET_SYSERR;
   1047 }
   1048 
   1049 
   1050 /**
   1051  * Cleanup data left from parsing token issue public key.
   1052  *
   1053  * @param cls closure, NULL
   1054  * @param[out] spec where to free the data
   1055  */
   1056 static void
   1057 clean_token_pub (void *cls,
   1058                  struct GNUNET_JSON_Specification *spec)
   1059 {
   1060   struct TALER_TokenIssuePublicKey *token_pub = spec->ptr;
   1061 
   1062   (void) cls;
   1063   TALER_token_issue_pub_free (token_pub);
   1064 }
   1065 
   1066 
   1067 struct GNUNET_JSON_Specification
   1068 TALER_JSON_spec_token_pub (const char *field,
   1069                            struct TALER_TokenIssuePublicKey *pk)
   1070 {
   1071   struct GNUNET_JSON_Specification ret = {
   1072     .field = field,
   1073     .parser = &parse_token_pub,
   1074     .cleaner = &clean_token_pub,
   1075     .ptr = pk
   1076   };
   1077 
   1078   pk->public_key = NULL;
   1079   return ret;
   1080 }
   1081 
   1082 
   1083 /**
   1084  * Parse given JSON object partially into a denomination public key.
   1085  *
   1086  * Depending on the cipher in cls, it parses the corresponding public key type.
   1087  *
   1088  * @param cls closure, enum GNUNET_CRYPTO_BlindSignatureAlgorithm
   1089  * @param root the json object representing data
   1090  * @param[out] spec where to write the data
   1091  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1092  */
   1093 static enum GNUNET_GenericReturnValue
   1094 parse_denom_pub_cipher (void *cls,
   1095                         json_t *root,
   1096                         struct GNUNET_JSON_Specification *spec)
   1097 {
   1098   struct TALER_DenominationPublicKey *denom_pub = spec->ptr;
   1099   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher =
   1100     (enum GNUNET_CRYPTO_BlindSignatureAlgorithm) (long) cls;
   1101   struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
   1102   const char *emsg;
   1103   unsigned int eline;
   1104 
   1105   bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
   1106   bsign_pub->cipher = cipher;
   1107   bsign_pub->rc = 1;
   1108   switch (cipher)
   1109   {
   1110   case GNUNET_CRYPTO_BSA_INVALID:
   1111     break;
   1112   case GNUNET_CRYPTO_BSA_RSA:
   1113     {
   1114       struct GNUNET_JSON_Specification ispec[] = {
   1115         GNUNET_JSON_spec_rsa_public_key (
   1116           "rsa_pub",
   1117           &bsign_pub->details.rsa_public_key),
   1118         GNUNET_JSON_spec_end ()
   1119       };
   1120 
   1121       if (GNUNET_OK !=
   1122           GNUNET_JSON_parse (root,
   1123                              ispec,
   1124                              &emsg,
   1125                              &eline))
   1126       {
   1127         GNUNET_break_op (0);
   1128         GNUNET_free (bsign_pub);
   1129         return GNUNET_SYSERR;
   1130       }
   1131       denom_pub->bsign_pub_key = bsign_pub;
   1132       return GNUNET_OK;
   1133     }
   1134   case GNUNET_CRYPTO_BSA_CS:
   1135     {
   1136       struct GNUNET_JSON_Specification ispec[] = {
   1137         GNUNET_JSON_spec_fixed ("cs_pub",
   1138                                 &bsign_pub->details.cs_public_key,
   1139                                 sizeof (bsign_pub->details.cs_public_key)),
   1140         GNUNET_JSON_spec_end ()
   1141       };
   1142 
   1143       if (GNUNET_OK !=
   1144           GNUNET_JSON_parse (root,
   1145                              ispec,
   1146                              &emsg,
   1147                              &eline))
   1148       {
   1149         GNUNET_break_op (0);
   1150         GNUNET_free (bsign_pub);
   1151         return GNUNET_SYSERR;
   1152       }
   1153       denom_pub->bsign_pub_key = bsign_pub;
   1154       return GNUNET_OK;
   1155     }
   1156   }
   1157   GNUNET_break_op (0);
   1158   GNUNET_free (bsign_pub);
   1159   return GNUNET_SYSERR;
   1160 }
   1161 
   1162 
   1163 struct GNUNET_JSON_Specification
   1164 TALER_JSON_spec_denom_pub_cipher (
   1165   const char *field,
   1166   enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher,
   1167   struct TALER_DenominationPublicKey *pk)
   1168 {
   1169   struct GNUNET_JSON_Specification ret = {
   1170     .parser = &parse_denom_pub_cipher,
   1171     .cleaner = &clean_denom_pub,
   1172     .field = field,
   1173     .cls = (void *) cipher,
   1174     .ptr = pk
   1175   };
   1176 
   1177   pk->bsign_pub_key = NULL;
   1178   return ret;
   1179 }
   1180 
   1181 
   1182 struct GNUNET_JSON_Specification
   1183 TALER_JSON_spec_denom_sig (const char *field,
   1184                            struct TALER_DenominationSignature *sig)
   1185 {
   1186   sig->unblinded_sig = NULL;
   1187   return GNUNET_JSON_spec_unblinded_signature (field,
   1188                                                &sig->unblinded_sig);
   1189 }
   1190 
   1191 
   1192 struct GNUNET_JSON_Specification
   1193 TALER_JSON_spec_blinded_denom_sig (
   1194   const char *field,
   1195   struct TALER_BlindedDenominationSignature *sig)
   1196 {
   1197   sig->blinded_sig = NULL;
   1198   return GNUNET_JSON_spec_blinded_signature (field,
   1199                                              &sig->blinded_sig);
   1200 }
   1201 
   1202 
   1203 struct GNUNET_JSON_Specification
   1204 TALER_JSON_spec_blinded_planchet (
   1205   const char *field,
   1206   struct TALER_BlindedPlanchet *blinded_planchet)
   1207 {
   1208   blinded_planchet->blinded_message = NULL;
   1209   return GNUNET_JSON_spec_blinded_message (field,
   1210                                            &blinded_planchet->blinded_message);
   1211 }
   1212 
   1213 
   1214 /**
   1215  * Parse given JSON object to exchange withdraw values (/csr).
   1216  *
   1217  * @param cls closure, NULL
   1218  * @param root the json object representing data
   1219  * @param[out] spec where to write the data
   1220  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1221  */
   1222 static enum GNUNET_GenericReturnValue
   1223 parse_exchange_blinding_values (void *cls,
   1224                                 json_t *root,
   1225                                 struct GNUNET_JSON_Specification *spec)
   1226 {
   1227   struct TALER_ExchangeBlindingValues *ewv = spec->ptr;
   1228   struct GNUNET_CRYPTO_BlindingInputValues *bi;
   1229   const char *cipher;
   1230   struct GNUNET_JSON_Specification dspec[] = {
   1231     GNUNET_JSON_spec_string ("cipher",
   1232                              &cipher),
   1233     GNUNET_JSON_spec_end ()
   1234   };
   1235   const char *emsg;
   1236   unsigned int eline;
   1237   enum GNUNET_CRYPTO_BlindSignatureAlgorithm ci;
   1238 
   1239   (void) cls;
   1240   if (GNUNET_OK !=
   1241       GNUNET_JSON_parse (root,
   1242                          dspec,
   1243                          &emsg,
   1244                          &eline))
   1245   {
   1246     GNUNET_break_op (0);
   1247     return GNUNET_SYSERR;
   1248   }
   1249   ci = string_to_cipher (cipher);
   1250   switch (ci)
   1251   {
   1252   case GNUNET_CRYPTO_BSA_INVALID:
   1253     break;
   1254   case GNUNET_CRYPTO_BSA_RSA:
   1255     ewv->blinding_inputs = TALER_denom_ewv_rsa_singleton ()->blinding_inputs;
   1256     return GNUNET_OK;
   1257   case GNUNET_CRYPTO_BSA_CS:
   1258     bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
   1259     bi->cipher = GNUNET_CRYPTO_BSA_CS;
   1260     bi->rc = 1;
   1261     {
   1262       struct GNUNET_JSON_Specification ispec[] = {
   1263         GNUNET_JSON_spec_fixed (
   1264           "r_pub_0",
   1265           &bi->details.cs_values.r_pub[0],
   1266           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
   1267         GNUNET_JSON_spec_fixed (
   1268           "r_pub_1",
   1269           &bi->details.cs_values.r_pub[1],
   1270           sizeof (struct GNUNET_CRYPTO_CsRPublic)),
   1271         GNUNET_JSON_spec_end ()
   1272       };
   1273 
   1274       if (GNUNET_OK !=
   1275           GNUNET_JSON_parse (root,
   1276                              ispec,
   1277                              &emsg,
   1278                              &eline))
   1279       {
   1280         GNUNET_break_op (0);
   1281         GNUNET_free (bi);
   1282         return GNUNET_SYSERR;
   1283       }
   1284       ewv->blinding_inputs = bi;
   1285       return GNUNET_OK;
   1286     }
   1287   }
   1288   GNUNET_break_op (0);
   1289   return GNUNET_SYSERR;
   1290 }
   1291 
   1292 
   1293 /**
   1294  * Cleanup data left from parsing withdraw values
   1295  *
   1296  * @param cls closure, NULL
   1297  * @param[out] spec where to free the data
   1298  */
   1299 static void
   1300 clean_exchange_blinding_values (
   1301   void *cls,
   1302   struct GNUNET_JSON_Specification *spec)
   1303 {
   1304   struct TALER_ExchangeBlindingValues *ewv = spec->ptr;
   1305 
   1306   (void) cls;
   1307   TALER_denom_ewv_free (ewv);
   1308 }
   1309 
   1310 
   1311 struct GNUNET_JSON_Specification
   1312 TALER_JSON_spec_exchange_blinding_values (
   1313   const char *field,
   1314   struct TALER_ExchangeBlindingValues *ewv)
   1315 {
   1316   struct GNUNET_JSON_Specification ret = {
   1317     .parser = &parse_exchange_blinding_values,
   1318     .cleaner = &clean_exchange_blinding_values,
   1319     .field = field,
   1320     .ptr = ewv
   1321   };
   1322 
   1323   ewv->blinding_inputs = NULL;
   1324   return ret;
   1325 }
   1326 
   1327 
   1328 /**
   1329  * Closure for #parse_i18n_string.
   1330  */
   1331 struct I18nContext
   1332 {
   1333   /**
   1334    * Language pattern to match.
   1335    */
   1336   char *lp;
   1337 
   1338   /**
   1339    * Name of the field to match.
   1340    */
   1341   const char *field;
   1342 };
   1343 
   1344 
   1345 /**
   1346  * Parse given JSON object to internationalized string.
   1347  *
   1348  * @param cls closure, our `struct I18nContext *`
   1349  * @param root the json object representing data
   1350  * @param[out] spec where to write the data
   1351  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1352  */
   1353 static enum GNUNET_GenericReturnValue
   1354 parse_i18n_string (void *cls,
   1355                    json_t *root,
   1356                    struct GNUNET_JSON_Specification *spec)
   1357 {
   1358   struct I18nContext *ctx = cls;
   1359   json_t *i18n;
   1360   json_t *val;
   1361 
   1362   {
   1363     char *i18nf;
   1364 
   1365     GNUNET_asprintf (&i18nf,
   1366                      "%s_i18n",
   1367                      ctx->field);
   1368     i18n = json_object_get (root,
   1369                             i18nf);
   1370     GNUNET_free (i18nf);
   1371   }
   1372 
   1373   val = json_object_get (root,
   1374                          ctx->field);
   1375   if ( (NULL != i18n) &&
   1376        (NULL != ctx->lp) )
   1377   {
   1378     double best = 0.0;
   1379     json_t *pos;
   1380     const char *lang;
   1381 
   1382     json_object_foreach (i18n, lang, pos)
   1383     {
   1384       double score;
   1385 
   1386       score = TALER_pattern_matches (ctx->lp,
   1387                                      lang);
   1388       if (score > best)
   1389       {
   1390         best = score;
   1391         val = pos;
   1392       }
   1393     }
   1394   }
   1395 
   1396   {
   1397     const char *str;
   1398 
   1399     str = json_string_value (val);
   1400     *(const char **) spec->ptr = str;
   1401   }
   1402   return GNUNET_OK;
   1403 }
   1404 
   1405 
   1406 /**
   1407  * Function called to clean up data from earlier parsing.
   1408  *
   1409  * @param cls closure
   1410  * @param spec our specification entry with data to clean.
   1411  */
   1412 static void
   1413 i18n_cleaner (void *cls,
   1414               struct GNUNET_JSON_Specification *spec)
   1415 {
   1416   struct I18nContext *ctx = cls;
   1417 
   1418   (void) spec;
   1419   if (NULL != ctx)
   1420   {
   1421     GNUNET_free (ctx->lp);
   1422     GNUNET_free (ctx);
   1423   }
   1424 }
   1425 
   1426 
   1427 struct GNUNET_JSON_Specification
   1428 TALER_JSON_spec_i18n_string (const char *name,
   1429                              const char *language_pattern,
   1430                              const char **strptr)
   1431 {
   1432   struct I18nContext *ctx = GNUNET_new (struct I18nContext);
   1433   struct GNUNET_JSON_Specification ret = {
   1434     .parser = &parse_i18n_string,
   1435     .cleaner = &i18n_cleaner,
   1436     .cls = ctx,
   1437     .field = NULL, /* we want the main object */
   1438     .ptr = strptr,
   1439     .ptr_size = 0,
   1440     .size_ptr = NULL
   1441   };
   1442 
   1443   ctx->lp = (NULL != language_pattern)
   1444     ? GNUNET_strdup (language_pattern)
   1445     : NULL;
   1446   ctx->field = name;
   1447   *strptr = NULL;
   1448   return ret;
   1449 }
   1450 
   1451 
   1452 struct GNUNET_JSON_Specification
   1453 TALER_JSON_spec_i18n_str (const char *name,
   1454                           const char **strptr)
   1455 {
   1456   const char *lang = getenv ("LANG");
   1457   char *dot;
   1458   char *l;
   1459   struct GNUNET_JSON_Specification ret;
   1460 
   1461   if (NULL != lang)
   1462   {
   1463     dot = strchr (lang,
   1464                   '.');
   1465     if (NULL == dot)
   1466       l = GNUNET_strdup (lang);
   1467     else
   1468       l = GNUNET_strndup (lang,
   1469                           dot - lang);
   1470   }
   1471   else
   1472   {
   1473     l = NULL;
   1474   }
   1475   ret = TALER_JSON_spec_i18n_string (name,
   1476                                      l,
   1477                                      strptr);
   1478   GNUNET_free (l);
   1479   return ret;
   1480 }
   1481 
   1482 
   1483 /**
   1484  * Parse given JSON object with Taler error code.
   1485  *
   1486  * @param cls closure, NULL
   1487  * @param root the json object representing data
   1488  * @param[out] spec where to write the data
   1489  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1490  */
   1491 static enum GNUNET_GenericReturnValue
   1492 parse_ec (void *cls,
   1493           json_t *root,
   1494           struct GNUNET_JSON_Specification *spec)
   1495 {
   1496   enum TALER_ErrorCode *ec = spec->ptr;
   1497   json_int_t num;
   1498 
   1499   (void) cls;
   1500   if (! json_is_integer (root))
   1501   {
   1502     GNUNET_break_op (0);
   1503     return GNUNET_SYSERR;
   1504   }
   1505   num = json_integer_value (root);
   1506   if (num < 0)
   1507   {
   1508     GNUNET_break_op (0);
   1509     *ec = TALER_EC_INVALID;
   1510     return GNUNET_SYSERR;
   1511   }
   1512   *ec = (enum TALER_ErrorCode) num;
   1513   return GNUNET_OK;
   1514 }
   1515 
   1516 
   1517 struct GNUNET_JSON_Specification
   1518 TALER_JSON_spec_ec (const char *field,
   1519                     enum TALER_ErrorCode *ec)
   1520 {
   1521   struct GNUNET_JSON_Specification ret = {
   1522     .parser = &parse_ec,
   1523     .field = field,
   1524     .ptr = ec
   1525   };
   1526 
   1527   *ec = TALER_EC_NONE;
   1528   return ret;
   1529 }
   1530 
   1531 
   1532 /**
   1533  * Parse given JSON object to web URL.
   1534  *
   1535  * @param cls closure, NULL
   1536  * @param root the json object representing data
   1537  * @param[out] spec where to write the data
   1538  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1539  */
   1540 static enum GNUNET_GenericReturnValue
   1541 parse_web_url (void *cls,
   1542                json_t *root,
   1543                struct GNUNET_JSON_Specification *spec)
   1544 {
   1545   const char *str;
   1546 
   1547   (void) cls;
   1548   str = json_string_value (root);
   1549   if (NULL == str)
   1550   {
   1551     GNUNET_break_op (0);
   1552     return GNUNET_SYSERR;
   1553   }
   1554   if (! TALER_is_web_url (str))
   1555   {
   1556     GNUNET_break_op (0);
   1557     return GNUNET_SYSERR;
   1558   }
   1559   *(const char **) spec->ptr = str;
   1560   return GNUNET_OK;
   1561 }
   1562 
   1563 
   1564 struct GNUNET_JSON_Specification
   1565 TALER_JSON_spec_web_url (const char *field,
   1566                          const char **url)
   1567 {
   1568   struct GNUNET_JSON_Specification ret = {
   1569     .parser = &parse_web_url,
   1570     .field = field,
   1571     .ptr = url
   1572   };
   1573 
   1574   *url = NULL;
   1575   return ret;
   1576 }
   1577 
   1578 
   1579 /**
   1580  * Parse given JSON object to web URL, and make a copy.
   1581  *
   1582  * @param cls closure, NULL
   1583  * @param root the json object representing data
   1584  * @param[out] spec where to write the data
   1585  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1586  */
   1587 static enum GNUNET_GenericReturnValue
   1588 parse_web_url_copy (void *cls,
   1589                     json_t *root,
   1590                     struct GNUNET_JSON_Specification *spec)
   1591 {
   1592   const char *str;
   1593 
   1594   (void) cls;
   1595   str = json_string_value (root);
   1596   if (NULL == str)
   1597   {
   1598     GNUNET_break_op (0);
   1599     return GNUNET_SYSERR;
   1600   }
   1601   if (! TALER_is_web_url (str))
   1602   {
   1603     GNUNET_break_op (0);
   1604     return GNUNET_SYSERR;
   1605   }
   1606   *(char **) spec->ptr = GNUNET_strdup (str);
   1607   return GNUNET_OK;
   1608 }
   1609 
   1610 
   1611 struct GNUNET_JSON_Specification
   1612 TALER_JSON_spec_web_url_copy (const char *field,
   1613                               char **url)
   1614 {
   1615   struct GNUNET_JSON_Specification ret = {
   1616     .parser = &parse_web_url_copy,
   1617     .field = field,
   1618     .ptr = url
   1619   };
   1620 
   1621   *url = NULL;
   1622   return ret;
   1623 }
   1624 
   1625 
   1626 /**
   1627  * Parse given JSON object to slug.
   1628  *
   1629  * @param cls closure, NULL
   1630  * @param root the json object representing data
   1631  * @param[out] spec where to write the data
   1632  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1633  */
   1634 static enum GNUNET_GenericReturnValue
   1635 parse_slug (void *cls,
   1636             json_t *root,
   1637             struct GNUNET_JSON_Specification *spec)
   1638 {
   1639   const char *str;
   1640 
   1641   (void) cls;
   1642   str = json_string_value (root);
   1643   if (NULL == str)
   1644   {
   1645     GNUNET_break_op (0);
   1646     return GNUNET_SYSERR;
   1647   }
   1648   if (! TALER_is_slug (str))
   1649   {
   1650     GNUNET_break_op (0);
   1651     return GNUNET_SYSERR;
   1652   }
   1653   *(const char **) spec->ptr = str;
   1654   return GNUNET_OK;
   1655 }
   1656 
   1657 
   1658 struct GNUNET_JSON_Specification
   1659 TALER_JSON_spec_slug (const char *field,
   1660                       const char **slug)
   1661 {
   1662   struct GNUNET_JSON_Specification ret = {
   1663     .parser = &parse_slug,
   1664     .field = field,
   1665     .ptr = slug
   1666   };
   1667 
   1668   *slug = NULL;
   1669   return ret;
   1670 }
   1671 
   1672 
   1673 /**
   1674  * Parse given JSON object to slug.
   1675  *
   1676  * @param cls closure, NULL
   1677  * @param root the json object representing data
   1678  * @param[out] spec where to write the data
   1679  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1680  */
   1681 static enum GNUNET_GenericReturnValue
   1682 parse_slug_copy (void *cls,
   1683                  json_t *root,
   1684                  struct GNUNET_JSON_Specification *spec)
   1685 {
   1686   const char *str;
   1687 
   1688   (void) cls;
   1689   str = json_string_value (root);
   1690   if (NULL == str)
   1691   {
   1692     GNUNET_break_op (0);
   1693     return GNUNET_SYSERR;
   1694   }
   1695   if (! TALER_is_slug (str))
   1696   {
   1697     GNUNET_break_op (0);
   1698     return GNUNET_SYSERR;
   1699   }
   1700   *(char **) spec->ptr = GNUNET_strdup (str);
   1701   return GNUNET_OK;
   1702 }
   1703 
   1704 
   1705 struct GNUNET_JSON_Specification
   1706 TALER_JSON_spec_slug_copy (const char *field,
   1707                            char **slug)
   1708 {
   1709   struct GNUNET_JSON_Specification ret = {
   1710     .parser = &parse_slug_copy,
   1711     .field = field,
   1712     .ptr = slug
   1713   };
   1714 
   1715   *slug = NULL;
   1716   return ret;
   1717 }
   1718 
   1719 
   1720 /**
   1721  * Parse given JSON object to a session ID.
   1722  *
   1723  * @param cls closure, NULL
   1724  * @param root the json object representing data
   1725  * @param[out] spec where to write the data
   1726  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1727  */
   1728 static enum GNUNET_GenericReturnValue
   1729 parse_session_id (void *cls,
   1730                   json_t *root,
   1731                   struct GNUNET_JSON_Specification *spec)
   1732 {
   1733   const char *str;
   1734 
   1735   (void) cls;
   1736   str = json_string_value (root);
   1737   if (NULL == str)
   1738   {
   1739     GNUNET_break_op (0);
   1740     return GNUNET_SYSERR;
   1741   }
   1742   if (! TALER_is_session_id (str))
   1743   {
   1744     GNUNET_break_op (0);
   1745     return GNUNET_SYSERR;
   1746   }
   1747   *(const char **) spec->ptr = str;
   1748   return GNUNET_OK;
   1749 }
   1750 
   1751 
   1752 struct GNUNET_JSON_Specification
   1753 TALER_JSON_spec_session_id (const char *field,
   1754                             const char **session_id)
   1755 {
   1756   struct GNUNET_JSON_Specification ret = {
   1757     .parser = &parse_session_id,
   1758     .field = field,
   1759     .ptr = session_id
   1760   };
   1761 
   1762   *session_id = NULL;
   1763   return ret;
   1764 }
   1765 
   1766 
   1767 /**
   1768  * Parse given JSON object to a session ID that must not be empty.
   1769  *
   1770  * @param cls closure, NULL
   1771  * @param root the json object representing data
   1772  * @param[out] spec where to write the data
   1773  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1774  */
   1775 static enum GNUNET_GenericReturnValue
   1776 parse_nonempty_session_id (void *cls,
   1777                            json_t *root,
   1778                            struct GNUNET_JSON_Specification *spec)
   1779 {
   1780   if (GNUNET_OK !=
   1781       parse_session_id (cls,
   1782                         root,
   1783                         spec))
   1784     return GNUNET_SYSERR;
   1785   if ('\0' == (*(const char **) spec->ptr)[0])
   1786   {
   1787     GNUNET_break_op (0);
   1788     return GNUNET_SYSERR;
   1789   }
   1790   return GNUNET_OK;
   1791 }
   1792 
   1793 
   1794 struct GNUNET_JSON_Specification
   1795 TALER_JSON_spec_nonempty_session_id (const char *field,
   1796                                      const char **session_id)
   1797 {
   1798   struct GNUNET_JSON_Specification ret = {
   1799     .parser = &parse_nonempty_session_id,
   1800     .field = field,
   1801     .ptr = session_id
   1802   };
   1803 
   1804   *session_id = NULL;
   1805   return ret;
   1806 }
   1807 
   1808 
   1809 /**
   1810  * Parse given JSON object to payto:// URI.
   1811  *
   1812  * @param cls closure, NULL
   1813  * @param root the json object representing data
   1814  * @param[out] spec where to write the data
   1815  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1816  */
   1817 static enum GNUNET_GenericReturnValue
   1818 parse_full_payto_uri (void *cls,
   1819                       json_t *root,
   1820                       struct GNUNET_JSON_Specification *spec)
   1821 {
   1822   struct TALER_FullPayto *payto_uri = spec->ptr;
   1823   const char *str;
   1824   char *err;
   1825 
   1826   (void) cls;
   1827   str = json_string_value (root);
   1828   if (NULL == str)
   1829   {
   1830     GNUNET_break_op (0);
   1831     return GNUNET_SYSERR;
   1832   }
   1833   payto_uri->full_payto = (char *) str;
   1834   err = TALER_payto_validate (*payto_uri);
   1835   if (NULL != err)
   1836   {
   1837     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1838                 "payto:// malformed: %s\n",
   1839                 err);
   1840     GNUNET_free (err);
   1841     payto_uri->full_payto = NULL;
   1842     return GNUNET_SYSERR;
   1843   }
   1844   return GNUNET_OK;
   1845 }
   1846 
   1847 
   1848 struct GNUNET_JSON_Specification
   1849 TALER_JSON_spec_full_payto_uri (
   1850   const char *field,
   1851   struct TALER_FullPayto *payto_uri)
   1852 {
   1853   struct GNUNET_JSON_Specification ret = {
   1854     .parser = &parse_full_payto_uri,
   1855     .field = field,
   1856     .ptr = payto_uri
   1857   };
   1858 
   1859   payto_uri->full_payto = NULL;
   1860   return ret;
   1861 }
   1862 
   1863 
   1864 /**
   1865  * Parse given JSON object to payto:// URI.
   1866  *
   1867  * @param cls closure, NULL
   1868  * @param root the json object representing data
   1869  * @param[out] spec where to write the data
   1870  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1871  */
   1872 static enum GNUNET_GenericReturnValue
   1873 parse_normalized_payto_uri (void *cls,
   1874                             json_t *root,
   1875                             struct GNUNET_JSON_Specification *spec)
   1876 {
   1877   struct TALER_NormalizedPayto *payto_uri = spec->ptr;
   1878   const char *str;
   1879 
   1880   (void) cls;
   1881   str = json_string_value (root);
   1882   if (NULL == str)
   1883   {
   1884     GNUNET_break_op (0);
   1885     return GNUNET_SYSERR;
   1886   }
   1887   payto_uri->normalized_payto = (char *) str;
   1888   {
   1889     char *err;
   1890 
   1891     err = TALER_normalized_payto_validate (*payto_uri);
   1892     if (NULL != err)
   1893     {
   1894       GNUNET_break_op (0);
   1895       GNUNET_free (err);
   1896       payto_uri->normalized_payto = NULL;
   1897       return GNUNET_SYSERR;
   1898     }
   1899   }
   1900   return GNUNET_OK;
   1901 }
   1902 
   1903 
   1904 struct GNUNET_JSON_Specification
   1905 TALER_JSON_spec_normalized_payto_uri (
   1906   const char *field,
   1907   struct TALER_NormalizedPayto *payto_uri)
   1908 {
   1909   struct GNUNET_JSON_Specification ret = {
   1910     .parser = &parse_normalized_payto_uri,
   1911     .field = field,
   1912     .ptr = payto_uri
   1913   };
   1914 
   1915   payto_uri->normalized_payto = NULL;
   1916   return ret;
   1917 }
   1918 
   1919 
   1920 /**
   1921  * Parse given JSON object with protocol version.
   1922  *
   1923  * @param cls closure, NULL
   1924  * @param root the json object representing data
   1925  * @param[out] spec where to write the data
   1926  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1927  */
   1928 static enum GNUNET_GenericReturnValue
   1929 parse_protocol_version (void *cls,
   1930                         json_t *root,
   1931                         struct GNUNET_JSON_Specification *spec)
   1932 {
   1933   struct TALER_JSON_ProtocolVersion *pv = spec->ptr;
   1934   const char *ver;
   1935   char dummy;
   1936 
   1937   (void) cls;
   1938   if (! json_is_string (root))
   1939   {
   1940     GNUNET_break_op (0);
   1941     return GNUNET_SYSERR;
   1942   }
   1943   ver = json_string_value (root);
   1944   if (3 != sscanf (ver,
   1945                    "%u:%u:%u%c",
   1946                    &pv->current,
   1947                    &pv->revision,
   1948                    &pv->age,
   1949                    &dummy))
   1950   {
   1951     GNUNET_break_op (0);
   1952     return GNUNET_SYSERR;
   1953   }
   1954   return GNUNET_OK;
   1955 }
   1956 
   1957 
   1958 struct GNUNET_JSON_Specification
   1959 TALER_JSON_spec_version (const char *field,
   1960                          struct TALER_JSON_ProtocolVersion *ver)
   1961 {
   1962   struct GNUNET_JSON_Specification ret = {
   1963     .parser = &parse_protocol_version,
   1964     .field = field,
   1965     .ptr = ver
   1966   };
   1967 
   1968   return ret;
   1969 }
   1970 
   1971 
   1972 /**
   1973  * Parse given JSON object to an OTP key.
   1974  *
   1975  * @param cls closure, NULL
   1976  * @param root the json object representing data
   1977  * @param[out] spec where to write the data
   1978  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1979  */
   1980 static enum GNUNET_GenericReturnValue
   1981 parse_otp_key (void *cls,
   1982                json_t *root,
   1983                struct GNUNET_JSON_Specification *spec)
   1984 {
   1985   const char *pos_key;
   1986 
   1987   (void) cls;
   1988   pos_key = json_string_value (root);
   1989   if (NULL == pos_key)
   1990   {
   1991     GNUNET_break_op (0);
   1992     return GNUNET_SYSERR;
   1993   }
   1994   {
   1995     size_t pos_key_length = strlen (pos_key);
   1996     void *key; /* pos_key in binary */
   1997     size_t key_len; /* length of the key */
   1998     int dret;
   1999 
   2000     key_len = pos_key_length * 5 / 8;
   2001     key = GNUNET_malloc (key_len);
   2002     dret = TALER_rfc3548_base32decode (pos_key,
   2003                                        pos_key_length,
   2004                                        key,
   2005                                        key_len);
   2006     if (-1 == dret)
   2007     {
   2008       GNUNET_free (key);
   2009       GNUNET_break_op (0);
   2010       return GNUNET_SYSERR;
   2011     }
   2012     GNUNET_free (key);
   2013   }
   2014   *(const char **) spec->ptr = pos_key;
   2015   return GNUNET_OK;
   2016 }
   2017 
   2018 
   2019 struct GNUNET_JSON_Specification
   2020 TALER_JSON_spec_otp_key (const char *name,
   2021                          const char **otp_key)
   2022 {
   2023   struct GNUNET_JSON_Specification ret = {
   2024     .parser = &parse_otp_key,
   2025     .field = name,
   2026     .ptr = otp_key
   2027   };
   2028 
   2029   *otp_key = NULL;
   2030   return ret;
   2031 }
   2032 
   2033 
   2034 /**
   2035  * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm`
   2036  *
   2037  * @param cls closure, NULL
   2038  * @param root the json object representing data
   2039  * @param[out] spec where to write the data
   2040  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   2041  */
   2042 static enum GNUNET_GenericReturnValue
   2043 parse_otp_type (void *cls,
   2044                 json_t *root,
   2045                 struct GNUNET_JSON_Specification *spec)
   2046 {
   2047   static const struct Entry
   2048   {
   2049     const char *name;
   2050     enum TALER_MerchantConfirmationAlgorithm val;
   2051   } lt [] = {
   2052     { .name = "NONE",
   2053       .val = TALER_MCA_NONE },
   2054     { .name = "TOTP_WITHOUT_PRICE",
   2055       .val = TALER_MCA_WITHOUT_PRICE },
   2056     { .name = "TOTP_WITH_PRICE",
   2057       .val = TALER_MCA_WITH_PRICE },
   2058     { .name = "ECDSA_CHALLENGE",
   2059       .val = TALER_MCA_ECDSA_CHALLENGE },
   2060     { .name = "EDDSA_CHALLENGE",
   2061       .val = TALER_MCA_EDDSA_CHALLENGE },
   2062     { .name = NULL,
   2063       .val = TALER_MCA_NONE },
   2064   };
   2065   enum TALER_MerchantConfirmationAlgorithm *res
   2066     = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr;
   2067 
   2068   (void) cls;
   2069   if (json_is_string (root))
   2070   {
   2071     const char *str;
   2072 
   2073     str = json_string_value (root);
   2074     if (NULL == str)
   2075     {
   2076       GNUNET_break_op (0);
   2077       return GNUNET_SYSERR;
   2078     }
   2079     for (unsigned int i = 0; NULL != lt[i].name; i++)
   2080     {
   2081       if (0 == strcasecmp (str,
   2082                            lt[i].name))
   2083       {
   2084         *res = lt[i].val;
   2085         return GNUNET_OK;
   2086       }
   2087     }
   2088     GNUNET_break_op (0);
   2089   }
   2090   if (json_is_integer (root))
   2091   {
   2092     json_int_t val;
   2093 
   2094     val = json_integer_value (root);
   2095     for (unsigned int i = 0; NULL != lt[i].name; i++)
   2096     {
   2097       if (val == lt[i].val)
   2098       {
   2099         *res = lt[i].val;
   2100         return GNUNET_OK;
   2101       }
   2102     }
   2103     GNUNET_break_op (0);
   2104     return GNUNET_SYSERR;
   2105   }
   2106   GNUNET_break_op (0);
   2107   return GNUNET_SYSERR;
   2108 }
   2109 
   2110 
   2111 struct GNUNET_JSON_Specification
   2112 TALER_JSON_spec_otp_type (const char *name,
   2113                           enum TALER_MerchantConfirmationAlgorithm *mca)
   2114 {
   2115   struct GNUNET_JSON_Specification ret = {
   2116     .parser = &parse_otp_type,
   2117     .field = name,
   2118     .ptr = mca
   2119   };
   2120 
   2121   *mca = TALER_MCA_NONE;
   2122   return ret;
   2123 }
   2124 
   2125 
   2126 /**
   2127  * Parse given JSON object to `enum TALER_KYCLOGIC_KycTriggerEvent`
   2128  *
   2129  * @param cls closure, NULL
   2130  * @param root the json object representing data
   2131  * @param[out] spec where to write the data
   2132  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   2133  */
   2134 static enum GNUNET_GenericReturnValue
   2135 parse_kycte (void *cls,
   2136              json_t *root,
   2137              struct GNUNET_JSON_Specification *spec)
   2138 {
   2139   static const struct Entry
   2140   {
   2141     const char *name;
   2142     enum TALER_KYCLOGIC_KycTriggerEvent val;
   2143   } lt [] = {
   2144     { .name = "NONE",
   2145       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   2146     { .name = "WITHDRAW",
   2147       .val = TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
   2148     { .name = "DEPOSIT",
   2149       .val = TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT },
   2150     { .name = "MERGE",
   2151       .val = TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
   2152     { .name = "BALANCE",
   2153       .val = TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
   2154     { .name = "CLOSE",
   2155       .val = TALER_KYCLOGIC_KYC_TRIGGER_RESERVE_CLOSE },
   2156     { .name = "AGGREGATE",
   2157       .val = TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE },
   2158     { .name = "TRANSACTION",
   2159       .val = TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION },
   2160     { .name = "REFUND",
   2161       .val = TALER_KYCLOGIC_KYC_TRIGGER_REFUND },
   2162     { .name = NULL,
   2163       .val = TALER_KYCLOGIC_KYC_TRIGGER_NONE },
   2164   };
   2165   enum TALER_KYCLOGIC_KycTriggerEvent *res
   2166     = (enum TALER_KYCLOGIC_KycTriggerEvent *) spec->ptr;
   2167 
   2168   (void) cls;
   2169   if (json_is_string (root))
   2170   {
   2171     const char *str;
   2172 
   2173     str = json_string_value (root);
   2174     if (NULL == str)
   2175     {
   2176       GNUNET_break_op (0);
   2177       return GNUNET_SYSERR;
   2178     }
   2179     for (unsigned int i = 0; NULL != lt[i].name; i++)
   2180     {
   2181       if (0 == strcasecmp (str,
   2182                            lt[i].name))
   2183       {
   2184         *res = lt[i].val;
   2185         return GNUNET_OK;
   2186       }
   2187     }
   2188     GNUNET_break_op (0);
   2189     return GNUNET_SYSERR;
   2190   }
   2191   if (json_is_integer (root))
   2192   {
   2193     json_int_t val;
   2194 
   2195     val = json_integer_value (root);
   2196     for (unsigned int i = 0; NULL != lt[i].name; i++)
   2197     {
   2198       if (val == lt[i].val)
   2199       {
   2200         *res = lt[i].val;
   2201         return GNUNET_OK;
   2202       }
   2203     }
   2204     GNUNET_break_op (0);
   2205     return GNUNET_SYSERR;
   2206   }
   2207   GNUNET_break_op (0);
   2208   return GNUNET_SYSERR;
   2209 }
   2210 
   2211 
   2212 struct GNUNET_JSON_Specification
   2213 TALER_JSON_spec_kycte (const char *name,
   2214                        enum TALER_KYCLOGIC_KycTriggerEvent *kte)
   2215 {
   2216   struct GNUNET_JSON_Specification ret = {
   2217     .parser = &parse_kycte,
   2218     .field = name,
   2219     .ptr = kte
   2220   };
   2221 
   2222   *kte = TALER_KYCLOGIC_KYC_TRIGGER_NONE;
   2223   return ret;
   2224 }
   2225 
   2226 
   2227 /**
   2228  * Parser combinator of a tuple of parsers, for parsing
   2229  * an array of expected size and element types.
   2230  *
   2231  * @param cls closure, array of specs, NULL terminated
   2232  * @param root the json root
   2233  * @param[out] spec where to write the data
   2234  */
   2235 static enum GNUNET_GenericReturnValue
   2236 parse_tuple_of (void *cls,
   2237                 json_t *root,
   2238                 struct GNUNET_JSON_Specification *spec)
   2239 {
   2240   struct GNUNET_JSON_Specification *specs = cls;
   2241   static size_t max_specs = 100;
   2242   bool found_end = false;
   2243 
   2244   enum GNUNET_GenericReturnValue ret;
   2245 
   2246   if (! json_is_array (root))
   2247   {
   2248     return GNUNET_SYSERR;
   2249   }
   2250 
   2251   {
   2252     size_t num;
   2253     for (num = 0; num< max_specs; num++)
   2254     {
   2255       if (NULL == specs[num].parser)
   2256       {
   2257         found_end = true;
   2258         break;
   2259       }
   2260     }
   2261     GNUNET_assert (found_end);
   2262 
   2263     if (num != json_array_size (root))
   2264     {
   2265       GNUNET_break_op (0);
   2266       return GNUNET_SYSERR;
   2267     }
   2268   }
   2269 
   2270   {
   2271     json_t *j_entry;
   2272     size_t idx;
   2273 
   2274     json_array_foreach (root, idx, j_entry) {
   2275       ret = GNUNET_JSON_parse (j_entry,
   2276                                &specs[idx],
   2277                                NULL,
   2278                                NULL);
   2279       if (GNUNET_OK != ret)
   2280       {
   2281         GNUNET_break_op (0);
   2282         return GNUNET_SYSERR;
   2283       }
   2284     }
   2285   }
   2286 
   2287   return GNUNET_OK;
   2288 }
   2289 
   2290 
   2291 struct GNUNET_JSON_Specification
   2292 TALER_JSON_spec_tuple_of (
   2293   const char *field,
   2294   struct GNUNET_JSON_Specification specs[])
   2295 {
   2296   struct GNUNET_JSON_Specification ret = {
   2297     .parser = &parse_tuple_of,
   2298     .field = field,
   2299     .cls = specs
   2300   };
   2301 
   2302   return ret;
   2303 }
   2304 
   2305 
   2306 /**
   2307  * Parser for an array of unknown length but
   2308  * of elements of the same type with the same
   2309  * fixed length.
   2310  *
   2311  * @param cls closure, entry_size
   2312  * @param root the json root
   2313  * @param spec the output spec
   2314  */
   2315 static enum GNUNET_GenericReturnValue
   2316 parse_array_fixed (void *cls,
   2317                    json_t *root,
   2318                    struct GNUNET_JSON_Specification *spec)
   2319 {
   2320   enum GNUNET_GenericReturnValue ret;
   2321   size_t entry_size = (size_t) cls;
   2322   size_t num_entries;
   2323 
   2324   GNUNET_assert (0< entry_size);
   2325   num_entries = spec->ptr_size / entry_size;
   2326   GNUNET_assert (0 < num_entries);
   2327 
   2328 
   2329   if (! json_is_array (root))
   2330   {
   2331     GNUNET_break_op (0);
   2332     return GNUNET_SYSERR;
   2333   }
   2334   if (num_entries != json_array_size (root))
   2335   {
   2336     GNUNET_break_op (0);
   2337     return GNUNET_SYSERR;
   2338   }
   2339 
   2340   {
   2341     json_t *j_entry;
   2342     size_t idx;
   2343     void *ptr = spec->ptr;
   2344     void *end = spec->ptr + spec->ptr_size;
   2345 
   2346     json_array_foreach (root, idx, j_entry) {
   2347       struct GNUNET_JSON_Specification esp[] = {
   2348         GNUNET_JSON_spec_fixed (NULL,
   2349                                 ptr,
   2350                                 entry_size),
   2351         GNUNET_JSON_spec_end ()
   2352       };
   2353       GNUNET_assert (ptr < end);
   2354       ret = GNUNET_JSON_parse (j_entry,
   2355                                esp,
   2356                                NULL,
   2357                                NULL);
   2358       if (GNUNET_OK != ret)
   2359       {
   2360         GNUNET_break_op (0);
   2361         return GNUNET_SYSERR;
   2362       }
   2363       ptr += entry_size;
   2364     }
   2365   }
   2366   return GNUNET_OK;
   2367 }
   2368 
   2369 
   2370 struct GNUNET_JSON_Specification
   2371 TALER_JSON_spec_array_fixed (
   2372   const char *field,
   2373   size_t num_entries,
   2374   void *entries,
   2375   size_t entry_size)
   2376 {
   2377   struct GNUNET_JSON_Specification ret = {
   2378     .parser = &parse_array_fixed,
   2379     .ptr = entries,
   2380     .ptr_size = entry_size * num_entries,
   2381     .field = field,
   2382     .cls = (void *) entry_size,
   2383   };
   2384 
   2385   GNUNET_assert ((num_entries <= 1) ||
   2386                  (entry_size * num_entries > entry_size));
   2387   return ret;
   2388 }
   2389 
   2390 
   2391 /**
   2392  * Closure for the parser of arrays of fixed size data
   2393  * of unknown array length
   2394  */
   2395 struct closure_array_of_data
   2396 {
   2397   /**
   2398    * Fixed (known) size per entry
   2399    */
   2400   size_t entry_size;
   2401 
   2402   /**
   2403    * Pointer where to put the number of elements
   2404    * allocated, i.e. the number of elements in the
   2405    * json array.
   2406    */
   2407   size_t *num_entries;
   2408 };
   2409 
   2410 /**
   2411  * Parser for an array of data of known element size,
   2412  * but unknown array length
   2413  */
   2414 static enum GNUNET_GenericReturnValue
   2415 parse_array_of_data (void *cls,
   2416                      json_t *root,
   2417                      struct GNUNET_JSON_Specification *spec)
   2418 {
   2419   enum GNUNET_GenericReturnValue ret;
   2420   struct closure_array_of_data *info = cls;
   2421   size_t num_entries;
   2422 
   2423   if (! json_is_array (root))
   2424   {
   2425     GNUNET_break_op (0);
   2426     return GNUNET_SYSERR;
   2427   }
   2428   num_entries = json_array_size (root);
   2429   *info->num_entries = num_entries;
   2430   if (0 == num_entries)
   2431   {
   2432     *(char **) spec->ptr = NULL;
   2433     return GNUNET_OK;
   2434   }
   2435 
   2436   spec->ptr_size = num_entries * info->entry_size;
   2437   GNUNET_assert (spec->ptr_size > num_entries);
   2438   *((char **) spec->ptr) = GNUNET_malloc (spec->ptr_size);
   2439 
   2440   {
   2441     json_t *j_entry;
   2442     size_t idx;
   2443     char *ptr = *(char **) spec->ptr;
   2444     char *end = ptr + spec->ptr_size;
   2445 
   2446     json_array_foreach (root, idx, j_entry) {
   2447       struct GNUNET_JSON_Specification esp[] = {
   2448         GNUNET_JSON_spec_fixed (NULL,
   2449                                 ptr,
   2450                                 info->entry_size),
   2451         GNUNET_JSON_spec_end ()
   2452       };
   2453       GNUNET_assert (ptr < end);
   2454       ret = GNUNET_JSON_parse (j_entry,
   2455                                esp,
   2456                                NULL,
   2457                                NULL);
   2458       if (GNUNET_OK != ret)
   2459       {
   2460         GNUNET_break_op (0);
   2461         return GNUNET_SYSERR;
   2462       }
   2463       ptr += info->entry_size;
   2464     }
   2465   }
   2466   return GNUNET_OK;
   2467 }
   2468 
   2469 
   2470 /**
   2471  * Cleanup data left from parsing an array of fixed size (but unknown length).
   2472  *
   2473  * @param cls closure_of_array_data
   2474  * @param[out] spec where to free the data
   2475  */
   2476 static void
   2477 cleaner_array_of_data (void *cls,
   2478                        struct GNUNET_JSON_Specification *spec)
   2479 {
   2480   struct closure_array_of_data *info = cls;
   2481 
   2482   GNUNET_free (*(void **) spec->ptr);
   2483   GNUNET_free (info);
   2484 }
   2485 
   2486 
   2487 struct GNUNET_JSON_Specification
   2488 TALER_JSON_spec_array_of_data (
   2489   const char *field,
   2490   size_t entry_size,
   2491   size_t *num_entries,
   2492   void **entries)
   2493 {
   2494   struct closure_array_of_data *cls;
   2495 
   2496   GNUNET_assert (0< entry_size);
   2497   *entries = NULL;
   2498   *num_entries = 0;
   2499   cls = GNUNET_new (struct closure_array_of_data);
   2500   cls->num_entries = num_entries;
   2501   cls->entry_size = entry_size;
   2502   {
   2503     struct GNUNET_JSON_Specification ret = {
   2504       .parser = &parse_array_of_data,
   2505       .ptr = entries,
   2506       .field = field,
   2507       .cleaner = &cleaner_array_of_data,
   2508       .cls = (void *) cls,
   2509     };
   2510 
   2511     return ret;
   2512   }
   2513 }
   2514 
   2515 
   2516 struct GNUNET_JSON_Specification
   2517 TALER_JSON_spec_array_of_denom_pub_h (
   2518   const char *field,
   2519   size_t *num_entries,
   2520   struct TALER_DenominationHashP **entries)
   2521 {
   2522   *num_entries = 0;
   2523   *entries = NULL;
   2524   return TALER_JSON_spec_array_of_data (
   2525     field,
   2526     sizeof (struct TALER_DenominationHashP),
   2527     num_entries,
   2528     (void **) entries);
   2529 }
   2530 
   2531 
   2532 /**
   2533  * Parser for an array of blinded denomination signatures,
   2534  * of unknown array length
   2535  */
   2536 static enum GNUNET_GenericReturnValue
   2537 parse_array_of_blinded_denom_sigs (void *cls,
   2538                                    json_t *root,
   2539                                    struct GNUNET_JSON_Specification *spec)
   2540 {
   2541   enum GNUNET_GenericReturnValue ret;
   2542   struct TALER_BlindedDenominationSignature *sigs = spec->ptr;
   2543   size_t expected_num_entries = (size_t) cls;
   2544   size_t num_entries;
   2545 
   2546   if (! json_is_array (root))
   2547   {
   2548     GNUNET_break_op (0);
   2549     return GNUNET_SYSERR;
   2550   }
   2551   num_entries = json_array_size (root);
   2552   if (num_entries != expected_num_entries)
   2553   {
   2554     GNUNET_break_op (0);
   2555     return GNUNET_SYSERR;
   2556   }
   2557 
   2558   {
   2559     json_t *j_entry;
   2560     size_t idx;
   2561     struct TALER_BlindedDenominationSignature *ptr = sigs;
   2562 
   2563     json_array_foreach (root, idx, j_entry) {
   2564       struct GNUNET_JSON_Specification esp[] = {
   2565         TALER_JSON_spec_blinded_denom_sig (NULL,
   2566                                            ptr),
   2567         GNUNET_JSON_spec_end ()
   2568       };
   2569       ret = GNUNET_JSON_parse (j_entry,
   2570                                esp,
   2571                                NULL,
   2572                                NULL);
   2573       if (GNUNET_OK != ret)
   2574       {
   2575         GNUNET_break_op (0);
   2576         for (size_t i = 0; i < idx; i++)
   2577         {
   2578           TALER_blinded_denom_sig_free (&sigs[i]);
   2579           sigs[i].blinded_sig = NULL;
   2580         }
   2581         return GNUNET_SYSERR;
   2582       }
   2583       ptr++;
   2584     }
   2585   }
   2586   return GNUNET_OK;
   2587 }
   2588 
   2589 
   2590 /**
   2591  * Cleanup data left from parsing an array of blinded signatures.
   2592  *
   2593  * @param cls pointer to a size_t with the length of the array
   2594  * @param[out] spec where to free the data
   2595  */
   2596 static void
   2597 cleaner_array_of_blinded_denom_sigs (
   2598   void *cls,
   2599   struct GNUNET_JSON_Specification *spec)
   2600 {
   2601   struct TALER_BlindedDenominationSignature *sigs = spec->ptr;
   2602   size_t num_entries = (size_t) cls;
   2603 
   2604   for (size_t i = 0; i < num_entries; i++)
   2605   {
   2606     if (NULL != sigs[i].blinded_sig)
   2607     {
   2608       TALER_blinded_denom_sig_free (&sigs[i]);
   2609       sigs[i].blinded_sig = NULL;
   2610     }
   2611   }
   2612 }
   2613 
   2614 
   2615 struct GNUNET_JSON_Specification
   2616 TALER_JSON_spec_array_of_blinded_denom_sigs (
   2617   const char *field,
   2618   size_t num_entries,
   2619   struct TALER_BlindedDenominationSignature *entries)
   2620 {
   2621   struct GNUNET_JSON_Specification ret = {
   2622     .parser = &parse_array_of_blinded_denom_sigs,
   2623     .ptr = entries,
   2624     .field = field,
   2625     .cleaner = &cleaner_array_of_blinded_denom_sigs,
   2626     .cls = (void *) num_entries,
   2627   };
   2628 
   2629   for (size_t i = 0; i<num_entries; i++)
   2630     entries[i].blinded_sig = NULL;
   2631   return ret;
   2632 }
   2633 
   2634 
   2635 /* end of json/json_helper.c */