LCOV - code coverage report
Current view: top level - util - contract_parse.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 76.7 % 467 358
Test Date: 2025-10-31 14:20:14 Functions: 100.0 % 20 20

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   (C) 2024 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU 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              :  */
      21              : #include "platform.h"
      22              : #include <gnunet/gnunet_common.h>
      23              : #include <gnunet/gnunet_json_lib.h>
      24              : #include <jansson.h>
      25              : #include <stdbool.h>
      26              : #include <stdint.h>
      27              : #include <taler/taler_json_lib.h>
      28              : #include <taler/taler_util.h>
      29              : #include "taler_merchant_util.h"
      30              : 
      31              : 
      32              : /**
      33              :  * Parse merchant details of given JSON contract terms.
      34              :  *
      35              :  * @param cls closure, unused parameter
      36              :  * @param root the JSON object representing data
      37              :  * @param[out] ospec where to write the data
      38              :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
      39              :  */
      40              : static enum GNUNET_GenericReturnValue
      41          161 : parse_merchant_details (void *cls,
      42              :                         json_t *root,
      43              :                         struct GNUNET_JSON_Specification *ospec)
      44              : {
      45          161 :   struct TALER_MERCHANT_Contract *contract = ospec->ptr;
      46              :   struct GNUNET_JSON_Specification spec[] = {
      47          161 :     GNUNET_JSON_spec_string_copy ("name",
      48              :                                   &contract->merchant.name),
      49          161 :     GNUNET_JSON_spec_mark_optional (
      50              :       GNUNET_JSON_spec_string_copy ("email",
      51              :                                     &contract->merchant.email),
      52              :       NULL),
      53          161 :     GNUNET_JSON_spec_mark_optional (
      54              :       GNUNET_JSON_spec_string_copy ("website",
      55              :                                     &contract->merchant.website),
      56              :       NULL),
      57          161 :     GNUNET_JSON_spec_mark_optional (
      58              :       GNUNET_JSON_spec_string_copy ("logo",
      59              :                                     &contract->merchant.logo),
      60              :       NULL),
      61          161 :     GNUNET_JSON_spec_mark_optional (
      62              :       GNUNET_JSON_spec_object_copy ("address",
      63              :                                     &contract->merchant.address),
      64              :       NULL),
      65          161 :     GNUNET_JSON_spec_mark_optional (
      66              :       GNUNET_JSON_spec_object_copy ("jurisdiction",
      67              :                                     &contract->merchant.jurisdiction),
      68              :       NULL),
      69          161 :     GNUNET_JSON_spec_end ()
      70              :   };
      71              :   const char *error_name;
      72              :   unsigned int error_line;
      73              : 
      74              :   (void) cls;
      75          161 :   if (GNUNET_OK !=
      76          161 :       GNUNET_JSON_parse (root,
      77              :                          spec,
      78              :                          &error_name,
      79              :                          &error_line))
      80              :   {
      81            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
      82              :                 "Failed to parse %s at %u: %s\n",
      83              :                 spec[error_line].field,
      84              :                 error_line,
      85              :                 error_name);
      86            0 :     GNUNET_break_op (0);
      87            0 :     return GNUNET_SYSERR;
      88              :   }
      89          161 :   return GNUNET_OK;
      90              : }
      91              : 
      92              : 
      93              : /**
      94              :  * Provide specification to parse given JSON object to merchant details in the
      95              :  * contract terms. All fields from @a contract are copied.
      96              :  *
      97              :  * @param name name of the merchant details field in the JSON
      98              :  * @param[out] contract where the merchant details have to be written
      99              :  */
     100              : static struct GNUNET_JSON_Specification
     101          161 : spec_merchant_details (const char *name,
     102              :                        struct TALER_MERCHANT_Contract *contract)
     103              : {
     104          161 :   struct GNUNET_JSON_Specification ret = {
     105              :     .parser = &parse_merchant_details,
     106              :     .field = name,
     107              :     .ptr = contract,
     108              :   };
     109              : 
     110          161 :   return ret;
     111              : }
     112              : 
     113              : 
     114              : /**
     115              :  * Get enum value from contract token type string.
     116              :  *
     117              :  * @param str contract token type string
     118              :  * @return enum value of token type
     119              :  */
     120              : static enum TALER_MERCHANT_ContractTokenKind
     121            9 : contract_token_kind_from_string (const char *str)
     122              : {
     123            9 :   if (0 == strcmp ("subscription",
     124              :                    str))
     125            7 :     return TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION;
     126            2 :   if (0 == strcmp ("discount",
     127              :                    str))
     128            2 :     return TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT;
     129            0 :   return TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID;
     130              : }
     131              : 
     132              : 
     133              : enum GNUNET_GenericReturnValue
     134           15 : TALER_MERCHANT_parse_choice_input (
     135              :   json_t *root,
     136              :   struct TALER_MERCHANT_ContractInput *input,
     137              :   size_t index,
     138              :   bool order)
     139              : {
     140              :   const char *ename;
     141              :   unsigned int eline;
     142              :   struct GNUNET_JSON_Specification ispec[] = {
     143           15 :     TALER_MERCHANT_json_spec_cit ("type",
     144              :                                   &input->type),
     145           15 :     GNUNET_JSON_spec_end ()
     146              :   };
     147              : 
     148           15 :   if (GNUNET_OK !=
     149           15 :       GNUNET_JSON_parse (root,
     150              :                          ispec,
     151              :                          &ename,
     152              :                          &eline))
     153              :   {
     154            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     155              :                 "Failed to parse %s at %u: %s\n",
     156              :                 ispec[eline].field,
     157              :                 eline,
     158              :                 ename);
     159            0 :     GNUNET_break_op (0);
     160            0 :     return GNUNET_SYSERR;
     161              :   }
     162              : 
     163           15 :   switch (input->type)
     164              :   {
     165            0 :   case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
     166            0 :     GNUNET_break (0);
     167            0 :     break;
     168           15 :   case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
     169              :     {
     170              :       struct GNUNET_JSON_Specification spec[] = {
     171           15 :         GNUNET_JSON_spec_string ("token_family_slug",
     172              :                                  &input->details.token.token_family_slug),
     173           15 :         GNUNET_JSON_spec_mark_optional (
     174              :           GNUNET_JSON_spec_uint32 ("count",
     175           15 :                                    &input->details.token.count),
     176              :           NULL),
     177           15 :         GNUNET_JSON_spec_end ()
     178              :       };
     179              : 
     180           15 :       if (GNUNET_OK !=
     181           15 :           GNUNET_JSON_parse (root,
     182              :                              spec,
     183              :                              &ename,
     184              :                              &eline))
     185              :       {
     186            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     187              :                     "Failed to parse %s at %u: %s\n",
     188              :                     spec[eline].field,
     189              :                     eline,
     190              :                     ename);
     191            0 :         GNUNET_break_op (0);
     192            0 :         return GNUNET_SYSERR;
     193              :       }
     194              : 
     195           15 :       return GNUNET_OK;
     196              :     }
     197              :   }
     198              : 
     199            0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     200              :               "Field 'type' invalid in input #%u\n",
     201              :               (unsigned int) index);
     202            0 :   GNUNET_break_op (0);
     203            0 :   return GNUNET_SYSERR;
     204              : }
     205              : 
     206              : 
     207              : enum GNUNET_GenericReturnValue
     208           16 : TALER_MERCHANT_parse_choice_output (
     209              :   json_t *root,
     210              :   struct TALER_MERCHANT_ContractOutput *output,
     211              :   size_t index,
     212              :   bool order)
     213              : {
     214              :   const char *ename;
     215              :   unsigned int eline;
     216              :   struct GNUNET_JSON_Specification ispec[] = {
     217           16 :     TALER_MERCHANT_json_spec_cot ("type",
     218              :                                   &output->type),
     219           16 :     GNUNET_JSON_spec_end ()
     220              :   };
     221              : 
     222           16 :   if (GNUNET_OK !=
     223           16 :       GNUNET_JSON_parse (root,
     224              :                          ispec,
     225              :                          &ename,
     226              :                          &eline))
     227              :   {
     228            0 :     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     229              :                 "Failed to parse %s at %u: %s\n",
     230              :                 ispec[eline].field,
     231              :                 eline,
     232              :                 ename);
     233            0 :     GNUNET_break_op (0);
     234            0 :     return GNUNET_SYSERR;
     235              :   }
     236              : 
     237           16 :   switch (output->type)
     238              :   {
     239            0 :   case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
     240            0 :     GNUNET_break (0);
     241            0 :     break;
     242           15 :   case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
     243              :     {
     244              :       struct GNUNET_JSON_Specification spec[] = {
     245           15 :         GNUNET_JSON_spec_string ("token_family_slug",
     246              :                                  &output->details.token.token_family_slug),
     247           15 :         GNUNET_JSON_spec_mark_optional (
     248              :           GNUNET_JSON_spec_uint ("count",
     249              :                                  &output->details.token.count),
     250              :           NULL),
     251           15 :         GNUNET_JSON_spec_mark_optional (
     252              :           GNUNET_JSON_spec_timestamp ("valid_at",
     253              :                                       &output->details.token.valid_at),
     254              :           NULL),
     255           15 :         (! order)
     256            7 :         ? GNUNET_JSON_spec_uint ("key_index",
     257              :                                  &output->details.token.key_index)
     258           15 :         : GNUNET_JSON_spec_end (),
     259           15 :         GNUNET_JSON_spec_end ()
     260              :       };
     261              : 
     262           15 :       if (GNUNET_OK !=
     263           15 :           GNUNET_JSON_parse (root,
     264              :                              spec,
     265              :                              &ename,
     266              :                              &eline))
     267              :       {
     268            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     269              :                     "Failed to parse %s at %u: %s\n",
     270              :                     spec[eline].field,
     271              :                     eline,
     272              :                     ename);
     273            0 :         GNUNET_break_op (0);
     274            0 :         return GNUNET_SYSERR;
     275              :       }
     276              : 
     277           15 :       return GNUNET_OK;
     278              :     }
     279            1 :   case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
     280              :     {
     281            1 :       const json_t *donau_urls = NULL;
     282              :       struct GNUNET_JSON_Specification spec[] = {
     283            1 :         GNUNET_JSON_spec_mark_optional (
     284              :           TALER_JSON_spec_amount_any ("amount",
     285              :                                       &output->details.donation_receipt.amount),
     286              :           NULL),
     287            1 :         (! order)
     288            1 :         ? GNUNET_JSON_spec_array_const ("donau_urls",
     289              :                                         &donau_urls)
     290            1 :         : GNUNET_JSON_spec_end (),
     291            1 :         GNUNET_JSON_spec_end ()
     292              :       };
     293              : 
     294            1 :       if (GNUNET_OK !=
     295            1 :           GNUNET_JSON_parse (root,
     296              :                              spec,
     297              :                              &ename,
     298              :                              &eline))
     299              :       {
     300            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     301              :                     "Failed to parse %s at %u: %s\n",
     302              :                     spec[eline].field,
     303              :                     eline,
     304              :                     ename);
     305            0 :         GNUNET_break_op (0);
     306            0 :         return GNUNET_SYSERR;
     307              :       }
     308              : 
     309            1 :       GNUNET_array_grow (output->details.donation_receipt.donau_urls,
     310              :                          output->details.donation_receipt.donau_urls_len,
     311              :                          json_array_size (donau_urls));
     312              : 
     313            1 :       for (unsigned int i = 0;
     314            4 :            i < output->details.donation_receipt.donau_urls_len;
     315            3 :            i++)
     316              :       {
     317              :         const json_t *jurl;
     318              : 
     319            3 :         jurl = json_array_get (donau_urls,
     320              :                                i);
     321            3 :         if (! json_is_string (jurl))
     322              :         {
     323            0 :           GNUNET_break_op (0);
     324            0 :           return GNUNET_SYSERR;
     325              :         }
     326            3 :         output->details.donation_receipt.donau_urls[i] =
     327            3 :           GNUNET_strdup (json_string_value (jurl));
     328              :       }
     329              : 
     330            1 :       return GNUNET_OK;
     331              :     }
     332              :   }
     333              : 
     334            0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     335              :               "Field 'type' invalid in output #%u\n",
     336              :               (unsigned int) index);
     337            0 :   GNUNET_break_op (0);
     338            0 :   return GNUNET_SYSERR;
     339              : }
     340              : 
     341              : 
     342              : /**
     343              :  * Parse given JSON object to choices array.
     344              :  *
     345              :  * @param cls closure, pointer to array length
     346              :  * @param root the json array representing the choices
     347              :  * @param[out] ospec where to write the data
     348              :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     349              :  */
     350              : static enum GNUNET_GenericReturnValue
     351            8 : parse_choices (
     352              :   void *cls,
     353              :   json_t *root,
     354              :   struct GNUNET_JSON_Specification *ospec)
     355              : {
     356            8 :   struct TALER_MERCHANT_ContractChoice **choices = ospec->ptr;
     357            8 :   unsigned int *choices_len = cls;
     358              : 
     359            8 :   if (! json_is_array (root))
     360              :   {
     361            0 :     GNUNET_break_op (0);
     362            0 :     return GNUNET_SYSERR;
     363              :   }
     364              : 
     365            8 :   GNUNET_array_grow (*choices,
     366              :                      *choices_len,
     367              :                      json_array_size (root));
     368              : 
     369           17 :   for (unsigned int i = 0; i < *choices_len; i++)
     370              :   {
     371            9 :     struct TALER_MERCHANT_ContractChoice *choice = &(*choices)[i];
     372              :     const json_t *jinputs;
     373              :     const json_t *joutputs;
     374              :     struct GNUNET_JSON_Specification spec[] = {
     375            9 :       TALER_JSON_spec_amount_any ("amount",
     376              :                                   &choice->amount),
     377            9 :       GNUNET_JSON_spec_mark_optional (
     378              :         GNUNET_JSON_spec_string_copy ("description",
     379              :                                       &choice->description),
     380              :         NULL),
     381            9 :       GNUNET_JSON_spec_mark_optional (
     382              :         GNUNET_JSON_spec_object_copy ("description_i18n",
     383              :                                       &choice->description_i18n),
     384              :         NULL),
     385            9 :       TALER_JSON_spec_amount_any ("max_fee",
     386              :                                   &choice->max_fee),
     387            9 :       GNUNET_JSON_spec_array_const ("inputs",
     388              :                                     &jinputs),
     389            9 :       GNUNET_JSON_spec_array_const ("outputs",
     390              :                                     &joutputs),
     391            9 :       GNUNET_JSON_spec_end ()
     392              :     };
     393              :     const char *ename;
     394              :     unsigned int eline;
     395              : 
     396            9 :     if (GNUNET_OK !=
     397            9 :         GNUNET_JSON_parse (json_array_get (root, i),
     398              :                            spec,
     399              :                            &ename,
     400              :                            &eline))
     401              :     {
     402            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     403              :                   "Failed to parse %s at %u: %s\n",
     404              :                   spec[eline].field,
     405              :                   eline,
     406              :                   ename);
     407            0 :       GNUNET_break_op (0);
     408            0 :       return GNUNET_SYSERR;
     409              :     }
     410              : 
     411              :     {
     412              :       const json_t *jinput;
     413              :       size_t idx;
     414              : 
     415           15 :       json_array_foreach ((json_t *) jinputs, idx, jinput)
     416              :       {
     417            6 :         struct TALER_MERCHANT_ContractInput input = {
     418              :           .details.token.count = 1
     419              :         };
     420              : 
     421            6 :         if (GNUNET_OK !=
     422            6 :             TALER_MERCHANT_parse_choice_input ((json_t *) jinput,
     423              :                                                &input,
     424              :                                                idx,
     425              :                                                false))
     426              :         {
     427            0 :           GNUNET_break (0);
     428            0 :           return GNUNET_SYSERR;
     429              :         }
     430            6 :         switch (input.type)
     431              :         {
     432            0 :         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
     433            0 :           GNUNET_break_op (0);
     434            0 :           return GNUNET_SYSERR;
     435            6 :         case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
     436              :           /* Ignore inputs tokens with 'count' field set to 0 */
     437            6 :           if (0 == input.details.token.count)
     438            0 :             continue;
     439            6 :           break;
     440              :         }
     441            6 :         GNUNET_array_append (choice->inputs,
     442              :                              choice->inputs_len,
     443              :                              input);
     444              :       }
     445              :     }
     446              : 
     447              :     {
     448              :       const json_t *joutput;
     449              :       size_t idx;
     450           17 :       json_array_foreach ((json_t *) joutputs, idx, joutput)
     451              :       {
     452            8 :         struct TALER_MERCHANT_ContractOutput output = {
     453              :           .details.token.count = 1
     454              :         };
     455              : 
     456            8 :         if (GNUNET_OK !=
     457            8 :             TALER_MERCHANT_parse_choice_output ((json_t *) joutput,
     458              :                                                 &output,
     459              :                                                 idx,
     460              :                                                 false))
     461              :         {
     462            0 :           GNUNET_break (0);
     463            0 :           return GNUNET_SYSERR;
     464              :         }
     465            8 :         switch (output.type)
     466              :         {
     467            0 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
     468            0 :           GNUNET_break_op (0);
     469            0 :           return GNUNET_SYSERR;
     470            7 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
     471              :           /* Ignore output tokens with 'count' field set to 0 */
     472            7 :           if (0 == output.details.token.count)
     473            0 :             continue;
     474            7 :           break;
     475            1 :         case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
     476            1 :           break;
     477              :         }
     478            8 :         GNUNET_array_append (choice->outputs,
     479              :                              choice->outputs_len,
     480              :                              output);
     481              :       }
     482              :     }
     483              :   }
     484              : 
     485            8 :   return GNUNET_OK;
     486              : }
     487              : 
     488              : 
     489              : /**
     490              :  * Provide specification to parse given JSON array to contract terms
     491              :  * choices. All fields from @a choices elements are copied.
     492              :  *
     493              :  * @param name name of the choices field in the JSON
     494              :  * @param[out] choices where the contract choices array has to be written
     495              :  * @param[out] choices_len length of the @a choices array
     496              :  */
     497              : static struct GNUNET_JSON_Specification
     498            8 : spec_choices (
     499              :   const char *name,
     500              :   struct TALER_MERCHANT_ContractChoice **choices,
     501              :   unsigned int *choices_len)
     502              : {
     503            8 :   struct GNUNET_JSON_Specification ret = {
     504              :     .cls = (void *) choices_len,
     505              :     .parser = &parse_choices,
     506              :     .field = name,
     507              :     .ptr = choices,
     508              :   };
     509              : 
     510            8 :   return ret;
     511              : }
     512              : 
     513              : 
     514              : void
     515           19 : TALER_MERCHANT_contract_choice_free (
     516              :   struct TALER_MERCHANT_ContractChoice *choice)
     517              : {
     518           35 :   for (unsigned int i = 0; i < choice->outputs_len; i++)
     519              :   {
     520           16 :     struct TALER_MERCHANT_ContractOutput *output = &choice->outputs[i];
     521              : 
     522           16 :     switch (output->type)
     523              :     {
     524            0 :     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
     525            0 :       GNUNET_break (0);
     526            0 :       break;
     527           15 :     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
     528           15 :       break;
     529            1 :     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
     530            1 :       for (unsigned int j = 0;
     531            4 :            j<output->details.donation_receipt.donau_urls_len;
     532            3 :            j++)
     533            3 :         GNUNET_free (output->details.donation_receipt.donau_urls[j]);
     534            1 :       GNUNET_array_grow (output->details.donation_receipt.donau_urls,
     535              :                          output->details.donation_receipt.donau_urls_len,
     536              :                          0);
     537            1 :       break;
     538              : #if FUTURE
     539              :     case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_COIN:
     540              :       GNUNET_free (output->details.coin.exchange_url);
     541              :       break;
     542              : #endif
     543              :     }
     544              :   }
     545           19 :   GNUNET_free (choice->description);
     546           19 :   if (NULL != choice->description_i18n)
     547              :   {
     548            1 :     json_decref (choice->description_i18n);
     549            1 :     choice->description_i18n = NULL;
     550              :   }
     551           19 :   GNUNET_free (choice->inputs);
     552           19 :   GNUNET_free (choice->outputs);
     553           19 : }
     554              : 
     555              : 
     556              : /**
     557              :  * Parse token details of the given JSON contract token family.
     558              :  *
     559              :  * @param cls closure, unused parameter
     560              :  * @param root the JSON object representing data
     561              :  * @param[out] ospec where to write the data
     562              :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     563              :  */
     564              : static enum GNUNET_GenericReturnValue
     565            9 : parse_token_details (void *cls,
     566              :                      json_t *root,
     567              :                      struct GNUNET_JSON_Specification *ospec)
     568              : {
     569            9 :   struct TALER_MERCHANT_ContractTokenFamily *family = ospec->ptr;
     570              :   const char *class;
     571              :   const char *ename;
     572              :   unsigned int eline;
     573              :   struct GNUNET_JSON_Specification ispec[] = {
     574            9 :     GNUNET_JSON_spec_string ("class",
     575              :                              &class),
     576            9 :     GNUNET_JSON_spec_end ()
     577              :   };
     578              : 
     579              :   (void) cls;
     580            9 :   if (GNUNET_OK !=
     581            9 :       GNUNET_JSON_parse (root,
     582              :                          ispec,
     583              :                          &ename,
     584              :                          &eline))
     585              :   {
     586            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     587              :                 "Failed to parse %s at %u: %s\n",
     588              :                 ispec[eline].field,
     589              :                 eline,
     590              :                 ename);
     591            0 :     GNUNET_break_op (0);
     592            0 :     return GNUNET_SYSERR;
     593              :   }
     594              : 
     595            9 :   family->kind = contract_token_kind_from_string (class);
     596              : 
     597            9 :   switch (family->kind)
     598              :   {
     599            0 :   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
     600            0 :     break;
     601            7 :   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
     602              :     {
     603              :       const json_t *trusted_domains;
     604              :       struct GNUNET_JSON_Specification spec[] = {
     605            7 :         GNUNET_JSON_spec_array_const ("trusted_domains",
     606              :                                       &trusted_domains),
     607            7 :         GNUNET_JSON_spec_end ()
     608              :       };
     609              : 
     610            7 :       if (GNUNET_OK !=
     611            7 :           GNUNET_JSON_parse (root,
     612              :                              spec,
     613              :                              &ename,
     614              :                              &eline))
     615              :       {
     616            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     617              :                     "Failed to parse %s at %u: %s\n",
     618              :                     spec[eline].field,
     619              :                     eline,
     620              :                     ename);
     621            0 :         GNUNET_break_op (0);
     622            0 :         return GNUNET_SYSERR;
     623              :       }
     624              : 
     625            7 :       GNUNET_array_grow (family->details.subscription.trusted_domains,
     626              :                          family->details.subscription.trusted_domains_len,
     627              :                          json_array_size (trusted_domains));
     628              : 
     629            7 :       for (unsigned int i = 0;
     630           10 :            i < family->details.subscription.trusted_domains_len;
     631            3 :            i++)
     632              :       {
     633              :         const json_t *jdomain;
     634            3 :         jdomain = json_array_get (trusted_domains, i);
     635              : 
     636            3 :         if (! json_is_string (jdomain))
     637              :         {
     638            0 :           GNUNET_break_op (0);
     639            0 :           return GNUNET_SYSERR;
     640              :         }
     641              : 
     642            3 :         family->details.subscription.trusted_domains[i] =
     643            3 :           GNUNET_strdup (json_string_value (jdomain));
     644              :       }
     645              : 
     646            7 :       return GNUNET_OK;
     647              :     }
     648            2 :   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
     649              :     {
     650              :       const json_t *expected_domains;
     651              :       struct GNUNET_JSON_Specification spec[] = {
     652            2 :         GNUNET_JSON_spec_array_const ("expected_domains",
     653              :                                       &expected_domains),
     654            2 :         GNUNET_JSON_spec_end ()
     655              :       };
     656              : 
     657            2 :       if (GNUNET_OK !=
     658            2 :           GNUNET_JSON_parse (root,
     659              :                              spec,
     660              :                              &ename,
     661              :                              &eline))
     662              :       {
     663            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     664              :                     "Failed to parse %s at %u: %s\n",
     665              :                     spec[eline].field,
     666              :                     eline,
     667              :                     ename);
     668            0 :         GNUNET_break_op (0);
     669            0 :         return GNUNET_SYSERR;
     670              :       }
     671              : 
     672            2 :       GNUNET_array_grow (family->details.discount.expected_domains,
     673              :                          family->details.discount.expected_domains_len,
     674              :                          json_array_size (expected_domains));
     675              : 
     676            2 :       for (unsigned int i = 0;
     677            5 :            i < family->details.discount.expected_domains_len;
     678            3 :            i++)
     679              :       {
     680              :         const json_t *jdomain;
     681              : 
     682            3 :         jdomain = json_array_get (expected_domains,
     683              :                                   i);
     684            3 :         if (! json_is_string (jdomain))
     685              :         {
     686            0 :           GNUNET_break_op (0);
     687            0 :           return GNUNET_SYSERR;
     688              :         }
     689              : 
     690            3 :         family->details.discount.expected_domains[i] =
     691            3 :           GNUNET_strdup (json_string_value (jdomain));
     692              :       }
     693              : 
     694            2 :       return GNUNET_OK;
     695              :     }
     696              :   }
     697              : 
     698            0 :   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     699              :               "Field 'type' invalid in token family\n");
     700            0 :   GNUNET_break_op (0);
     701            0 :   return GNUNET_SYSERR;
     702              : }
     703              : 
     704              : 
     705              : /**
     706              :  * Provide specification to parse given JSON object to contract token details
     707              :  * in the contract token family. All fields from @a family are copied.
     708              :  *
     709              :  * @param name name of the token details field in the JSON
     710              :  * @param[out] family token_family where the token details have to be written
     711              :  */
     712              : static struct GNUNET_JSON_Specification
     713            9 : spec_token_details (const char *name,
     714              :                     struct TALER_MERCHANT_ContractTokenFamily *family)
     715              : {
     716            9 :   struct GNUNET_JSON_Specification ret = {
     717              :     .parser = &parse_token_details,
     718              :     .field = name,
     719              :     .ptr = family,
     720              :   };
     721              : 
     722            9 :   return ret;
     723              : }
     724              : 
     725              : 
     726              : /**
     727              :  * Parse given JSON object to token families array.
     728              :  *
     729              :  * @param cls closure, pointer to array length
     730              :  * @param root the json object representing the token families. The keys are
     731              :  *             the token family slugs.
     732              :  * @param[out] ospec where to write the data
     733              :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     734              :  */
     735              : static enum GNUNET_GenericReturnValue
     736            8 : parse_token_families (void *cls,
     737              :                       json_t *root,
     738              :                       struct GNUNET_JSON_Specification *ospec)
     739              : {
     740            8 :   struct TALER_MERCHANT_ContractTokenFamily **families = ospec->ptr;
     741            8 :   unsigned int *families_len = cls;
     742              :   json_t *jfamily;
     743              :   const char *slug;
     744              : 
     745            8 :   if (! json_is_object (root))
     746              :   {
     747            0 :     GNUNET_break_op (0);
     748            0 :     return GNUNET_SYSERR;
     749              :   }
     750              : 
     751           17 :   json_object_foreach (root, slug, jfamily)
     752              :   {
     753              :     const json_t *keys;
     754           18 :     struct TALER_MERCHANT_ContractTokenFamily family = {
     755            9 :       .slug = GNUNET_strdup (slug)
     756              :     };
     757              :     struct GNUNET_JSON_Specification spec[] = {
     758            9 :       GNUNET_JSON_spec_string_copy ("name",
     759              :                                     &family.name),
     760            9 :       GNUNET_JSON_spec_string_copy ("description",
     761              :                                     &family.description),
     762            9 :       GNUNET_JSON_spec_object_copy ("description_i18n",
     763              :                                     &family.description_i18n),
     764            9 :       GNUNET_JSON_spec_array_const ("keys",
     765              :                                     &keys),
     766            9 :       spec_token_details ("details",
     767              :                           &family),
     768            9 :       GNUNET_JSON_spec_bool ("critical",
     769              :                              &family.critical),
     770            9 :       GNUNET_JSON_spec_end ()
     771              :     };
     772              :     const char *error_name;
     773              :     unsigned int error_line;
     774              : 
     775            9 :     if (GNUNET_OK !=
     776            9 :         GNUNET_JSON_parse (jfamily,
     777              :                            spec,
     778              :                            &error_name,
     779              :                            &error_line))
     780              :     {
     781            0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     782              :                   "Failed to parse %s at %u: %s\n",
     783              :                   spec[error_line].field,
     784              :                   error_line,
     785              :                   error_name);
     786            0 :       GNUNET_break_op (0);
     787            0 :       return GNUNET_SYSERR;
     788              :     }
     789              : 
     790            9 :     GNUNET_array_grow (family.keys,
     791              :                        family.keys_len,
     792              :                        json_array_size (keys));
     793              : 
     794           17 :     for (unsigned int i = 0; i<family.keys_len; i++)
     795              :     {
     796            8 :       struct TALER_MERCHANT_ContractTokenFamilyKey *key = &family.keys[i];
     797              :       struct GNUNET_JSON_Specification key_spec[] = {
     798            8 :         TALER_JSON_spec_token_pub (
     799              :           NULL,
     800              :           &key->pub),
     801            8 :         GNUNET_JSON_spec_timestamp (
     802              :           "signature_validity_start",
     803              :           &key->valid_after),
     804            8 :         GNUNET_JSON_spec_timestamp (
     805              :           "signature_validity_end",
     806              :           &key->valid_before),
     807            8 :         GNUNET_JSON_spec_end ()
     808              :       };
     809              :       const char *ierror_name;
     810              :       unsigned int ierror_line;
     811              : 
     812            8 :       if (GNUNET_OK !=
     813            8 :           GNUNET_JSON_parse (json_array_get (keys,
     814              :                                              i),
     815              :                              key_spec,
     816              :                              &ierror_name,
     817              :                              &ierror_line))
     818              :       {
     819            0 :         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     820              :                     "Failed to parse %s at %u: %s\n",
     821              :                     key_spec[ierror_line].field,
     822              :                     ierror_line,
     823              :                     ierror_name);
     824            0 :         GNUNET_break_op (0);
     825            0 :         return GNUNET_SYSERR;
     826              :       }
     827              :     }
     828              : 
     829            9 :     GNUNET_array_append (*families,
     830              :                          *families_len,
     831              :                          family);
     832              :   }
     833              : 
     834            8 :   return GNUNET_OK;
     835              : }
     836              : 
     837              : 
     838              : /**
     839              :  * Provide specification to parse given JSON array to token families in the
     840              :  * contract terms. All fields from @a families items are copied.
     841              :  *
     842              :  * @param name name of the token families field in the JSON
     843              :  * @param[out] families where the token families array has to be written
     844              :  * @param[out] families_len length of the @a families array
     845              :  */
     846              : static struct GNUNET_JSON_Specification
     847            8 : spec_token_families (
     848              :   const char *name,
     849              :   struct TALER_MERCHANT_ContractTokenFamily **families,
     850              :   unsigned int *families_len)
     851              : {
     852            8 :   struct GNUNET_JSON_Specification ret = {
     853              :     .cls = (void *) families_len,
     854              :     .parser = &parse_token_families,
     855              :     .field = name,
     856              :     .ptr = families,
     857              :   };
     858              : 
     859            8 :   return ret;
     860              : }
     861              : 
     862              : 
     863              : enum GNUNET_GenericReturnValue
     864            2 : TALER_MERCHANT_find_token_family_key (
     865              :   const char *slug,
     866              :   struct GNUNET_TIME_Timestamp valid_after,
     867              :   const struct TALER_MERCHANT_ContractTokenFamily *families,
     868              :   unsigned int families_len,
     869              :   struct TALER_MERCHANT_ContractTokenFamily *family,
     870              :   struct TALER_MERCHANT_ContractTokenFamilyKey *key)
     871              : {
     872            3 :   for (unsigned int i = 0; i < families_len; i++)
     873              :   {
     874            3 :     const struct TALER_MERCHANT_ContractTokenFamily *fami
     875            3 :       = &families[i];
     876              : 
     877            3 :     if (0 != strcmp (fami->slug,
     878              :                      slug))
     879            1 :       continue;
     880            2 :     if (NULL != family)
     881            2 :       *family = *fami;
     882            2 :     for (unsigned int k = 0; k < fami->keys_len; k++)
     883              :     {
     884            2 :       struct TALER_MERCHANT_ContractTokenFamilyKey *ki = &fami->keys[k];
     885              : 
     886            2 :       if (GNUNET_TIME_timestamp_cmp (ki->valid_after,
     887              :                                      ==,
     888              :                                      valid_after))
     889              :       {
     890            2 :         if (NULL != key)
     891            2 :           *key = *ki;
     892            2 :         return GNUNET_OK;
     893              :       }
     894              :     }
     895              :     /* matching family found, but no key. */
     896            0 :     return GNUNET_NO;
     897              :   }
     898              : 
     899              :   /* no matching family found */
     900            0 :   return GNUNET_SYSERR;
     901              : }
     902              : 
     903              : 
     904              : /**
     905              :  * Free all the fields in the given @a family, but not @a family itself, since
     906              :  * it is normally part of an array.
     907              :  *
     908              :  * @param[in] family contract token family to free
     909              :  */
     910              : static void
     911            9 : contract_token_family_free (
     912              :   struct TALER_MERCHANT_ContractTokenFamily *family)
     913              : {
     914            9 :   GNUNET_free (family->slug);
     915            9 :   GNUNET_free (family->name);
     916            9 :   GNUNET_free (family->description);
     917            9 :   if (NULL != family->description_i18n)
     918              :   {
     919            9 :     json_decref (family->description_i18n);
     920            9 :     family->description_i18n = NULL;
     921              :   }
     922           17 :   for (unsigned int i = 0; i < family->keys_len; i++)
     923            8 :     TALER_token_issue_pub_free (&family->keys[i].pub);
     924            9 :   GNUNET_free (family->keys);
     925              : 
     926            9 :   switch (family->kind)
     927              :   {
     928            0 :   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
     929            0 :     break;
     930            2 :   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
     931            5 :     for (unsigned int i = 0; i < family->details.discount.expected_domains_len;
     932            3 :          i++)
     933            3 :       GNUNET_free (family->details.discount.expected_domains[i]);
     934            2 :     break;
     935            7 :   case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
     936           10 :     for (unsigned int i = 0; i < family->details.subscription.
     937            3 :          trusted_domains_len; i++)
     938            3 :       GNUNET_free (family->details.subscription.trusted_domains[i]);
     939            7 :     break;
     940              :   }
     941            9 : }
     942              : 
     943              : 
     944              : /**
     945              :  * Parse contract version of given JSON contract terms.
     946              :  *
     947              :  * @param cls closure, unused parameter
     948              :  * @param root the JSON object representing data
     949              :  * @param[out] spec where to write the data
     950              :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
     951              :  */
     952              : static enum GNUNET_GenericReturnValue
     953          161 : parse_contract_version (void *cls,
     954              :                         json_t *root,
     955              :                         struct GNUNET_JSON_Specification *spec)
     956              : {
     957          161 :   enum TALER_MERCHANT_ContractVersion *res
     958              :     = (enum TALER_MERCHANT_ContractVersion *) spec->ptr;
     959              : 
     960              :   (void) cls;
     961          161 :   if (json_is_integer (root))
     962              :   {
     963          161 :     json_int_t version = json_integer_value (root);
     964              : 
     965          161 :     switch (version)
     966              :     {
     967          153 :     case 0:
     968          153 :       *res = TALER_MERCHANT_CONTRACT_VERSION_0;
     969          153 :       return GNUNET_OK;
     970            8 :     case 1:
     971            8 :       *res = TALER_MERCHANT_CONTRACT_VERSION_1;
     972            8 :       return GNUNET_OK;
     973              :     }
     974              : 
     975            0 :     GNUNET_break_op (0);
     976            0 :     return GNUNET_SYSERR;
     977              :   }
     978              : 
     979            0 :   if (json_is_null (root))
     980              :   {
     981            0 :     *res = TALER_MERCHANT_CONTRACT_VERSION_0;
     982            0 :     return GNUNET_OK;
     983              :   }
     984              : 
     985            0 :   GNUNET_break_op (0);
     986            0 :   return GNUNET_SYSERR;
     987              : }
     988              : 
     989              : 
     990              : /**
     991              :  * Create JSON specification to parse a merchant contract
     992              :  * version.
     993              :  *
     994              :  * @param name name of the field
     995              :  * @param[out] version where to write the contract version
     996              :  * @return JSON specification object
     997              :  */
     998              : static struct GNUNET_JSON_Specification
     999          161 : spec_contract_version (
    1000              :   const char *name,
    1001              :   enum TALER_MERCHANT_ContractVersion *version)
    1002              : {
    1003          161 :   struct GNUNET_JSON_Specification ret = {
    1004              :     .parser = &parse_contract_version,
    1005              :     .field = name,
    1006              :     .ptr = version
    1007              :   };
    1008              : 
    1009          161 :   *version = TALER_MERCHANT_CONTRACT_VERSION_0;
    1010          161 :   return ret;
    1011              : }
    1012              : 
    1013              : 
    1014              : /**
    1015              :  * Parse v0-specific fields of @a input JSON into @a contract.
    1016              :  *
    1017              :  * @param[in] input the JSON contract terms
    1018              :  * @param[out] contract where to write the data
    1019              :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    1020              :  */
    1021              : static enum GNUNET_GenericReturnValue
    1022          153 : parse_contract_v0 (
    1023              :   json_t *input,
    1024              :   struct TALER_MERCHANT_Contract *contract)
    1025              : {
    1026              :   struct GNUNET_JSON_Specification espec[] = {
    1027          153 :     TALER_JSON_spec_amount_any ("amount",
    1028              :                                 &contract->details.v0.brutto),
    1029          153 :     TALER_JSON_spec_amount_any ("max_fee",
    1030              :                                 &contract->details.v0.max_fee),
    1031          153 :     GNUNET_JSON_spec_end ()
    1032              :   };
    1033              :   enum GNUNET_GenericReturnValue res;
    1034              :   const char *ename;
    1035              :   unsigned int eline;
    1036              : 
    1037          153 :   res = GNUNET_JSON_parse (input,
    1038              :                            espec,
    1039              :                            &ename,
    1040              :                            &eline);
    1041          153 :   if (GNUNET_OK != res)
    1042              :   {
    1043            0 :     GNUNET_break (0);
    1044            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1045              :                 "Failed to parse contract v0 at field %s\n",
    1046              :                 ename);
    1047            0 :     return GNUNET_SYSERR;
    1048              :   }
    1049              : 
    1050          153 :   if (GNUNET_OK !=
    1051          153 :       TALER_amount_cmp_currency (&contract->details.v0.max_fee,
    1052          153 :                                  &contract->details.v0.brutto))
    1053              :   {
    1054            0 :     GNUNET_break (0);
    1055            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1056              :                 "'max_fee' in database does not match currency of contract price");
    1057            0 :     return GNUNET_SYSERR;
    1058              :   }
    1059              : 
    1060          153 :   return res;
    1061              : }
    1062              : 
    1063              : 
    1064              : /**
    1065              :  * Parse v1-specific fields of @a input JSON into @a contract.
    1066              :  *
    1067              :  * @param[in] input the JSON contract terms
    1068              :  * @param[out] contract where to write the data
    1069              :  * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
    1070              :  */
    1071              : static enum GNUNET_GenericReturnValue
    1072            8 : parse_contract_v1 (
    1073              :   json_t *input,
    1074              :   struct TALER_MERCHANT_Contract *contract)
    1075              : {
    1076              :   struct GNUNET_JSON_Specification espec[] = {
    1077            8 :     spec_choices (
    1078              :       "choices",
    1079              :       &contract->details.v1.choices,
    1080              :       &contract->details.v1.choices_len),
    1081            8 :     spec_token_families (
    1082              :       "token_families",
    1083              :       &contract->details.v1.token_authorities,
    1084              :       &contract->details.v1.token_authorities_len),
    1085            8 :     GNUNET_JSON_spec_end ()
    1086              :   };
    1087              : 
    1088              :   enum GNUNET_GenericReturnValue res;
    1089              :   const char *ename;
    1090              :   unsigned int eline;
    1091              : 
    1092            8 :   res = GNUNET_JSON_parse (input,
    1093              :                            espec,
    1094              :                            &ename,
    1095              :                            &eline);
    1096            8 :   if (GNUNET_OK != res)
    1097              :   {
    1098            0 :     GNUNET_break (0);
    1099            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1100              :                 "Failed to parse contract v1 at field %s\n",
    1101              :                 ename);
    1102            0 :     return GNUNET_SYSERR;
    1103              :   }
    1104              : 
    1105            8 :   return res;
    1106              : }
    1107              : 
    1108              : 
    1109              : struct TALER_MERCHANT_Contract *
    1110          161 : TALER_MERCHANT_contract_parse (json_t *input,
    1111              :                                bool nonce_optional)
    1112              : {
    1113              :   struct TALER_MERCHANT_Contract *contract
    1114          161 :     = GNUNET_new (struct TALER_MERCHANT_Contract);
    1115              :   struct GNUNET_JSON_Specification espec[] = {
    1116          161 :     spec_contract_version ("version",
    1117              :                            &contract->version),
    1118          161 :     GNUNET_JSON_spec_string_copy ("summary",
    1119              :                                   &contract->summary),
    1120              :     /* FIXME: do i18n_str validation in the future */
    1121          161 :     GNUNET_JSON_spec_mark_optional (
    1122              :       GNUNET_JSON_spec_object_copy ("summary_i18n",
    1123              :                                     &contract->summary_i18n),
    1124              :       NULL),
    1125          161 :     GNUNET_JSON_spec_string_copy ("order_id",
    1126              :                                   &contract->order_id),
    1127          161 :     GNUNET_JSON_spec_mark_optional (
    1128              :       GNUNET_JSON_spec_string_copy ("public_reorder_url",
    1129              :                                     &contract->public_reorder_url),
    1130              :       NULL),
    1131          161 :     GNUNET_JSON_spec_mark_optional (
    1132              :       GNUNET_JSON_spec_string_copy ("fulfillment_url",
    1133              :                                     &contract->fulfillment_url),
    1134              :       NULL),
    1135          161 :     GNUNET_JSON_spec_mark_optional (
    1136              :       GNUNET_JSON_spec_string_copy ("fulfillment_message",
    1137              :                                     &contract->fulfillment_message),
    1138              :       NULL),
    1139          161 :     GNUNET_JSON_spec_mark_optional (
    1140              :       GNUNET_JSON_spec_object_copy ("fulfillment_message_i18n",
    1141              :                                     &contract->fulfillment_message_i18n),
    1142              :       NULL),
    1143          161 :     GNUNET_JSON_spec_array_copy ("products",
    1144              :                                  &contract->products),
    1145          161 :     GNUNET_JSON_spec_timestamp ("timestamp",
    1146              :                                 &contract->timestamp),
    1147          161 :     GNUNET_JSON_spec_timestamp ("refund_deadline",
    1148              :                                 &contract->refund_deadline),
    1149          161 :     GNUNET_JSON_spec_timestamp ("pay_deadline",
    1150              :                                 &contract->pay_deadline),
    1151          161 :     GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
    1152              :                                 &contract->wire_deadline),
    1153          161 :     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
    1154              :                                  &contract->merchant_pub),
    1155          161 :     GNUNET_JSON_spec_string_copy ("merchant_base_url",
    1156              :                                   &contract->merchant_base_url),
    1157          161 :     spec_merchant_details ("merchant",
    1158              :                            contract),
    1159          161 :     GNUNET_JSON_spec_fixed_auto ("h_wire",
    1160              :                                  &contract->h_wire),
    1161          161 :     GNUNET_JSON_spec_string_copy ("wire_method",
    1162              :                                   &contract->wire_method),
    1163          161 :     GNUNET_JSON_spec_array_copy ("exchanges",
    1164              :                                  &contract->exchanges),
    1165          161 :     GNUNET_JSON_spec_mark_optional (
    1166              :       GNUNET_JSON_spec_object_copy ("delivery_location",
    1167              :                                     &contract->delivery_location),
    1168              :       NULL),
    1169          161 :     GNUNET_JSON_spec_mark_optional (
    1170              :       GNUNET_JSON_spec_timestamp ("delivery_date",
    1171              :                                   &contract->delivery_date),
    1172              :       NULL),
    1173              :     (nonce_optional)
    1174          159 :     ? GNUNET_JSON_spec_mark_optional (
    1175              :       GNUNET_JSON_spec_string_copy ("nonce",
    1176              :                                     &contract->nonce),
    1177              :       NULL)
    1178          161 :     : GNUNET_JSON_spec_string_copy ("nonce",
    1179              :                                     &contract->nonce),
    1180          161 :     GNUNET_JSON_spec_mark_optional (
    1181              :       GNUNET_JSON_spec_relative_time ("auto_refund",
    1182              :                                       &contract->auto_refund),
    1183              :       NULL),
    1184          161 :     GNUNET_JSON_spec_mark_optional (
    1185              :       GNUNET_JSON_spec_object_copy ("extra",
    1186              :                                     &contract->extra),
    1187              :       NULL),
    1188          161 :     GNUNET_JSON_spec_mark_optional (
    1189              :       GNUNET_JSON_spec_uint8 ("minimum_age",
    1190              :                               &contract->minimum_age),
    1191              :       NULL),
    1192          161 :     GNUNET_JSON_spec_end ()
    1193              :   };
    1194              : 
    1195              :   enum GNUNET_GenericReturnValue res;
    1196              :   const char *ename;
    1197              :   unsigned int eline;
    1198              : 
    1199          161 :   GNUNET_assert (NULL != input);
    1200          161 :   res = GNUNET_JSON_parse (input,
    1201              :                            espec,
    1202              :                            &ename,
    1203              :                            &eline);
    1204          161 :   if (GNUNET_OK != res)
    1205              :   {
    1206            0 :     GNUNET_break (0);
    1207            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1208              :                 "Failed to parse contract at field %s\n",
    1209              :                 ename);
    1210            0 :     goto cleanup;
    1211              :   }
    1212              : 
    1213          161 :   switch (contract->version)
    1214              :   {
    1215          153 :   case TALER_MERCHANT_CONTRACT_VERSION_0:
    1216          153 :     res = parse_contract_v0 (input,
    1217              :                              contract);
    1218          153 :     break;
    1219            8 :   case TALER_MERCHANT_CONTRACT_VERSION_1:
    1220            8 :     res = parse_contract_v1 (input,
    1221              :                              contract);
    1222            8 :     break;
    1223              :   }
    1224              : 
    1225          161 :   if (GNUNET_OK != res)
    1226              :   {
    1227            0 :     GNUNET_break (0);
    1228            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1229              :                 "Failed to parse contract\n");
    1230            0 :     goto cleanup;
    1231              :   }
    1232          161 :   return contract;
    1233              : 
    1234            0 : cleanup:
    1235            0 :   TALER_MERCHANT_contract_free (contract);
    1236            0 :   return NULL;
    1237              : }
    1238              : 
    1239              : 
    1240              : void
    1241          161 : TALER_MERCHANT_contract_free (
    1242              :   struct TALER_MERCHANT_Contract *contract)
    1243              : {
    1244          161 :   if (NULL == contract)
    1245            0 :     return;
    1246          161 :   GNUNET_free (contract->public_reorder_url);
    1247          161 :   GNUNET_free (contract->order_id);
    1248          161 :   GNUNET_free (contract->merchant_base_url);
    1249          161 :   GNUNET_free (contract->merchant.name);
    1250          161 :   GNUNET_free (contract->merchant.website);
    1251          161 :   GNUNET_free (contract->merchant.email);
    1252          161 :   GNUNET_free (contract->merchant.logo);
    1253          161 :   if (NULL != contract->merchant.address)
    1254              :   {
    1255          161 :     json_decref (contract->merchant.address);
    1256          161 :     contract->merchant.address = NULL;
    1257              :   }
    1258          161 :   if (NULL != contract->merchant.jurisdiction)
    1259              :   {
    1260          161 :     json_decref (contract->merchant.jurisdiction);
    1261          161 :     contract->merchant.jurisdiction = NULL;
    1262              :   }
    1263          161 :   GNUNET_free (contract->summary);
    1264          161 :   GNUNET_free (contract->fulfillment_url);
    1265          161 :   GNUNET_free (contract->fulfillment_message);
    1266          161 :   if (NULL != contract->fulfillment_message_i18n)
    1267              :   {
    1268            2 :     json_decref (contract->fulfillment_message_i18n);
    1269            2 :     contract->fulfillment_message_i18n = NULL;
    1270              :   }
    1271          161 :   if (NULL != contract->products)
    1272              :   {
    1273          161 :     json_decref (contract->products);
    1274          161 :     contract->products = NULL;
    1275              :   }
    1276          161 :   GNUNET_free (contract->wire_method);
    1277          161 :   if (NULL != contract->exchanges)
    1278              :   {
    1279          161 :     json_decref (contract->exchanges);
    1280          161 :     contract->exchanges = NULL;
    1281              :   }
    1282          161 :   if (NULL != contract->delivery_location)
    1283              :   {
    1284            2 :     json_decref (contract->delivery_location);
    1285            2 :     contract->delivery_location = NULL;
    1286              :   }
    1287          161 :   GNUNET_free (contract->nonce);
    1288          161 :   if (NULL != contract->extra)
    1289              :   {
    1290            2 :     json_decref (contract->extra);
    1291            2 :     contract->extra = NULL;
    1292              :   }
    1293              : 
    1294          161 :   switch (contract->version)
    1295              :   {
    1296          153 :   case TALER_MERCHANT_CONTRACT_VERSION_0:
    1297          153 :     break;
    1298            8 :   case TALER_MERCHANT_CONTRACT_VERSION_1:
    1299            8 :     for (unsigned int i = 0;
    1300           17 :          i < contract->details.v1.choices_len;
    1301            9 :          i++)
    1302            9 :       TALER_MERCHANT_contract_choice_free (&contract->details.v1.choices[i]);
    1303            8 :     GNUNET_free (contract->details.v1.choices);
    1304            8 :     for (unsigned int i = 0;
    1305           17 :          i < contract->details.v1.token_authorities_len;
    1306            9 :          i++)
    1307            9 :       contract_token_family_free (&contract->details.v1.token_authorities[i]);
    1308            8 :     GNUNET_free (contract->details.v1.token_authorities);
    1309            8 :     break;
    1310              :   }
    1311          161 :   GNUNET_free (contract);
    1312              : }
        

Generated by: LCOV version 2.0-1