LCOV - code coverage report
Current view: top level - lib - merchant_api_post-private-products.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 190 0
Test Date: 2026-04-12 12:58:13 Functions: 0.0 % 5 0

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2020-2026 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify
       6              :   it under the terms of the GNU Lesser General Public License as
       7              :   published by the Free Software Foundation; either version 2.1,
       8              :   or (at your option) any later version.
       9              : 
      10              :   TALER is distributed in the hope that it will be useful,
      11              :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :   GNU Lesser General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU Lesser General
      16              :   Public License along with TALER; see the file COPYING.LGPL.
      17              :   If not, see <http://www.gnu.org/licenses/>
      18              : */
      19              : /**
      20              :  * @file merchant_api_post-private-products-new.c
      21              :  * @brief Implementation of the POST /private/products request
      22              :  * @author Christian Grothoff
      23              :  */
      24              : #include "taler/platform.h"
      25              : #include <curl/curl.h>
      26              : #include <jansson.h>
      27              : #include <microhttpd.h> /* just for HTTP status codes */
      28              : #include <gnunet/gnunet_util_lib.h>
      29              : #include <gnunet/gnunet_curl_lib.h>
      30              : #include <taler/merchant/post-private-products.h>
      31              : #include "merchant_api_curl_defaults.h"
      32              : #include "merchant_api_common.h"
      33              : #include <taler/taler_json_lib.h>
      34              : #include <taler/taler_curl_lib.h>
      35              : 
      36              : 
      37              : /**
      38              :  * Handle for a POST /private/products operation.
      39              :  */
      40              : struct TALER_MERCHANT_PostPrivateProductsHandle
      41              : {
      42              :   /**
      43              :    * Base URL of the merchant backend.
      44              :    */
      45              :   char *base_url;
      46              : 
      47              :   /**
      48              :    * The full URL for this request.
      49              :    */
      50              :   char *url;
      51              : 
      52              :   /**
      53              :    * Handle for the request.
      54              :    */
      55              :   struct GNUNET_CURL_Job *job;
      56              : 
      57              :   /**
      58              :    * Function to call with the result.
      59              :    */
      60              :   TALER_MERCHANT_PostPrivateProductsCallback cb;
      61              : 
      62              :   /**
      63              :    * Closure for @a cb.
      64              :    */
      65              :   TALER_MERCHANT_POST_PRIVATE_PRODUCTS_RESULT_CLOSURE *cb_cls;
      66              : 
      67              :   /**
      68              :    * Reference to the execution context.
      69              :    */
      70              :   struct GNUNET_CURL_Context *ctx;
      71              : 
      72              :   /**
      73              :    * Minor context that holds body and headers.
      74              :    */
      75              :   struct TALER_CURL_PostContext post_ctx;
      76              : 
      77              :   /**
      78              :    * Product identifier.
      79              :    */
      80              :   char *product_id;
      81              : 
      82              :   /**
      83              :    * Human-readable description.
      84              :    */
      85              :   char *description;
      86              : 
      87              :   /**
      88              :    * Unit of measurement.
      89              :    */
      90              :   char *unit;
      91              : 
      92              :   /**
      93              :    * Product image (base64-encoded or empty), set via option.
      94              :    */
      95              :   char *image;
      96              : 
      97              :   /**
      98              :    * Explicit product name (if different from description).
      99              :    */
     100              :   char *product_name;
     101              : 
     102              :   /**
     103              :    * Total stock (-1 for unlimited).
     104              :    */
     105              :   int64_t total_stock;
     106              : 
     107              :   /**
     108              :    * Product group ID.
     109              :    */
     110              :   uint64_t product_group_id;
     111              : 
     112              :   /**
     113              :    * Whether product_group_id has been set.
     114              :    */
     115              :   bool have_product_group_id;
     116              : 
     117              :   /**
     118              :    * Money pot ID.
     119              :    */
     120              :   uint64_t money_pot_id;
     121              : 
     122              :   /**
     123              :    * Whether money_pot_id has been set.
     124              :    */
     125              :   bool have_money_pot_id;
     126              : 
     127              :   /**
     128              :    * Whether the price is net (before tax).
     129              :    */
     130              :   bool price_is_net;
     131              : 
     132              :   /**
     133              :    * Whether price_is_net has been set.
     134              :    */
     135              :   bool have_price_is_net;
     136              : 
     137              :   /**
     138              :    * Optional internationalized descriptions (JSON).
     139              :    */
     140              :   json_t *description_i18n;
     141              : 
     142              :   /**
     143              :    * Optional tax information (JSON array).
     144              :    */
     145              :   json_t *taxes;
     146              : 
     147              :   /**
     148              :    * Optional storage location (JSON).
     149              :    */
     150              :   json_t *address;
     151              : 
     152              :   /**
     153              :    * Optional expected restock time.
     154              :    */
     155              :   struct GNUNET_TIME_Timestamp next_restock;
     156              : 
     157              :   /**
     158              :    * Whether next_restock has been set.
     159              :    */
     160              :   bool have_next_restock;
     161              : 
     162              :   /**
     163              :    * Optional minimum age requirement.
     164              :    */
     165              :   uint32_t minimum_age;
     166              : 
     167              :   /**
     168              :    * Whether minimum_age has been set.
     169              :    */
     170              :   bool have_minimum_age;
     171              : 
     172              :   /**
     173              :    * Optional category IDs.
     174              :    */
     175              :   uint64_t *cats;
     176              : 
     177              :   /**
     178              :    * Number of category IDs.
     179              :    */
     180              :   unsigned int num_cats;
     181              : 
     182              :   /**
     183              :    * Array of unit prices.
     184              :    */
     185              :   struct TALER_Amount *unit_prices;
     186              : 
     187              :   /**
     188              :    * Length of @e unit_prices array.
     189              :    */
     190              :   size_t unit_prices_len;
     191              : 
     192              :   /**
     193              :    * Fractional part of total stock.
     194              :    */
     195              :   uint32_t total_stock_frac;
     196              : 
     197              :   /**
     198              :    * Whether fractional quantities are allowed.
     199              :    */
     200              :   bool unit_allow_fraction;
     201              : 
     202              :   /**
     203              :    * Whether unit_allow_fraction has been set.
     204              :    */
     205              :   bool have_unit_allow_fraction;
     206              : 
     207              :   /**
     208              :    * Precision level for fractions.
     209              :    */
     210              :   uint32_t unit_precision_level;
     211              : 
     212              :   /**
     213              :    * Whether unit_precision_level has been set.
     214              :    */
     215              :   bool have_unit_precision_level;
     216              : };
     217              : 
     218              : 
     219              : /**
     220              :  * Function called when we're done processing the
     221              :  * HTTP POST /private/products request.
     222              :  *
     223              :  * @param cls the `struct TALER_MERCHANT_PostPrivateProductsHandle`
     224              :  * @param response_code HTTP response code, 0 on error
     225              :  * @param response response body, NULL if not in JSON
     226              :  */
     227              : static void
     228            0 : handle_post_products_finished (void *cls,
     229              :                                long response_code,
     230              :                                const void *response)
     231              : {
     232            0 :   struct TALER_MERCHANT_PostPrivateProductsHandle *ppph = cls;
     233            0 :   const json_t *json = response;
     234            0 :   struct TALER_MERCHANT_PostPrivateProductsResponse ppr = {
     235            0 :     .hr.http_status = (unsigned int) response_code,
     236              :     .hr.reply = json
     237              :   };
     238              : 
     239            0 :   ppph->job = NULL;
     240            0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     241              :               "POST /private/products completed with response code %u\n",
     242              :               (unsigned int) response_code);
     243            0 :   switch (response_code)
     244              :   {
     245            0 :   case 0:
     246            0 :     ppr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     247            0 :     break;
     248            0 :   case MHD_HTTP_NO_CONTENT:
     249            0 :     break;
     250            0 :   case MHD_HTTP_BAD_REQUEST:
     251            0 :     ppr.hr.ec = TALER_JSON_get_error_code (json);
     252            0 :     ppr.hr.hint = TALER_JSON_get_error_hint (json);
     253            0 :     break;
     254            0 :   case MHD_HTTP_UNAUTHORIZED:
     255            0 :     ppr.hr.ec = TALER_JSON_get_error_code (json);
     256            0 :     ppr.hr.hint = TALER_JSON_get_error_hint (json);
     257            0 :     break;
     258            0 :   case MHD_HTTP_FORBIDDEN:
     259            0 :     ppr.hr.ec = TALER_JSON_get_error_code (json);
     260            0 :     ppr.hr.hint = TALER_JSON_get_error_hint (json);
     261            0 :     break;
     262            0 :   case MHD_HTTP_NOT_FOUND:
     263            0 :     ppr.hr.ec = TALER_JSON_get_error_code (json);
     264            0 :     ppr.hr.hint = TALER_JSON_get_error_hint (json);
     265            0 :     break;
     266            0 :   case MHD_HTTP_CONFLICT:
     267            0 :     ppr.hr.ec = TALER_JSON_get_error_code (json);
     268            0 :     ppr.hr.hint = TALER_JSON_get_error_hint (json);
     269            0 :     break;
     270            0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     271            0 :     ppr.hr.ec = TALER_JSON_get_error_code (json);
     272            0 :     ppr.hr.hint = TALER_JSON_get_error_hint (json);
     273            0 :     break;
     274            0 :   default:
     275            0 :     TALER_MERCHANT_parse_error_details_ (json,
     276              :                                          response_code,
     277              :                                          &ppr.hr);
     278            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     279              :                 "Unexpected response code %u/%d\n",
     280              :                 (unsigned int) response_code,
     281              :                 (int) ppr.hr.ec);
     282            0 :     GNUNET_break_op (0);
     283            0 :     break;
     284              :   }
     285            0 :   ppph->cb (ppph->cb_cls,
     286              :             &ppr);
     287            0 :   TALER_MERCHANT_post_private_products_cancel (ppph);
     288            0 : }
     289              : 
     290              : 
     291              : struct TALER_MERCHANT_PostPrivateProductsHandle *
     292            0 : TALER_MERCHANT_post_private_products_create (
     293              :   struct GNUNET_CURL_Context *ctx,
     294              :   const char *url,
     295              :   const char *product_id,
     296              :   const char *description,
     297              :   const char *unit,
     298              :   unsigned int num_prices,
     299              :   const struct TALER_Amount prices[static num_prices])
     300            0 : {
     301              :   struct TALER_MERCHANT_PostPrivateProductsHandle *ppph;
     302              : 
     303            0 :   ppph = GNUNET_new (struct TALER_MERCHANT_PostPrivateProductsHandle);
     304            0 :   ppph->ctx = ctx;
     305            0 :   ppph->base_url = GNUNET_strdup (url);
     306            0 :   ppph->product_id = GNUNET_strdup (product_id);
     307            0 :   ppph->description = GNUNET_strdup (description);
     308            0 :   ppph->unit = GNUNET_strdup (unit);
     309            0 :   ppph->unit_prices_len = num_prices;
     310            0 :   ppph->unit_prices = GNUNET_new_array (num_prices,
     311              :                                         struct TALER_Amount);
     312            0 :   memcpy (ppph->unit_prices,
     313              :           prices,
     314              :           num_prices * sizeof (struct TALER_Amount));
     315            0 :   return ppph;
     316              : }
     317              : 
     318              : 
     319              : enum GNUNET_GenericReturnValue
     320            0 : TALER_MERCHANT_post_private_products_set_options_ (
     321              :   struct TALER_MERCHANT_PostPrivateProductsHandle *ppph,
     322              :   unsigned int num_options,
     323              :   const struct TALER_MERCHANT_PostPrivateProductsOptionValue *options)
     324              : {
     325            0 :   for (unsigned int i = 0; i < num_options; i++)
     326              :   {
     327            0 :     switch (options[i].option)
     328              :     {
     329            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_END:
     330            0 :       return GNUNET_OK;
     331            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_DESCRIPTION_I18N:
     332            0 :       json_decref (ppph->description_i18n);
     333            0 :       ppph->description_i18n = json_incref ((json_t *) options[i].details.
     334              :                                             description_i18n);
     335            0 :       continue;
     336            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_TAXES:
     337            0 :       json_decref (ppph->taxes);
     338            0 :       ppph->taxes = json_incref ((json_t *) options[i].details.taxes);
     339            0 :       continue;
     340            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_ADDRESS:
     341            0 :       json_decref (ppph->address);
     342            0 :       ppph->address = json_incref ((json_t *) options[i].details.address);
     343            0 :       continue;
     344            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_NEXT_RESTOCK:
     345            0 :       ppph->next_restock = options[i].details.next_restock;
     346            0 :       ppph->have_next_restock = true;
     347            0 :       continue;
     348            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_MINIMUM_AGE:
     349            0 :       ppph->minimum_age = options[i].details.minimum_age;
     350            0 :       ppph->have_minimum_age = true;
     351            0 :       continue;
     352            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_CATEGORIES:
     353            0 :       ppph->num_cats = options[i].details.categories.num;
     354            0 :       GNUNET_free (ppph->cats);
     355            0 :       ppph->cats = GNUNET_new_array (ppph->num_cats,
     356              :                                      uint64_t);
     357            0 :       memcpy (ppph->cats,
     358            0 :               options[i].details.categories.cats,
     359            0 :               ppph->num_cats * sizeof (uint64_t));
     360            0 :       continue;
     361            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_TOTAL_STOCK_FRAC:
     362            0 :       ppph->total_stock_frac = options[i].details.total_stock.frac;
     363            0 :       continue;
     364            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_TOTAL_STOCK_VAL:
     365            0 :       ppph->total_stock = options[i].details.total_stock.val;
     366            0 :       continue;
     367            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_TOTAL_STOCK:
     368            0 :       ppph->total_stock_frac = options[i].details.total_stock.frac;
     369            0 :       ppph->total_stock = options[i].details.total_stock.val;
     370            0 :       continue;
     371            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_UNIT_ALLOW_FRACTION:
     372            0 :       ppph->unit_allow_fraction = options[i].details.unit_allow_fraction;
     373            0 :       ppph->have_unit_allow_fraction = true;
     374            0 :       continue;
     375            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_UNIT_PRECISION_LEVEL:
     376            0 :       ppph->unit_precision_level = options[i].details.unit_precision_level;
     377            0 :       ppph->have_unit_precision_level = true;
     378            0 :       continue;
     379            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_PRODUCT_NAME:
     380            0 :       GNUNET_free (ppph->product_name);
     381            0 :       ppph->product_name = GNUNET_strdup (options[i].details.product_name);
     382            0 :       continue;
     383            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_IMAGE:
     384            0 :       GNUNET_free (ppph->image);
     385            0 :       ppph->image = GNUNET_strdup (options[i].details.image);
     386            0 :       continue;
     387            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_PRODUCT_GROUP_ID:
     388            0 :       ppph->product_group_id = options[i].details.product_group_id;
     389            0 :       ppph->have_product_group_id = true;
     390            0 :       continue;
     391            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_MONEY_POT_ID:
     392            0 :       ppph->money_pot_id = options[i].details.money_pot_id;
     393            0 :       ppph->have_money_pot_id = true;
     394            0 :       continue;
     395            0 :     case TALER_MERCHANT_POST_PRIVATE_PRODUCTS_OPTION_PRICE_IS_NET:
     396            0 :       ppph->price_is_net = options[i].details.price_is_net;
     397            0 :       ppph->have_price_is_net = true;
     398            0 :       continue;
     399              :     }
     400            0 :     GNUNET_break (0);
     401            0 :     return GNUNET_SYSERR;
     402              :   }
     403            0 :   return GNUNET_OK;
     404              : }
     405              : 
     406              : 
     407              : enum TALER_ErrorCode
     408            0 : TALER_MERCHANT_post_private_products_start (
     409              :   struct TALER_MERCHANT_PostPrivateProductsHandle *ppph,
     410              :   TALER_MERCHANT_PostPrivateProductsCallback cb,
     411              :   TALER_MERCHANT_POST_PRIVATE_PRODUCTS_RESULT_CLOSURE *cb_cls)
     412              : {
     413              :   json_t *req_obj;
     414              :   json_t *categories;
     415              :   CURL *eh;
     416              :   char unit_total_stock_buf[64];
     417              : 
     418            0 :   ppph->cb = cb;
     419            0 :   ppph->cb_cls = cb_cls;
     420            0 :   ppph->url = TALER_url_join (ppph->base_url,
     421              :                               "private/products",
     422              :                               NULL);
     423            0 :   if (NULL == ppph->url)
     424            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     425              : 
     426            0 :   TALER_MERCHANT_format_stock_string (ppph->total_stock,
     427              :                                       ppph->total_stock_frac,
     428              :                                       unit_total_stock_buf,
     429              :                                       sizeof (unit_total_stock_buf));
     430              : 
     431            0 :   if (0 == ppph->num_cats)
     432              :   {
     433            0 :     categories = NULL;
     434              :   }
     435              :   else
     436              :   {
     437            0 :     categories = json_array ();
     438            0 :     GNUNET_assert (NULL != categories);
     439            0 :     for (unsigned int i = 0; i < ppph->num_cats; i++)
     440            0 :       GNUNET_assert (0 ==
     441              :                      json_array_append_new (categories,
     442              :                                             json_integer (ppph->cats[i])));
     443              :   }
     444              : 
     445            0 :   req_obj = GNUNET_JSON_PACK (
     446              :     GNUNET_JSON_pack_string ("product_id",
     447              :                              ppph->product_id),
     448              :     GNUNET_JSON_pack_string ("product_name",
     449              :                              (NULL != ppph->product_name)
     450              :                              ? ppph->product_name
     451              :                              : ppph->description),
     452              :     GNUNET_JSON_pack_string ("description",
     453              :                              ppph->description),
     454              :     GNUNET_JSON_pack_allow_null (
     455              :       GNUNET_JSON_pack_object_incref ("description_i18n",
     456              :                                       ppph->description_i18n)),
     457              :     GNUNET_JSON_pack_allow_null (
     458              :       GNUNET_JSON_pack_array_steal ("categories",
     459              :                                     categories)),
     460              :     GNUNET_JSON_pack_string ("unit",
     461              :                              ppph->unit),
     462              :     TALER_JSON_pack_amount_array ("unit_price",
     463              :                                   ppph->unit_prices_len,
     464              :                                   ppph->unit_prices),
     465              :     GNUNET_JSON_pack_allow_null (
     466              :       GNUNET_JSON_pack_string ("image",
     467              :                                ppph->image)),
     468              :     GNUNET_JSON_pack_allow_null (
     469              :       GNUNET_JSON_pack_array_incref ("taxes",
     470              :                                      ppph->taxes)),
     471              :     GNUNET_JSON_pack_string ("unit_total_stock",
     472              :                              unit_total_stock_buf),
     473              :     GNUNET_JSON_pack_allow_null (
     474              :       GNUNET_JSON_pack_object_incref ("address",
     475              :                                       ppph->address)),
     476              :     GNUNET_JSON_pack_allow_null (
     477              :       GNUNET_JSON_pack_timestamp ("next_restock",
     478              :                                   ppph->have_next_restock
     479              :                                   ? ppph->next_restock
     480              :                                   : GNUNET_TIME_UNIT_ZERO_TS)));
     481            0 :   if (ppph->have_minimum_age)
     482              :   {
     483            0 :     GNUNET_assert (0 ==
     484              :                    json_object_set_new (req_obj,
     485              :                                         "minimum_age",
     486              :                                         json_integer (
     487              :                                           ppph->minimum_age)));
     488              :   }
     489            0 :   if (ppph->have_product_group_id)
     490              :   {
     491            0 :     GNUNET_assert (0 ==
     492              :                    json_object_set_new (req_obj,
     493              :                                         "product_group_id",
     494              :                                         json_integer (
     495              :                                           ppph->product_group_id)));
     496              :   }
     497            0 :   if (ppph->have_money_pot_id)
     498              :   {
     499            0 :     GNUNET_assert (0 ==
     500              :                    json_object_set_new (req_obj,
     501              :                                         "money_pot_id",
     502              :                                         json_integer (
     503              :                                           ppph->money_pot_id)));
     504              :   }
     505            0 :   if (ppph->have_price_is_net)
     506              :   {
     507            0 :     GNUNET_assert (0 ==
     508              :                    json_object_set_new (req_obj,
     509              :                                         "price_is_net",
     510              :                                         json_boolean (
     511              :                                           ppph->price_is_net)));
     512              :   }
     513            0 :   if (ppph->have_unit_allow_fraction &&
     514            0 :       ppph->unit_allow_fraction)
     515              :   {
     516            0 :     GNUNET_assert (0 ==
     517              :                    json_object_set_new (req_obj,
     518              :                                         "unit_allow_fraction",
     519              :                                         json_true ()));
     520            0 :     if (ppph->have_unit_precision_level)
     521              :     {
     522            0 :       GNUNET_assert (0 ==
     523              :                      json_object_set_new (req_obj,
     524              :                                           "unit_precision_level",
     525              :                                           json_integer (
     526              :                                             ppph->unit_precision_level)));
     527              :     }
     528              :   }
     529            0 :   eh = TALER_MERCHANT_curl_easy_get_ (ppph->url);
     530            0 :   if ( (NULL == eh) ||
     531              :        (GNUNET_OK !=
     532            0 :         TALER_curl_easy_post (&ppph->post_ctx,
     533              :                               eh,
     534              :                               req_obj)) )
     535              :   {
     536            0 :     GNUNET_break (0);
     537            0 :     json_decref (req_obj);
     538            0 :     if (NULL != eh)
     539            0 :       curl_easy_cleanup (eh);
     540            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     541              :   }
     542            0 :   json_decref (req_obj);
     543            0 :   ppph->job = GNUNET_CURL_job_add2 (ppph->ctx,
     544              :                                     eh,
     545            0 :                                     ppph->post_ctx.headers,
     546              :                                     &handle_post_products_finished,
     547              :                                     ppph);
     548            0 :   if (NULL == ppph->job)
     549            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     550            0 :   return TALER_EC_NONE;
     551              : }
     552              : 
     553              : 
     554              : void
     555            0 : TALER_MERCHANT_post_private_products_cancel (
     556              :   struct TALER_MERCHANT_PostPrivateProductsHandle *ppph)
     557              : {
     558            0 :   if (NULL != ppph->job)
     559              :   {
     560            0 :     GNUNET_CURL_job_cancel (ppph->job);
     561            0 :     ppph->job = NULL;
     562              :   }
     563            0 :   TALER_curl_easy_post_finished (&ppph->post_ctx);
     564            0 :   json_decref (ppph->description_i18n);
     565            0 :   json_decref (ppph->taxes);
     566            0 :   json_decref (ppph->address);
     567            0 :   GNUNET_free (ppph->cats);
     568            0 :   GNUNET_free (ppph->product_id);
     569            0 :   GNUNET_free (ppph->description);
     570            0 :   GNUNET_free (ppph->unit);
     571            0 :   GNUNET_free (ppph->image);
     572            0 :   GNUNET_free (ppph->product_name);
     573            0 :   GNUNET_free (ppph->url);
     574            0 :   GNUNET_free (ppph->base_url);
     575            0 :   GNUNET_free (ppph);
     576            0 : }
     577              : 
     578              : 
     579              : /* end of merchant_api_post-private-products-new.c */
        

Generated by: LCOV version 2.0-1