merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

contract_parse.c (48963B)


      1 /*
      2   This file is part of TALER
      3   (C) 2024, 2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Lesser 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 util/contract_parse.c
     18  * @brief shared logic for contract terms parsing
     19  * @author Iván Ávalos
     20  * @author Christian Grothoff
     21  */
     22 #include "taler/platform.h"
     23 #include <gnunet/gnunet_common.h>
     24 #include <gnunet/gnunet_json_lib.h>
     25 #include <jansson.h>
     26 #include <stdbool.h>
     27 #include <stdint.h>
     28 #include <taler/taler_json_lib.h>
     29 #include <taler/taler_util.h>
     30 #include "taler/taler_merchant_util.h"
     31 
     32 
     33 /**
     34  * Parse merchant details of given JSON contract terms.
     35  *
     36  * @param cls closure, unused parameter
     37  * @param root the JSON object representing data
     38  * @param[out] ospec where to write the data
     39  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     40  */
     41 static enum GNUNET_GenericReturnValue
     42 parse_merchant_details (void *cls,
     43                         json_t *root,
     44                         struct GNUNET_JSON_Specification *ospec)
     45 {
     46   struct TALER_MERCHANT_Contract *contract = ospec->ptr;
     47   struct GNUNET_JSON_Specification spec[] = {
     48     GNUNET_JSON_spec_string_copy ("name",
     49                                   &contract->merchant.name),
     50     GNUNET_JSON_spec_mark_optional (
     51       GNUNET_JSON_spec_string_copy ("email",
     52                                     &contract->merchant.email),
     53       NULL),
     54     GNUNET_JSON_spec_mark_optional (
     55       GNUNET_JSON_spec_string_copy ("website",
     56                                     &contract->merchant.website),
     57       NULL),
     58     GNUNET_JSON_spec_mark_optional (
     59       GNUNET_JSON_spec_string_copy ("logo",
     60                                     &contract->merchant.logo),
     61       NULL),
     62     GNUNET_JSON_spec_mark_optional (
     63       GNUNET_JSON_spec_object_copy ("address",
     64                                     &contract->merchant.address),
     65       NULL),
     66     GNUNET_JSON_spec_mark_optional (
     67       GNUNET_JSON_spec_object_copy ("jurisdiction",
     68                                     &contract->merchant.jurisdiction),
     69       NULL),
     70     GNUNET_JSON_spec_end ()
     71   };
     72   const char *error_name;
     73   unsigned int error_line;
     74 
     75   (void) cls;
     76   if (GNUNET_OK !=
     77       GNUNET_JSON_parse (root,
     78                          spec,
     79                          &error_name,
     80                          &error_line))
     81   {
     82     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     83                 "Failed to parse %s at %u: %s\n",
     84                 spec[error_line].field,
     85                 error_line,
     86                 error_name);
     87     GNUNET_break_op (0);
     88     return GNUNET_SYSERR;
     89   }
     90   return GNUNET_OK;
     91 }
     92 
     93 
     94 /**
     95  * Provide specification to parse given JSON object to merchant details in the
     96  * contract terms. All fields from @a contract are copied.
     97  *
     98  * @param name name of the merchant details field in the JSON
     99  * @param[out] contract where the merchant details have to be written
    100  */
    101 static struct GNUNET_JSON_Specification
    102 spec_merchant_details (const char *name,
    103                        struct TALER_MERCHANT_Contract *contract)
    104 {
    105   struct GNUNET_JSON_Specification ret = {
    106     .parser = &parse_merchant_details,
    107     .field = name,
    108     .ptr = contract,
    109   };
    110 
    111   return ret;
    112 }
    113 
    114 
    115 /**
    116  * Get enum value from contract token type string.
    117  *
    118  * @param str contract token type string
    119  * @return enum value of token type
    120  */
    121 static enum TALER_MERCHANT_ContractTokenKind
    122 contract_token_kind_from_string (const char *str)
    123 {
    124   if (0 == strcmp ("subscription",
    125                    str))
    126     return TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION;
    127   if (0 == strcmp ("discount",
    128                    str))
    129     return TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT;
    130   return TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID;
    131 }
    132 
    133 
    134 enum GNUNET_GenericReturnValue
    135 TALER_MERCHANT_parse_choice_input (
    136   json_t *root,
    137   struct TALER_MERCHANT_ContractInput *input,
    138   size_t index,
    139   bool order)
    140 {
    141   const char *ename;
    142   unsigned int eline;
    143   struct GNUNET_JSON_Specification ispec[] = {
    144     TALER_MERCHANT_json_spec_cit ("type",
    145                                   &input->type),
    146     GNUNET_JSON_spec_end ()
    147   };
    148 
    149   if (GNUNET_OK !=
    150       GNUNET_JSON_parse (root,
    151                          ispec,
    152                          &ename,
    153                          &eline))
    154   {
    155     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    156                 "Failed to parse %s at %u: %s\n",
    157                 ispec[eline].field,
    158                 eline,
    159                 ename);
    160     GNUNET_break_op (0);
    161     return GNUNET_SYSERR;
    162   }
    163 
    164   switch (input->type)
    165   {
    166   case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
    167     GNUNET_break (0);
    168     break;
    169   case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
    170     {
    171       struct GNUNET_JSON_Specification spec[] = {
    172         GNUNET_JSON_spec_string ("token_family_slug",
    173                                  &input->details.token.token_family_slug),
    174         GNUNET_JSON_spec_mark_optional (
    175           GNUNET_JSON_spec_uint32 ("count",
    176                                    &input->details.token.count),
    177           NULL),
    178         GNUNET_JSON_spec_end ()
    179       };
    180 
    181       if (GNUNET_OK !=
    182           GNUNET_JSON_parse (root,
    183                              spec,
    184                              &ename,
    185                              &eline))
    186       {
    187         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    188                     "Failed to parse %s at %u: %s\n",
    189                     spec[eline].field,
    190                     eline,
    191                     ename);
    192         GNUNET_break_op (0);
    193         return GNUNET_SYSERR;
    194       }
    195 
    196       return GNUNET_OK;
    197     }
    198   }
    199 
    200   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    201               "Field 'type' invalid in input #%u\n",
    202               (unsigned int) index);
    203   GNUNET_break_op (0);
    204   return GNUNET_SYSERR;
    205 }
    206 
    207 
    208 enum GNUNET_GenericReturnValue
    209 TALER_MERCHANT_parse_choice_output (
    210   json_t *root,
    211   struct TALER_MERCHANT_ContractOutput *output,
    212   size_t index,
    213   bool order)
    214 {
    215   const char *ename;
    216   unsigned int eline;
    217   struct GNUNET_JSON_Specification ispec[] = {
    218     TALER_MERCHANT_json_spec_cot ("type",
    219                                   &output->type),
    220     GNUNET_JSON_spec_end ()
    221   };
    222 
    223   if (GNUNET_OK !=
    224       GNUNET_JSON_parse (root,
    225                          ispec,
    226                          &ename,
    227                          &eline))
    228   {
    229     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    230                 "Failed to parse %s at %u: %s\n",
    231                 ispec[eline].field,
    232                 eline,
    233                 ename);
    234     GNUNET_break_op (0);
    235     return GNUNET_SYSERR;
    236   }
    237 
    238   switch (output->type)
    239   {
    240   case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
    241     GNUNET_break (0);
    242     break;
    243   case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
    244     {
    245       struct GNUNET_JSON_Specification spec[] = {
    246         GNUNET_JSON_spec_string ("token_family_slug",
    247                                  &output->details.token.token_family_slug),
    248         GNUNET_JSON_spec_mark_optional (
    249           GNUNET_JSON_spec_uint ("count",
    250                                  &output->details.token.count),
    251           NULL),
    252         GNUNET_JSON_spec_mark_optional (
    253           GNUNET_JSON_spec_timestamp ("valid_at",
    254                                       &output->details.token.valid_at),
    255           NULL),
    256         (! order)
    257         ? GNUNET_JSON_spec_uint ("key_index",
    258                                  &output->details.token.key_index)
    259         : GNUNET_JSON_spec_end (),
    260         GNUNET_JSON_spec_end ()
    261       };
    262 
    263       if (GNUNET_OK !=
    264           GNUNET_JSON_parse (root,
    265                              spec,
    266                              &ename,
    267                              &eline))
    268       {
    269         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    270                     "Failed to parse %s at %u: %s\n",
    271                     spec[eline].field,
    272                     eline,
    273                     ename);
    274         GNUNET_break_op (0);
    275         return GNUNET_SYSERR;
    276       }
    277 
    278       return GNUNET_OK;
    279     }
    280   case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
    281     {
    282       const json_t *donau_urls = NULL;
    283       struct GNUNET_JSON_Specification spec[] = {
    284         GNUNET_JSON_spec_mark_optional (
    285           TALER_JSON_spec_amount_any ("amount",
    286                                       &output->details.donation_receipt.amount),
    287           NULL),
    288         (! order)
    289         ? GNUNET_JSON_spec_array_const ("donau_urls",
    290                                         &donau_urls)
    291         : GNUNET_JSON_spec_end (),
    292         GNUNET_JSON_spec_end ()
    293       };
    294 
    295       if (GNUNET_OK !=
    296           GNUNET_JSON_parse (root,
    297                              spec,
    298                              &ename,
    299                              &eline))
    300       {
    301         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    302                     "Failed to parse %s at %u: %s\n",
    303                     spec[eline].field,
    304                     eline,
    305                     ename);
    306         GNUNET_break_op (0);
    307         return GNUNET_SYSERR;
    308       }
    309 
    310       GNUNET_array_grow (output->details.donation_receipt.donau_urls,
    311                          output->details.donation_receipt.donau_urls_len,
    312                          json_array_size (donau_urls));
    313 
    314       for (unsigned int i = 0;
    315            i < output->details.donation_receipt.donau_urls_len;
    316            i++)
    317       {
    318         const json_t *jurl;
    319 
    320         jurl = json_array_get (donau_urls,
    321                                i);
    322         if (! json_is_string (jurl))
    323         {
    324           GNUNET_break_op (0);
    325           return GNUNET_SYSERR;
    326         }
    327         output->details.donation_receipt.donau_urls[i] =
    328           GNUNET_strdup (json_string_value (jurl));
    329       }
    330 
    331       return GNUNET_OK;
    332     }
    333   }
    334 
    335   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    336               "Field 'type' invalid in output #%u\n",
    337               (unsigned int) index);
    338   GNUNET_break_op (0);
    339   return GNUNET_SYSERR;
    340 }
    341 
    342 
    343 /**
    344  * Parse given JSON object to choices array.
    345  *
    346  * @param cls closure, pointer to array length
    347  * @param root the json array representing the choices
    348  * @param[out] ospec where to write the data
    349  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    350  */
    351 static enum GNUNET_GenericReturnValue
    352 parse_choices (
    353   void *cls,
    354   json_t *root,
    355   struct GNUNET_JSON_Specification *ospec)
    356 {
    357   struct TALER_MERCHANT_ContractChoice **choices = ospec->ptr;
    358   unsigned int *choices_len = cls;
    359 
    360   if (! json_is_array (root))
    361   {
    362     GNUNET_break_op (0);
    363     return GNUNET_SYSERR;
    364   }
    365   if (0 == json_array_size (root))
    366   {
    367     /* empty list of choices is not allowed */
    368     GNUNET_break_op (0);
    369     return GNUNET_SYSERR;
    370   }
    371   GNUNET_array_grow (*choices,
    372                      *choices_len,
    373                      json_array_size (root));
    374 
    375   for (unsigned int i = 0; i < *choices_len; i++)
    376   {
    377     struct TALER_MERCHANT_ContractChoice *choice = &(*choices)[i];
    378     const json_t *jinputs = NULL;
    379     const json_t *joutputs = NULL;
    380     struct GNUNET_JSON_Specification spec[] = {
    381       TALER_JSON_spec_amount_any ("amount",
    382                                   &choice->amount),
    383       GNUNET_JSON_spec_mark_optional (
    384         TALER_JSON_spec_amount_any ("tip",
    385                                     &choice->tip),
    386         &choice->no_tip),
    387       GNUNET_JSON_spec_mark_optional (
    388         GNUNET_JSON_spec_string_copy ("description",
    389                                       &choice->description),
    390         NULL),
    391       GNUNET_JSON_spec_mark_optional (
    392         GNUNET_JSON_spec_object_copy ("description_i18n",
    393                                       &choice->description_i18n),
    394         NULL),
    395       GNUNET_JSON_spec_mark_optional (
    396         TALER_JSON_spec_amount_any ("max_fee",
    397                                     &choice->max_fee),
    398         NULL),
    399       GNUNET_JSON_spec_mark_optional (
    400         GNUNET_JSON_spec_array_const ("inputs",
    401                                       &jinputs),
    402         NULL),
    403       GNUNET_JSON_spec_mark_optional (
    404         GNUNET_JSON_spec_array_const ("outputs",
    405                                       &joutputs),
    406         NULL),
    407       GNUNET_JSON_spec_end ()
    408     };
    409     const char *ename;
    410     unsigned int eline;
    411 
    412     if (GNUNET_OK !=
    413         GNUNET_JSON_parse (json_array_get (root, i),
    414                            spec,
    415                            &ename,
    416                            &eline))
    417     {
    418       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    419                   "Failed to parse %s at %u: %s\n",
    420                   spec[eline].field,
    421                   eline,
    422                   ename);
    423       GNUNET_break_op (0);
    424       return GNUNET_SYSERR;
    425     }
    426     if ( (! choice->no_tip) &&
    427          (GNUNET_OK !=
    428           TALER_amount_cmp_currency (&choice->amount,
    429                                      &choice->tip)) )
    430     {
    431       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    432                   "Tip currency does not match amount currency in choice #%u\n",
    433                   i);
    434       GNUNET_break_op (0);
    435       return GNUNET_SYSERR;
    436     }
    437 
    438     if (NULL != jinputs)
    439     {
    440       const json_t *jinput;
    441       size_t idx;
    442 
    443       json_array_foreach ((json_t *) jinputs, idx, jinput)
    444       {
    445         struct TALER_MERCHANT_ContractInput input = {
    446           .details.token.count = 1
    447         };
    448 
    449         if (GNUNET_OK !=
    450             TALER_MERCHANT_parse_choice_input ((json_t *) jinput,
    451                                                &input,
    452                                                idx,
    453                                                false))
    454         {
    455           GNUNET_break (0);
    456           return GNUNET_SYSERR;
    457         }
    458         switch (input.type)
    459         {
    460         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
    461           GNUNET_break_op (0);
    462           return GNUNET_SYSERR;
    463         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
    464           /* Ignore inputs tokens with 'count' field set to 0 */
    465           if (0 == input.details.token.count)
    466             continue;
    467           break;
    468         }
    469         GNUNET_array_append (choice->inputs,
    470                              choice->inputs_len,
    471                              input);
    472       }
    473     }
    474 
    475     if (NULL != joutputs)
    476     {
    477       const json_t *joutput;
    478       size_t idx;
    479       json_array_foreach ((json_t *) joutputs, idx, joutput)
    480       {
    481         struct TALER_MERCHANT_ContractOutput output = {
    482           .details.token.count = 1
    483         };
    484 
    485         if (GNUNET_OK !=
    486             TALER_MERCHANT_parse_choice_output ((json_t *) joutput,
    487                                                 &output,
    488                                                 idx,
    489                                                 false))
    490         {
    491           GNUNET_break (0);
    492           return GNUNET_SYSERR;
    493         }
    494         switch (output.type)
    495         {
    496         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
    497           GNUNET_break_op (0);
    498           return GNUNET_SYSERR;
    499         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
    500           /* Ignore output tokens with 'count' field set to 0 */
    501           if (0 == output.details.token.count)
    502             continue;
    503           break;
    504         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
    505           break;
    506         }
    507         GNUNET_array_append (choice->outputs,
    508                              choice->outputs_len,
    509                              output);
    510       }
    511     }
    512   }
    513 
    514   return GNUNET_OK;
    515 }
    516 
    517 
    518 struct GNUNET_JSON_Specification
    519 TALER_MERCHANT_spec_choices (
    520   const char *name,
    521   struct TALER_MERCHANT_ContractChoice **choices,
    522   unsigned int *choices_len)
    523 {
    524   struct GNUNET_JSON_Specification ret = {
    525     .cls = (void *) choices_len,
    526     .parser = &parse_choices,
    527     .field = name,
    528     .ptr = choices,
    529   };
    530 
    531   return ret;
    532 }
    533 
    534 
    535 void
    536 TALER_MERCHANT_contract_choice_free (
    537   struct TALER_MERCHANT_ContractChoice *choice)
    538 {
    539   for (unsigned int i = 0; i < choice->outputs_len; i++)
    540   {
    541     struct TALER_MERCHANT_ContractOutput *output = &choice->outputs[i];
    542 
    543     switch (output->type)
    544     {
    545     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
    546       GNUNET_break (0);
    547       break;
    548     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
    549       break;
    550     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
    551       for (unsigned int j = 0;
    552            j<output->details.donation_receipt.donau_urls_len;
    553            j++)
    554         GNUNET_free (output->details.donation_receipt.donau_urls[j]);
    555       GNUNET_array_grow (output->details.donation_receipt.donau_urls,
    556                          output->details.donation_receipt.donau_urls_len,
    557                          0);
    558       break;
    559 #if FUTURE
    560     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_COIN:
    561       GNUNET_free (output->details.coin.exchange_url);
    562       break;
    563 #endif
    564     }
    565   }
    566   GNUNET_free (choice->description);
    567   if (NULL != choice->description_i18n)
    568   {
    569     json_decref (choice->description_i18n);
    570     choice->description_i18n = NULL;
    571   }
    572   GNUNET_free (choice->inputs);
    573   GNUNET_free (choice->outputs);
    574 }
    575 
    576 
    577 /**
    578  * Parse token details of the given JSON contract token family.
    579  *
    580  * @param cls closure, unused parameter
    581  * @param root the JSON object representing data
    582  * @param[out] ospec where to write the data
    583  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    584  */
    585 static enum GNUNET_GenericReturnValue
    586 parse_token_details (void *cls,
    587                      json_t *root,
    588                      struct GNUNET_JSON_Specification *ospec)
    589 {
    590   struct TALER_MERCHANT_ContractTokenFamily *family = ospec->ptr;
    591   const char *class;
    592   const char *ename;
    593   unsigned int eline;
    594   struct GNUNET_JSON_Specification ispec[] = {
    595     GNUNET_JSON_spec_string ("class",
    596                              &class),
    597     GNUNET_JSON_spec_end ()
    598   };
    599 
    600   (void) cls;
    601   if (GNUNET_OK !=
    602       GNUNET_JSON_parse (root,
    603                          ispec,
    604                          &ename,
    605                          &eline))
    606   {
    607     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    608                 "Failed to parse %s at %u: %s\n",
    609                 ispec[eline].field,
    610                 eline,
    611                 ename);
    612     GNUNET_break_op (0);
    613     return GNUNET_SYSERR;
    614   }
    615 
    616   family->kind = contract_token_kind_from_string (class);
    617 
    618   switch (family->kind)
    619   {
    620   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
    621     break;
    622   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
    623     {
    624       const json_t *trusted_domains;
    625       struct GNUNET_JSON_Specification spec[] = {
    626         GNUNET_JSON_spec_array_const ("trusted_domains",
    627                                       &trusted_domains),
    628         GNUNET_JSON_spec_end ()
    629       };
    630 
    631       if (GNUNET_OK !=
    632           GNUNET_JSON_parse (root,
    633                              spec,
    634                              &ename,
    635                              &eline))
    636       {
    637         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    638                     "Failed to parse %s at %u: %s\n",
    639                     spec[eline].field,
    640                     eline,
    641                     ename);
    642         GNUNET_break_op (0);
    643         return GNUNET_SYSERR;
    644       }
    645 
    646       GNUNET_array_grow (family->details.subscription.trusted_domains,
    647                          family->details.subscription.trusted_domains_len,
    648                          json_array_size (trusted_domains));
    649 
    650       for (unsigned int i = 0;
    651            i < family->details.subscription.trusted_domains_len;
    652            i++)
    653       {
    654         const json_t *jdomain;
    655         jdomain = json_array_get (trusted_domains, i);
    656 
    657         if (! json_is_string (jdomain))
    658         {
    659           GNUNET_break_op (0);
    660           return GNUNET_SYSERR;
    661         }
    662 
    663         family->details.subscription.trusted_domains[i] =
    664           GNUNET_strdup (json_string_value (jdomain));
    665       }
    666 
    667       return GNUNET_OK;
    668     }
    669   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
    670     {
    671       const json_t *expected_domains;
    672       struct GNUNET_JSON_Specification spec[] = {
    673         GNUNET_JSON_spec_array_const ("expected_domains",
    674                                       &expected_domains),
    675         GNUNET_JSON_spec_end ()
    676       };
    677 
    678       if (GNUNET_OK !=
    679           GNUNET_JSON_parse (root,
    680                              spec,
    681                              &ename,
    682                              &eline))
    683       {
    684         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    685                     "Failed to parse %s at %u: %s\n",
    686                     spec[eline].field,
    687                     eline,
    688                     ename);
    689         GNUNET_break_op (0);
    690         return GNUNET_SYSERR;
    691       }
    692 
    693       GNUNET_array_grow (family->details.discount.expected_domains,
    694                          family->details.discount.expected_domains_len,
    695                          json_array_size (expected_domains));
    696 
    697       for (unsigned int i = 0;
    698            i < family->details.discount.expected_domains_len;
    699            i++)
    700       {
    701         const json_t *jdomain;
    702 
    703         jdomain = json_array_get (expected_domains,
    704                                   i);
    705         if (! json_is_string (jdomain))
    706         {
    707           GNUNET_break_op (0);
    708           return GNUNET_SYSERR;
    709         }
    710 
    711         family->details.discount.expected_domains[i] =
    712           GNUNET_strdup (json_string_value (jdomain));
    713       }
    714 
    715       return GNUNET_OK;
    716     }
    717   }
    718 
    719   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    720               "Field 'type' invalid in token family\n");
    721   GNUNET_break_op (0);
    722   return GNUNET_SYSERR;
    723 }
    724 
    725 
    726 /**
    727  * Provide specification to parse given JSON object to contract token details
    728  * in the contract token family. All fields from @a family are copied.
    729  *
    730  * @param name name of the token details field in the JSON
    731  * @param[out] family token_family where the token details have to be written
    732  */
    733 static struct GNUNET_JSON_Specification
    734 spec_token_details (const char *name,
    735                     struct TALER_MERCHANT_ContractTokenFamily *family)
    736 {
    737   struct GNUNET_JSON_Specification ret = {
    738     .parser = &parse_token_details,
    739     .field = name,
    740     .ptr = family,
    741   };
    742 
    743   return ret;
    744 }
    745 
    746 
    747 /**
    748  * Parse given JSON object to token families array.
    749  *
    750  * @param cls closure, pointer to array length
    751  * @param root the json object representing the token families. The keys are
    752  *             the token family slugs.
    753  * @param[out] ospec where to write the data
    754  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    755  */
    756 static enum GNUNET_GenericReturnValue
    757 parse_token_families (void *cls,
    758                       json_t *root,
    759                       struct GNUNET_JSON_Specification *ospec)
    760 {
    761   struct TALER_MERCHANT_ContractTokenFamily **families = ospec->ptr;
    762   unsigned int *families_len = cls;
    763   json_t *jfamily;
    764   const char *slug;
    765 
    766   if (! json_is_object (root))
    767   {
    768     GNUNET_break_op (0);
    769     return GNUNET_SYSERR;
    770   }
    771 
    772   json_object_foreach (root, slug, jfamily)
    773   {
    774     const json_t *keys;
    775     struct TALER_MERCHANT_ContractTokenFamily family = {
    776       .slug = GNUNET_strdup (slug)
    777     };
    778     struct GNUNET_JSON_Specification spec[] = {
    779       GNUNET_JSON_spec_string_copy ("name",
    780                                     &family.name),
    781       GNUNET_JSON_spec_string_copy ("description",
    782                                     &family.description),
    783       GNUNET_JSON_spec_object_copy ("description_i18n",
    784                                     &family.description_i18n),
    785       GNUNET_JSON_spec_array_const ("keys",
    786                                     &keys),
    787       spec_token_details ("details",
    788                           &family),
    789       GNUNET_JSON_spec_bool ("critical",
    790                              &family.critical),
    791       GNUNET_JSON_spec_end ()
    792     };
    793     const char *error_name;
    794     unsigned int error_line;
    795 
    796     if (GNUNET_OK !=
    797         GNUNET_JSON_parse (jfamily,
    798                            spec,
    799                            &error_name,
    800                            &error_line))
    801     {
    802       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    803                   "Failed to parse %s at %u: %s\n",
    804                   spec[error_line].field,
    805                   error_line,
    806                   error_name);
    807       GNUNET_break_op (0);
    808       return GNUNET_SYSERR;
    809     }
    810 
    811     GNUNET_array_grow (family.keys,
    812                        family.keys_len,
    813                        json_array_size (keys));
    814 
    815     for (unsigned int i = 0; i<family.keys_len; i++)
    816     {
    817       struct TALER_MERCHANT_ContractTokenFamilyKey *key = &family.keys[i];
    818       struct GNUNET_JSON_Specification key_spec[] = {
    819         TALER_JSON_spec_token_pub (
    820           NULL,
    821           &key->pub),
    822         GNUNET_JSON_spec_timestamp (
    823           "signature_validity_start",
    824           &key->valid_after),
    825         GNUNET_JSON_spec_timestamp (
    826           "signature_validity_end",
    827           &key->valid_before),
    828         GNUNET_JSON_spec_end ()
    829       };
    830       const char *ierror_name;
    831       unsigned int ierror_line;
    832 
    833       if (GNUNET_OK !=
    834           GNUNET_JSON_parse (json_array_get (keys,
    835                                              i),
    836                              key_spec,
    837                              &ierror_name,
    838                              &ierror_line))
    839       {
    840         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    841                     "Failed to parse %s at %u: %s\n",
    842                     key_spec[ierror_line].field,
    843                     ierror_line,
    844                     ierror_name);
    845         GNUNET_break_op (0);
    846         return GNUNET_SYSERR;
    847       }
    848     }
    849 
    850     GNUNET_array_append (*families,
    851                          *families_len,
    852                          family);
    853   }
    854 
    855   return GNUNET_OK;
    856 }
    857 
    858 
    859 /**
    860  * Provide specification to parse given JSON array to token families in the
    861  * contract terms. All fields from @a families items are copied.
    862  *
    863  * @param name name of the token families field in the JSON
    864  * @param[out] families where the token families array has to be written
    865  * @param[out] families_len length of the @a families array
    866  */
    867 static struct GNUNET_JSON_Specification
    868 spec_token_families (
    869   const char *name,
    870   struct TALER_MERCHANT_ContractTokenFamily **families,
    871   unsigned int *families_len)
    872 {
    873   struct GNUNET_JSON_Specification ret = {
    874     .cls = (void *) families_len,
    875     .parser = &parse_token_families,
    876     .field = name,
    877     .ptr = families,
    878   };
    879 
    880   return ret;
    881 }
    882 
    883 
    884 enum GNUNET_GenericReturnValue
    885 TALER_MERCHANT_find_token_family_key (
    886   const char *slug,
    887   struct GNUNET_TIME_Timestamp valid_after,
    888   const struct TALER_MERCHANT_ContractTokenFamily *families,
    889   unsigned int families_len,
    890   struct TALER_MERCHANT_ContractTokenFamily *family,
    891   struct TALER_MERCHANT_ContractTokenFamilyKey *key)
    892 {
    893   for (unsigned int i = 0; i < families_len; i++)
    894   {
    895     const struct TALER_MERCHANT_ContractTokenFamily *fami
    896       = &families[i];
    897 
    898     if (0 != strcmp (fami->slug,
    899                      slug))
    900       continue;
    901     if (NULL != family)
    902       *family = *fami;
    903     for (unsigned int k = 0; k < fami->keys_len; k++)
    904     {
    905       struct TALER_MERCHANT_ContractTokenFamilyKey *ki = &fami->keys[k];
    906 
    907       if (GNUNET_TIME_timestamp_cmp (ki->valid_after,
    908                                      ==,
    909                                      valid_after))
    910       {
    911         if (NULL != key)
    912           *key = *ki;
    913         return GNUNET_OK;
    914       }
    915     }
    916     /* matching family found, but no key. */
    917     return GNUNET_NO;
    918   }
    919 
    920   /* no matching family found */
    921   return GNUNET_SYSERR;
    922 }
    923 
    924 
    925 /**
    926  * Free all the fields in the given @a family, but not @a family itself, since
    927  * it is normally part of an array.
    928  *
    929  * @param[in] family contract token family to free
    930  */
    931 static void
    932 contract_token_family_free (
    933   struct TALER_MERCHANT_ContractTokenFamily *family)
    934 {
    935   GNUNET_free (family->slug);
    936   GNUNET_free (family->name);
    937   GNUNET_free (family->description);
    938   if (NULL != family->description_i18n)
    939   {
    940     json_decref (family->description_i18n);
    941     family->description_i18n = NULL;
    942   }
    943   for (unsigned int i = 0; i < family->keys_len; i++)
    944     TALER_token_issue_pub_free (&family->keys[i].pub);
    945   GNUNET_free (family->keys);
    946 
    947   switch (family->kind)
    948   {
    949   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
    950     break;
    951   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
    952     for (unsigned int i = 0; i < family->details.discount.expected_domains_len;
    953          i++)
    954       GNUNET_free (family->details.discount.expected_domains[i]);
    955     break;
    956   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
    957     for (unsigned int i = 0; i < family->details.subscription.
    958          trusted_domains_len; i++)
    959       GNUNET_free (family->details.subscription.trusted_domains[i]);
    960     break;
    961   }
    962 }
    963 
    964 
    965 /**
    966  * Parse contract version of given JSON contract terms.
    967  *
    968  * @param cls closure, unused parameter
    969  * @param root the JSON object representing data
    970  * @param[out] spec where to write the data
    971  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    972  */
    973 static enum GNUNET_GenericReturnValue
    974 parse_contract_version (void *cls,
    975                         json_t *root,
    976                         struct GNUNET_JSON_Specification *spec)
    977 {
    978   enum TALER_MERCHANT_ContractVersion *res
    979     = (enum TALER_MERCHANT_ContractVersion *) spec->ptr;
    980 
    981   (void) cls;
    982   if (json_is_integer (root))
    983   {
    984     json_int_t version = json_integer_value (root);
    985 
    986     switch (version)
    987     {
    988     case 0:
    989       *res = TALER_MERCHANT_CONTRACT_VERSION_0;
    990       return GNUNET_OK;
    991     case 1:
    992       *res = TALER_MERCHANT_CONTRACT_VERSION_1;
    993       return GNUNET_OK;
    994     }
    995 
    996     GNUNET_break_op (0);
    997     return GNUNET_SYSERR;
    998   }
    999 
   1000   if (json_is_null (root))
   1001   {
   1002     *res = TALER_MERCHANT_CONTRACT_VERSION_0;
   1003     return GNUNET_OK;
   1004   }
   1005 
   1006   GNUNET_break_op (0);
   1007   return GNUNET_SYSERR;
   1008 }
   1009 
   1010 
   1011 /**
   1012  * Create JSON specification to parse a merchant contract
   1013  * version.
   1014  *
   1015  * @param name name of the field
   1016  * @param[out] version where to write the contract version
   1017  * @return JSON specification object
   1018  */
   1019 static struct GNUNET_JSON_Specification
   1020 spec_contract_version (
   1021   const char *name,
   1022   enum TALER_MERCHANT_ContractVersion *version)
   1023 {
   1024   struct GNUNET_JSON_Specification ret = {
   1025     .parser = &parse_contract_version,
   1026     .field = name,
   1027     .ptr = version
   1028   };
   1029 
   1030   *version = TALER_MERCHANT_CONTRACT_VERSION_0;
   1031   return ret;
   1032 }
   1033 
   1034 
   1035 /**
   1036  * Parse v0-specific fields of @a input JSON into @a contract.
   1037  *
   1038  * @param[in] input the JSON contract terms
   1039  * @param[out] contract where to write the data
   1040  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1041  */
   1042 static enum GNUNET_GenericReturnValue
   1043 parse_contract_v0 (
   1044   json_t *input,
   1045   struct TALER_MERCHANT_Contract *contract)
   1046 {
   1047   struct GNUNET_JSON_Specification espec[] = {
   1048     TALER_JSON_spec_amount_any ("amount",
   1049                                 &contract->details.v0.brutto),
   1050     GNUNET_JSON_spec_mark_optional (
   1051       TALER_JSON_spec_amount_any ("tip",
   1052                                   &contract->details.v0.tip),
   1053       &contract->details.v0.no_tip),
   1054     TALER_JSON_spec_amount_any ("max_fee",
   1055                                 &contract->details.v0.max_fee),
   1056     GNUNET_JSON_spec_end ()
   1057   };
   1058   enum GNUNET_GenericReturnValue res;
   1059   const char *ename;
   1060   unsigned int eline;
   1061 
   1062   res = GNUNET_JSON_parse (input,
   1063                            espec,
   1064                            &ename,
   1065                            &eline);
   1066   if (GNUNET_OK != res)
   1067   {
   1068     GNUNET_break (0);
   1069     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1070                 "Failed to parse contract v0 at field %s\n",
   1071                 ename);
   1072     return GNUNET_SYSERR;
   1073   }
   1074 
   1075   if (GNUNET_OK !=
   1076       TALER_amount_cmp_currency (&contract->details.v0.max_fee,
   1077                                  &contract->details.v0.brutto))
   1078   {
   1079     GNUNET_break (0);
   1080     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1081                 "'max_fee' in database does not match currency of contract price");
   1082     return GNUNET_SYSERR;
   1083   }
   1084   if ( (! contract->details.v0.no_tip) &&
   1085        (GNUNET_OK !=
   1086         TALER_amount_cmp_currency (&contract->details.v0.tip,
   1087                                    &contract->details.v0.brutto)) )
   1088   {
   1089     GNUNET_break (0);
   1090     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1091                 "'tip' in database does not match currency of contract price");
   1092     return GNUNET_SYSERR;
   1093   }
   1094 
   1095   return res;
   1096 }
   1097 
   1098 
   1099 /**
   1100  * Parse v1-specific fields of @a input JSON into @a contract.
   1101  *
   1102  * @param[in] input the JSON contract terms
   1103  * @param[out] contract where to write the data
   1104  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
   1105  */
   1106 static enum GNUNET_GenericReturnValue
   1107 parse_contract_v1 (
   1108   json_t *input,
   1109   struct TALER_MERCHANT_Contract *contract)
   1110 {
   1111   struct GNUNET_JSON_Specification espec[] = {
   1112     TALER_MERCHANT_spec_choices (
   1113       "choices",
   1114       &contract->details.v1.choices,
   1115       &contract->details.v1.choices_len),
   1116     spec_token_families (
   1117       "token_families",
   1118       &contract->details.v1.token_authorities,
   1119       &contract->details.v1.token_authorities_len),
   1120     GNUNET_JSON_spec_end ()
   1121   };
   1122 
   1123   enum GNUNET_GenericReturnValue res;
   1124   const char *ename;
   1125   unsigned int eline;
   1126 
   1127   res = GNUNET_JSON_parse (input,
   1128                            espec,
   1129                            &ename,
   1130                            &eline);
   1131   if (GNUNET_OK != res)
   1132   {
   1133     GNUNET_break (0);
   1134     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1135                 "Failed to parse contract v1 at field %s\n",
   1136                 ename);
   1137     return GNUNET_SYSERR;
   1138   }
   1139 
   1140   return res;
   1141 }
   1142 
   1143 
   1144 /**
   1145  * Parse the given unit quantity string @a s and store the result in @a q.
   1146  *
   1147  * @param s quantity to parse
   1148  * @param[out] q where to store the result
   1149  * @return #GNUNET_OK on success
   1150  */
   1151 static enum GNUNET_GenericReturnValue
   1152 parse_unit_quantity (const char *s,
   1153                      struct TALER_MERCHANT_ProductQuantity *q)
   1154 {
   1155   const char *ptr;
   1156   uint64_t integer = 0;
   1157   uint32_t frac = 0;
   1158   unsigned int digits = 0;
   1159 
   1160   if (NULL == s)
   1161   {
   1162     GNUNET_break_op (0);
   1163     return GNUNET_SYSERR;
   1164   }
   1165   ptr = s;
   1166   if ('\0' == *ptr)
   1167   {
   1168     GNUNET_break_op (0);
   1169     return GNUNET_SYSERR;
   1170   }
   1171   if ('-' == *ptr)
   1172   {
   1173     GNUNET_break_op (0);
   1174     return GNUNET_SYSERR;
   1175   }
   1176   if (! isdigit ((unsigned char) *ptr))
   1177   {
   1178     GNUNET_break_op (0);
   1179     return GNUNET_SYSERR;
   1180   }
   1181   while (isdigit ((unsigned char) *ptr))
   1182   {
   1183     unsigned int digit = (unsigned int) (*ptr - '0');
   1184 
   1185     /* We intentionally allow at most INT64_MAX (as -1 has special meanings),
   1186        even though the data type would support UINT64_MAX */
   1187     if (integer > (INT64_MAX - digit) / 10)
   1188     {
   1189       GNUNET_break_op (0);
   1190       return GNUNET_SYSERR;
   1191     }
   1192     integer = integer * 10 + digit;
   1193     ptr++;
   1194   }
   1195   if ('.' == *ptr)
   1196   {
   1197     ptr++;
   1198     if ('\0' == *ptr)
   1199     {
   1200       GNUNET_break_op (0);
   1201       return GNUNET_SYSERR;
   1202     }
   1203     while (isdigit ((unsigned char) *ptr))
   1204     {
   1205       unsigned int digit = (unsigned int) (*ptr - '0');
   1206 
   1207       if (digits >= TALER_MERCHANT_UNIT_FRAC_MAX_DIGITS)
   1208       {
   1209         GNUNET_break_op (0);
   1210         return GNUNET_SYSERR;
   1211       }
   1212       frac = (uint32_t) (frac * 10 + digit);
   1213       digits++;
   1214       ptr++;
   1215     }
   1216     while (digits < TALER_MERCHANT_UNIT_FRAC_MAX_DIGITS)
   1217     {
   1218       frac *= 10;
   1219       digits++;
   1220     }
   1221   }
   1222   if ('\0' != *ptr)
   1223   {
   1224     GNUNET_break_op (0);
   1225     return GNUNET_SYSERR;
   1226   }
   1227   q->integer = integer;
   1228   q->fractional = frac;
   1229   return GNUNET_OK;
   1230 }
   1231 
   1232 
   1233 bool
   1234 TALER_MERCHANT_taxes_array_valid (const json_t *taxes)
   1235 {
   1236   json_t *tax;
   1237   size_t idx;
   1238 
   1239   if (! json_is_array (taxes))
   1240     return false;
   1241   json_array_foreach (taxes, idx, tax)
   1242   {
   1243     struct TALER_Amount amount;
   1244     const char *name;
   1245     struct GNUNET_JSON_Specification spec[] = {
   1246       GNUNET_JSON_spec_string ("name",
   1247                                &name),
   1248       TALER_JSON_spec_amount_any ("tax",
   1249                                   &amount),
   1250       GNUNET_JSON_spec_end ()
   1251     };
   1252     enum GNUNET_GenericReturnValue res;
   1253     const char *ename;
   1254     unsigned int eline;
   1255 
   1256     res = GNUNET_JSON_parse (tax,
   1257                              spec,
   1258                              &ename,
   1259                              &eline);
   1260     if (GNUNET_OK != res)
   1261     {
   1262       GNUNET_break_op (0);
   1263       return false;
   1264     }
   1265   }
   1266   return true;
   1267 }
   1268 
   1269 
   1270 enum GNUNET_GenericReturnValue
   1271 TALER_MERCHANT_parse_product_sold (const json_t *pj,
   1272                                    struct TALER_MERCHANT_ProductSold *r)
   1273 {
   1274   bool no_quantity;
   1275   bool no_unit_quantity;
   1276   bool no_price;
   1277   uint64_t legacy_quantity;
   1278   const char *unit_quantity_s;
   1279   struct TALER_Amount price;
   1280   const json_t *prices = NULL;
   1281   struct GNUNET_JSON_Specification spec[] = {
   1282     GNUNET_JSON_spec_mark_optional (
   1283       GNUNET_JSON_spec_string_copy ("product_id",
   1284                                     &r->product_id),
   1285       NULL),
   1286     GNUNET_JSON_spec_mark_optional (
   1287       GNUNET_JSON_spec_string_copy ("product_name",
   1288                                     &r->product_name),
   1289       NULL),
   1290     GNUNET_JSON_spec_mark_optional (
   1291       GNUNET_JSON_spec_string_copy ("description",
   1292                                     &r->description),
   1293       NULL),
   1294     GNUNET_JSON_spec_mark_optional (
   1295       GNUNET_JSON_spec_object_copy ("description_i18n",
   1296                                     &r->description_i18n),
   1297       NULL),
   1298     GNUNET_JSON_spec_mark_optional (
   1299       GNUNET_JSON_spec_uint64 ("quantity",
   1300                                &legacy_quantity),
   1301       &no_quantity),
   1302     GNUNET_JSON_spec_mark_optional (
   1303       GNUNET_JSON_spec_string ("unit_quantity",
   1304                                &unit_quantity_s),
   1305       &no_unit_quantity),
   1306     GNUNET_JSON_spec_mark_optional (
   1307       GNUNET_JSON_spec_string_copy ("unit",
   1308                                     &r->unit),
   1309       NULL),
   1310     GNUNET_JSON_spec_mark_optional (
   1311       TALER_JSON_spec_amount_any ("price",
   1312                                   &price),
   1313       &no_price),
   1314     GNUNET_JSON_spec_mark_optional (
   1315       GNUNET_JSON_spec_array_const ("prices",
   1316                                     &prices),
   1317       NULL),
   1318     GNUNET_JSON_spec_mark_optional (
   1319       GNUNET_JSON_spec_string_copy ("image",
   1320                                     &r->image),
   1321       NULL),
   1322     GNUNET_JSON_spec_mark_optional (
   1323       GNUNET_JSON_spec_array_copy ("taxes",
   1324                                    &r->taxes),
   1325       NULL),
   1326     GNUNET_JSON_spec_mark_optional (
   1327       GNUNET_JSON_spec_timestamp ("delivery_date",
   1328                                   &r->delivery_date),
   1329       NULL),
   1330     GNUNET_JSON_spec_mark_optional (
   1331       GNUNET_JSON_spec_uint64 ("product_money_pot",
   1332                                &r->product_money_pot),
   1333       NULL),
   1334     GNUNET_JSON_spec_end ()
   1335   };
   1336   enum GNUNET_GenericReturnValue res;
   1337   const char *ename;
   1338   unsigned int eline;
   1339 
   1340   r->delivery_date = GNUNET_TIME_UNIT_FOREVER_TS;
   1341   res = GNUNET_JSON_parse (pj,
   1342                            spec,
   1343                            &ename,
   1344                            &eline);
   1345   if (GNUNET_OK != res)
   1346   {
   1347     GNUNET_break (0);
   1348     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1349                 "Failed to parse product at field %s\n",
   1350                 ename);
   1351     return GNUNET_SYSERR;
   1352   }
   1353   if (! no_quantity)
   1354   {
   1355     r->unit_quantity.integer = legacy_quantity;
   1356     r->unit_quantity.fractional = 0;
   1357   }
   1358   if (! no_unit_quantity)
   1359   {
   1360     if (GNUNET_OK !=
   1361         parse_unit_quantity (unit_quantity_s,
   1362                              &r->unit_quantity))
   1363     {
   1364       GNUNET_break (0);
   1365       return GNUNET_SYSERR;
   1366     }
   1367   }
   1368   if ( (! no_quantity) && (! no_unit_quantity) )
   1369   {
   1370     GNUNET_break ( (0 == r->unit_quantity.fractional) &&
   1371                    (legacy_quantity == r->unit_quantity.integer) );
   1372   }
   1373   if ( (NULL != r->image) &&
   1374        (! TALER_MERCHANT_image_data_url_valid (r->image)) )
   1375   {
   1376     GNUNET_break_op (0);
   1377     return GNUNET_SYSERR;
   1378   }
   1379   if ( (NULL != r->taxes) &&
   1380        (! TALER_MERCHANT_taxes_array_valid (r->taxes)) )
   1381   {
   1382     GNUNET_break_op (0);
   1383     return GNUNET_SYSERR;
   1384   }
   1385   if (NULL != prices)
   1386   {
   1387     size_t len = json_array_size (prices);
   1388     size_t i;
   1389     json_t *price_i;
   1390 
   1391     GNUNET_assert (len < UINT_MAX);
   1392     r->prices = GNUNET_new_array ((unsigned int) len,
   1393                                   struct TALER_Amount);
   1394     json_array_foreach (prices, i, price_i)
   1395     {
   1396       struct GNUNET_JSON_Specification pspec[] = {
   1397         TALER_JSON_spec_amount_any (NULL,
   1398                                     &r->prices[i]),
   1399         GNUNET_JSON_spec_end ()
   1400       };
   1401 
   1402       res = GNUNET_JSON_parse (price_i,
   1403                                pspec,
   1404                                &ename,
   1405                                &eline);
   1406       if (GNUNET_OK != res)
   1407       {
   1408         GNUNET_break (0);
   1409         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1410                     "Failed to parse price at index %u\n",
   1411                     (unsigned int) i);
   1412         return GNUNET_SYSERR;
   1413       }
   1414     }
   1415   }
   1416   else if (! no_price)
   1417   {
   1418     r->prices = GNUNET_new_array (1,
   1419                                   struct TALER_Amount);
   1420     r->prices[0] = price;
   1421   }
   1422   return GNUNET_OK;
   1423 }
   1424 
   1425 
   1426 struct TALER_MERCHANT_Contract *
   1427 TALER_MERCHANT_contract_parse (json_t *input,
   1428                                bool nonce_optional)
   1429 {
   1430   struct TALER_MERCHANT_Contract *contract
   1431     = GNUNET_new (struct TALER_MERCHANT_Contract);
   1432   const json_t *products = NULL;
   1433   struct GNUNET_JSON_Specification espec[] = {
   1434     spec_contract_version ("version",
   1435                            &contract->version),
   1436     GNUNET_JSON_spec_string_copy ("summary",
   1437                                   &contract->summary),
   1438     /* FIXME: do i18n_str validation in the future */
   1439     GNUNET_JSON_spec_mark_optional (
   1440       GNUNET_JSON_spec_object_copy ("summary_i18n",
   1441                                     &contract->summary_i18n),
   1442       NULL),
   1443     GNUNET_JSON_spec_string_copy ("order_id",
   1444                                   &contract->order_id),
   1445     GNUNET_JSON_spec_mark_optional (
   1446       GNUNET_JSON_spec_string_copy ("public_reorder_url",
   1447                                     &contract->public_reorder_url),
   1448       NULL),
   1449     GNUNET_JSON_spec_mark_optional (
   1450       GNUNET_JSON_spec_string_copy ("fulfillment_url",
   1451                                     &contract->fulfillment_url),
   1452       NULL),
   1453     GNUNET_JSON_spec_mark_optional (
   1454       GNUNET_JSON_spec_string_copy ("fulfillment_message",
   1455                                     &contract->fulfillment_message),
   1456       NULL),
   1457     GNUNET_JSON_spec_mark_optional (
   1458       GNUNET_JSON_spec_object_copy ("fulfillment_message_i18n",
   1459                                     &contract->fulfillment_message_i18n),
   1460       NULL),
   1461     GNUNET_JSON_spec_mark_optional (
   1462       GNUNET_JSON_spec_array_const ("products",
   1463                                     &products),
   1464       NULL),
   1465     GNUNET_JSON_spec_timestamp ("timestamp",
   1466                                 &contract->timestamp),
   1467     GNUNET_JSON_spec_timestamp ("refund_deadline",
   1468                                 &contract->refund_deadline),
   1469     GNUNET_JSON_spec_timestamp ("pay_deadline",
   1470                                 &contract->pay_deadline),
   1471     GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
   1472                                 &contract->wire_deadline),
   1473     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
   1474                                  &contract->merchant_pub),
   1475     GNUNET_JSON_spec_string_copy ("merchant_base_url",
   1476                                   &contract->merchant_base_url),
   1477     spec_merchant_details ("merchant",
   1478                            contract),
   1479     GNUNET_JSON_spec_fixed_auto ("h_wire",
   1480                                  &contract->h_wire),
   1481     GNUNET_JSON_spec_string_copy ("wire_method",
   1482                                   &contract->wire_method),
   1483     GNUNET_JSON_spec_array_copy ("exchanges",
   1484                                  &contract->exchanges),
   1485     GNUNET_JSON_spec_mark_optional (
   1486       GNUNET_JSON_spec_object_copy ("delivery_location",
   1487                                     &contract->delivery_location),
   1488       NULL),
   1489     GNUNET_JSON_spec_mark_optional (
   1490       GNUNET_JSON_spec_timestamp ("delivery_date",
   1491                                   &contract->delivery_date),
   1492       NULL),
   1493     (nonce_optional)
   1494     ? GNUNET_JSON_spec_mark_optional (
   1495       GNUNET_JSON_spec_string_copy ("nonce",
   1496                                     &contract->nonce),
   1497       NULL)
   1498     : GNUNET_JSON_spec_string_copy ("nonce",
   1499                                     &contract->nonce),
   1500     GNUNET_JSON_spec_mark_optional (
   1501       GNUNET_JSON_spec_relative_time ("auto_refund",
   1502                                       &contract->auto_refund),
   1503       NULL),
   1504     GNUNET_JSON_spec_mark_optional (
   1505       GNUNET_JSON_spec_object_copy ("extra",
   1506                                     &contract->extra),
   1507       NULL),
   1508     GNUNET_JSON_spec_mark_optional (
   1509       GNUNET_JSON_spec_uint8 ("minimum_age",
   1510                               &contract->minimum_age),
   1511       NULL),
   1512     GNUNET_JSON_spec_mark_optional (
   1513       GNUNET_JSON_spec_uint64 ("default_money_pot",
   1514                                &contract->default_money_pot),
   1515       NULL),
   1516     GNUNET_JSON_spec_end ()
   1517   };
   1518 
   1519   enum GNUNET_GenericReturnValue res;
   1520   const char *ename;
   1521   unsigned int eline;
   1522 
   1523   GNUNET_assert (NULL != input);
   1524   res = GNUNET_JSON_parse (input,
   1525                            espec,
   1526                            &ename,
   1527                            &eline);
   1528   if (GNUNET_OK != res)
   1529   {
   1530     GNUNET_break (0);
   1531     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1532                 "Failed to parse contract at field %s\n",
   1533                 ename);
   1534     goto cleanup;
   1535   }
   1536   if (NULL != products)
   1537   {
   1538     contract->products_len = json_array_size (products);
   1539     if (0 != contract->products_len)
   1540     {
   1541       size_t i;
   1542       json_t *p;
   1543 
   1544       contract->products = GNUNET_new_array (contract->products_len,
   1545                                              struct TALER_MERCHANT_ProductSold);
   1546       json_array_foreach (products, i, p)
   1547       {
   1548         if (GNUNET_OK !=
   1549             TALER_MERCHANT_parse_product_sold (p,
   1550                                                &contract->products[i]))
   1551         {
   1552           GNUNET_break (0);
   1553           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1554                       "Failed to parse product at offset %u\n",
   1555                       (unsigned int) i);
   1556           goto cleanup;
   1557         }
   1558       }
   1559     }
   1560   }
   1561   switch (contract->version)
   1562   {
   1563   case TALER_MERCHANT_CONTRACT_VERSION_0:
   1564     res = parse_contract_v0 (input,
   1565                              contract);
   1566     break;
   1567   case TALER_MERCHANT_CONTRACT_VERSION_1:
   1568     res = parse_contract_v1 (input,
   1569                              contract);
   1570     break;
   1571   }
   1572 
   1573   if (GNUNET_OK != res)
   1574   {
   1575     GNUNET_break (0);
   1576     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1577                 "Failed to parse contract\n");
   1578     goto cleanup;
   1579   }
   1580   return contract;
   1581 
   1582 cleanup:
   1583   TALER_MERCHANT_contract_free (contract);
   1584   return NULL;
   1585 }
   1586 
   1587 
   1588 void
   1589 TALER_MERCHANT_product_sold_free (struct TALER_MERCHANT_ProductSold *product)
   1590 {
   1591   GNUNET_free (product->product_id);
   1592   GNUNET_free (product->product_name);
   1593   GNUNET_free (product->description);
   1594   json_decref (product->description_i18n);
   1595   GNUNET_free (product->prices);
   1596   GNUNET_free (product->unit);
   1597   GNUNET_free (product->image);
   1598   json_decref (product->taxes);
   1599 }
   1600 
   1601 
   1602 void
   1603 TALER_MERCHANT_contract_free (
   1604   struct TALER_MERCHANT_Contract *contract)
   1605 {
   1606   if (NULL == contract)
   1607     return;
   1608   GNUNET_free (contract->public_reorder_url);
   1609   GNUNET_free (contract->order_id);
   1610   GNUNET_free (contract->merchant_base_url);
   1611   GNUNET_free (contract->merchant.name);
   1612   GNUNET_free (contract->merchant.website);
   1613   GNUNET_free (contract->merchant.email);
   1614   GNUNET_free (contract->merchant.logo);
   1615   if (NULL != contract->merchant.address)
   1616   {
   1617     json_decref (contract->merchant.address);
   1618     contract->merchant.address = NULL;
   1619   }
   1620   if (NULL != contract->merchant.jurisdiction)
   1621   {
   1622     json_decref (contract->merchant.jurisdiction);
   1623     contract->merchant.jurisdiction = NULL;
   1624   }
   1625   GNUNET_free (contract->summary);
   1626   GNUNET_free (contract->fulfillment_url);
   1627   GNUNET_free (contract->fulfillment_message);
   1628   if (NULL != contract->fulfillment_message_i18n)
   1629   {
   1630     json_decref (contract->fulfillment_message_i18n);
   1631     contract->fulfillment_message_i18n = NULL;
   1632   }
   1633   if (NULL != contract->products)
   1634   {
   1635     for (size_t i = 0; i<contract->products_len; i++)
   1636       TALER_MERCHANT_product_sold_free (&contract->products[i]);
   1637     GNUNET_free (contract->products);
   1638   }
   1639   GNUNET_free (contract->wire_method);
   1640   if (NULL != contract->exchanges)
   1641   {
   1642     json_decref (contract->exchanges);
   1643     contract->exchanges = NULL;
   1644   }
   1645   if (NULL != contract->delivery_location)
   1646   {
   1647     json_decref (contract->delivery_location);
   1648     contract->delivery_location = NULL;
   1649   }
   1650   GNUNET_free (contract->nonce);
   1651   if (NULL != contract->extra)
   1652   {
   1653     json_decref (contract->extra);
   1654     contract->extra = NULL;
   1655   }
   1656 
   1657   switch (contract->version)
   1658   {
   1659   case TALER_MERCHANT_CONTRACT_VERSION_0:
   1660     break;
   1661   case TALER_MERCHANT_CONTRACT_VERSION_1:
   1662     for (unsigned int i = 0;
   1663          i < contract->details.v1.choices_len;
   1664          i++)
   1665       TALER_MERCHANT_contract_choice_free (&contract->details.v1.choices[i]);
   1666     GNUNET_free (contract->details.v1.choices);
   1667     for (unsigned int i = 0;
   1668          i < contract->details.v1.token_authorities_len;
   1669          i++)
   1670       contract_token_family_free (&contract->details.v1.token_authorities[i]);
   1671     GNUNET_free (contract->details.v1.token_authorities);
   1672     break;
   1673   }
   1674   GNUNET_free (contract);
   1675 }