merchant

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

taler-merchant-httpd_post-private-orders.c (119082B)


      1 /*
      2   This file is part of TALER
      3   (C) 2014-2025 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU Affero General Public License as
      7   published by the Free Software Foundation; either version 3,
      8   or (at your option) any later version.
      9 
     10   TALER is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with TALER; see the file COPYING.  If not,
     17   see <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file src/backend/taler-merchant-httpd_post-private-orders.c
     22  * @brief the POST /orders handler
     23  * @author Christian Grothoff
     24  * @author Marcello Stanisci
     25  * @author Christian Blättler
     26  */
     27 #include "platform.h"
     28 #include <gnunet/gnunet_common.h>
     29 #include <gnunet/gnunet_db_lib.h>
     30 #include <gnunet/gnunet_json_lib.h>
     31 #include <gnunet/gnunet_time_lib.h>
     32 #include <jansson.h>
     33 #include <microhttpd.h>
     34 #include <string.h>
     35 #include <taler/taler_error_codes.h>
     36 #include <taler/taler_signatures.h>
     37 #include <taler/taler_json_lib.h>
     38 #include <taler/taler_dbevents.h>
     39 #include <taler/taler_util.h>
     40 #include <taler/taler_merchant_util.h>
     41 #include <time.h>
     42 #include "taler-merchant-httpd.h"
     43 #include "taler-merchant-httpd_exchanges.h"
     44 #include "taler-merchant-httpd_post-private-orders.h"
     45 #include "taler-merchant-httpd_token-keys.h"
     46 #include "taler-merchant-httpd_get-exchanges.h"
     47 #include "taler-merchant-httpd_contract.h"
     48 #include "taler-merchant-httpd_helper.h"
     49 #include "taler-merchant-httpd_get-private-orders.h"
     50 #include "merchantdb_lib.h"
     51 #include "merchant-database/start.h"
     52 #include "merchant-database/event_listen.h"
     53 #include "merchant-database/event_notify.h"
     54 #include "merchant-database/preflight.h"
     55 #include "merchant-database/do_expire_locks.h"
     56 #include "merchant-database/get_missing_money_pot.h"
     57 #include "merchant-database/insert_order.h"
     58 #include "merchant-database/insert_order_lock.h"
     59 #include "merchant-database/get_order.h"
     60 #include "merchant-database/get_order_summary.h"
     61 #include "merchant-database/get_product.h"
     62 #include "merchant-database/iterate_token_family_keys.h"
     63 #include "merchant-database/iterate_donau_instances_filtered.h"
     64 #include "merchant-database/get_otp_device.h"
     65 #include "merchant-database/delete_inventory_lock.h"
     66 
     67 
     68 /**
     69  * How often do we retry the simple INSERT database transaction?
     70  */
     71 #define MAX_RETRIES 3
     72 
     73 /**
     74  * Maximum number of inventory products per order.
     75  */
     76 #define MAX_PRODUCTS 1024
     77 
     78 /**
     79  * What is the label under which we find/place the merchant's
     80  * jurisdiction in the locations list by default?
     81  */
     82 #define STANDARD_LABEL_MERCHANT_JURISDICTION "_mj"
     83 
     84 /**
     85  * What is the label under which we find/place the merchant's
     86  * address in the locations list by default?
     87  */
     88 #define STANDARD_LABEL_MERCHANT_ADDRESS "_ma"
     89 
     90 /**
     91  * How long do we wait at most for /keys from the exchange(s)?
     92  * Ensures that we do not block forever just because some exchange
     93  * fails to respond *or* because our taler-merchant-keyscheck
     94  * refuses a forced download.
     95  */
     96 #define MAX_KEYS_WAIT \
     97   GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 2500)
     98 
     99 /**
    100  * Generate the base URL for the given merchant instance.
    101  *
    102  * @param connection the MHD connection
    103  * @param instance_id the merchant instance ID
    104  * @returns the merchant instance's base URL
    105  */
    106 static char *
    107 make_merchant_base_url (struct MHD_Connection *connection,
    108                         const char *instance_id)
    109 {
    110   struct GNUNET_Buffer buf;
    111 
    112   if (GNUNET_OK !=
    113       TMH_base_url_by_connection (connection,
    114                                   instance_id,
    115                                   &buf))
    116     return NULL;
    117   GNUNET_buffer_write_path (&buf,
    118                             "");
    119   return GNUNET_buffer_reap_str (&buf);
    120 }
    121 
    122 
    123 /**
    124  * Information about a product we are supposed to add to the order
    125  * based on what we know it from our inventory.
    126  */
    127 struct InventoryProduct
    128 {
    129   /**
    130    * Identifier of the product in the inventory.
    131    */
    132   const char *product_id;
    133 
    134   /**
    135    * Number of units of the product to add to the order (integer part).
    136    */
    137   uint64_t quantity;
    138 
    139   /**
    140    * Fractional part of the quantity in units of 1/1000000 of the base value.
    141    */
    142   uint32_t quantity_frac;
    143 
    144   /**
    145    * True if the integer quantity field was missing in the request.
    146    */
    147   bool quantity_missing;
    148 
    149   /**
    150    * String representation of the quantity, if supplied.
    151    */
    152   const char *unit_quantity;
    153 
    154   /**
    155    * True if the string quantity field was missing in the request.
    156    */
    157   bool unit_quantity_missing;
    158 
    159   /**
    160    * Money pot associated with the product. 0 for none.
    161    */
    162   uint64_t product_money_pot;
    163 
    164 };
    165 
    166 
    167 /**
    168  * Handle for a rekey operation where we (re)request
    169  * the /keys from the exchange.
    170  */
    171 struct RekeyExchange
    172 {
    173   /**
    174    * Kept in a DLL.
    175    */
    176   struct RekeyExchange *prev;
    177 
    178   /**
    179    * Kept in a DLL.
    180    */
    181   struct RekeyExchange *next;
    182 
    183   /**
    184    * order this is for.
    185    */
    186   struct OrderContext *oc;
    187 
    188   /**
    189    * Base URL of the exchange.
    190    */
    191   char *url;
    192 
    193   /**
    194    * Request for keys.
    195    */
    196   struct TMH_EXCHANGES_KeysOperation *fo;
    197 
    198 };
    199 
    200 
    201 /**
    202  * Data structure where we evaluate the viability of a given
    203  * wire method for this order.
    204  */
    205 struct WireMethodCandidate
    206 {
    207   /**
    208    * Kept in a DLL.
    209    */
    210   struct WireMethodCandidate *next;
    211 
    212   /**
    213    * Kept in a DLL.
    214    */
    215   struct WireMethodCandidate *prev;
    216 
    217   /**
    218    * The wire method we are evaluating.
    219    */
    220   const struct TMH_WireMethod *wm;
    221 
    222   /**
    223    * List of exchanges to use when we use this wire method.
    224    */
    225   json_t *exchanges;
    226 
    227   /**
    228    * Set of maximum amounts that could be paid over all available exchanges
    229    * for this @a wm. Used to determine if this order creation requests exceeds
    230    * legal limits.
    231    */
    232   struct TALER_AmountSet total_exchange_limits;
    233 
    234 };
    235 
    236 
    237 /**
    238  * Information we keep per order we are processing.
    239  */
    240 struct OrderContext
    241 {
    242   /**
    243    * Information set in the #ORDER_PHASE_PARSE_REQUEST phase.
    244    */
    245   struct
    246   {
    247     /**
    248      * Order field of the request
    249      */
    250     json_t *order;
    251 
    252     /**
    253      * Set to how long refunds will be allowed.
    254      */
    255     struct GNUNET_TIME_Relative refund_delay;
    256 
    257     /**
    258      * RFC8905 payment target type to find a matching merchant account
    259      */
    260     const char *payment_target;
    261 
    262     /**
    263      * Shared key to use with @e pos_algorithm.
    264      */
    265     char *pos_key;
    266 
    267     /**
    268      * Selected algorithm (by template) when we are to
    269      * generate an OTP code for payment confirmation.
    270      */
    271     enum TALER_MerchantConfirmationAlgorithm pos_algorithm;
    272 
    273     /**
    274      * Challenge from the offline verifier to sign once the order is
    275      * paid.  Only meaningful when @e pos_algorithm is a
    276      * challenge-signature algorithm: the parser rejects a request
    277      * that pairs a challenge with any other algorithm.
    278      */
    279     struct TALER_PosChallengeP pos_challenge;
    280 
    281     /**
    282      * Hash of the POST request data, used to detect
    283      * idempotent requests.
    284      */
    285     struct TALER_MerchantPostDataHashP h_post_data;
    286 
    287     /**
    288      * Length of the @e inventory_products array.
    289      */
    290     unsigned int inventory_products_length;
    291 
    292     /**
    293      * Specifies that some products are to be included in the
    294      * order from the inventory. For these inventory management
    295      * is performed (so the products must be in stock).
    296      */
    297     struct InventoryProduct *inventory_products;
    298 
    299     /**
    300      * Length of the @e uuids array.
    301      */
    302     unsigned int uuids_length;
    303 
    304     /**
    305      * array of UUIDs used to reserve products from @a inventory_products.
    306      */
    307     struct GNUNET_Uuid *uuids;
    308 
    309     /**
    310      * Claim token for the request.
    311      */
    312     struct TALER_ClaimTokenP claim_token;
    313 
    314     /**
    315      * Session ID (optional) to use for the order.
    316      */
    317     const char *session_id;
    318 
    319   } parse_request;
    320 
    321   /**
    322    * Information set in the #ORDER_PHASE_PARSE_ORDER phase.
    323    */
    324   struct
    325   {
    326 
    327     /**
    328      * The main order data as provided by the client.
    329      */
    330     struct TALER_MERCHANT_Order *order;
    331 
    332     /**
    333      * Base URL of this merchant.
    334      */
    335     char *merchant_base_url;
    336 
    337     /**
    338      * Wire transfer round-up interval to apply.
    339      */
    340     enum GNUNET_TIME_RounderInterval wire_deadline_rounder;
    341 
    342   } parse_order;
    343 
    344   /**
    345    * Information set in the #ORDER_PHASE_PARSE_CHOICES phase.
    346    */
    347   struct
    348   {
    349     /**
    350      * Array of possible specific contracts the wallet/customer may choose
    351      * from by selecting the respective index when signing the deposit
    352      * confirmation.
    353      */
    354     struct TALER_MERCHANT_ContractChoice *choices;
    355 
    356     /**
    357      * Length of the @e choices array.
    358      */
    359     unsigned int choices_len;
    360 
    361     /**
    362      * Array of token families referenced in the contract.
    363      */
    364     struct TALER_MERCHANT_ContractTokenFamily *token_families;
    365 
    366     /**
    367      * Length of the @e token_families array.
    368      */
    369     unsigned int token_families_len;
    370   } parse_choices;
    371 
    372   /**
    373    * Information set in the #ORDER_PHASE_MERGE_INVENTORY phase.
    374    */
    375   struct
    376   {
    377     /**
    378      * Merged array of products in the @e order.
    379      */
    380     json_t *products;
    381   } merge_inventory;
    382 
    383   /**
    384    * Information set in the #ORDER_PHASE_ADD_PAYMENT_DETAILS phase.
    385    */
    386   struct
    387   {
    388 
    389     /**
    390      * DLL of wire methods under evaluation.
    391      */
    392     struct WireMethodCandidate *wmc_head;
    393 
    394     /**
    395      * DLL of wire methods under evaluation.
    396      */
    397     struct WireMethodCandidate *wmc_tail;
    398 
    399     /**
    400      * Array of maximum amounts that appear in the contract choices
    401      * per currency.
    402      * Determines the maximum amounts that a client could pay for this
    403      * order and which we must thus make sure is acceptable for the
    404      * selected wire method/account if possible.
    405      */
    406     struct TALER_Amount *max_choice_limits;
    407 
    408     /**
    409      * Length of the @e max_choice_limits array.
    410      */
    411     unsigned int num_max_choice_limits;
    412 
    413     /**
    414      * Set to true if we may need an exchange. True if any amount is non-zero.
    415      */
    416     bool need_exchange;
    417 
    418   } add_payment_details;
    419 
    420   /**
    421    * Information set in the #ORDER_PHASE_SELECT_WIRE_METHOD phase.
    422    */
    423   struct
    424   {
    425 
    426     /**
    427      * Array of exchanges we find acceptable for this order and wire method.
    428      */
    429     json_t *exchanges;
    430 
    431     /**
    432      * Wire method (and our bank account) we have selected
    433      * to be included for this order.
    434      */
    435     const struct TMH_WireMethod *wm;
    436 
    437   } select_wire_method;
    438 
    439   /**
    440    * Information set in the #ORDER_PHASE_SET_EXCHANGES phase.
    441    */
    442   struct
    443   {
    444 
    445     /**
    446      * Forced requests to /keys to update our exchange
    447      * information.
    448      */
    449     struct RekeyExchange *pending_reload_head;
    450 
    451     /**
    452      * Forced requests to /keys to update our exchange
    453      * information.
    454      */
    455     struct RekeyExchange *pending_reload_tail;
    456 
    457     /**
    458      * How long do we wait at most until giving up on getting keys?
    459      */
    460     struct GNUNET_TIME_Absolute keys_timeout;
    461 
    462     /**
    463      * Task to wake us up on @e keys_timeout.
    464      */
    465     struct GNUNET_SCHEDULER_Task *wakeup_task;
    466 
    467     /**
    468      * Array of reasons why a particular exchange may be
    469      * limited or not be eligible.
    470      */
    471     json_t *exchange_rejections;
    472 
    473     /**
    474      * Did we previously force reloading of /keys from
    475      * all exchanges? Set to 'true' to prevent us from
    476      * doing it again (and again...).
    477      */
    478     bool forced_reload;
    479 
    480     /**
    481      * Did we find a working exchange?
    482      */
    483     bool exchange_ok;
    484 
    485     /**
    486      * Did we find an exchange that justifies
    487      * reloading keys?
    488      */
    489     bool promising_exchange;
    490 
    491     /**
    492      * Set to true once we have attempted to load exchanges
    493      * for the first time.
    494      */
    495     bool exchanges_tried;
    496 
    497     /**
    498      * Details depending on the contract version.
    499      */
    500     union
    501     {
    502 
    503       /**
    504        * Details for contract v0.
    505        */
    506       struct
    507       {
    508         /**
    509          * Maximum fee for @e order based on STEFAN curves.
    510          * Used to set @e max_fee if not provided as part of
    511          * @e order.
    512          */
    513         struct TALER_Amount max_stefan_fee;
    514 
    515       } v0;
    516 
    517       /**
    518        * Details for contract v1.
    519        */
    520       struct
    521       {
    522         /**
    523          * Maximum fee for @e order based on STEFAN curves by
    524          * contract choice.
    525          * Used to set @e max_fee if not provided as part of
    526          * @e order.
    527          */
    528         struct TALER_Amount *max_stefan_fees;
    529 
    530       } v1;
    531 
    532     } details;
    533 
    534   } set_exchanges;
    535 
    536   /**
    537    * Information set in the #ORDER_PHASE_SET_MAX_FEE phase.
    538    */
    539   struct
    540   {
    541 
    542     /**
    543      * Details depending on the contract version.
    544      */
    545     union
    546     {
    547 
    548       /**
    549        * Details for contract v0.
    550        */
    551       struct
    552       {
    553         /**
    554          * Maximum fee
    555          */
    556         struct TALER_Amount max_fee;
    557       } v0;
    558 
    559       /**
    560        * Details for contract v1.
    561        */
    562       struct
    563       {
    564         /**
    565          * Maximum fees by contract choice.
    566          */
    567         struct TALER_Amount *max_fees;
    568 
    569       } v1;
    570 
    571     } details;
    572   } set_max_fee;
    573 
    574   /**
    575    * Information set in the #ORDER_PHASE_EXECUTE_ORDER phase.
    576    */
    577   struct
    578   {
    579     /**
    580      * Which product (by offset) is out of stock, UINT_MAX if all were in-stock.
    581      */
    582     unsigned int out_of_stock_index;
    583 
    584     /**
    585      * Set to a previous claim token *if* @e idempotent
    586      * is also true.
    587      */
    588     struct TALER_ClaimTokenP token;
    589 
    590     /**
    591      * Set to true if the order was idempotent and there
    592      * was an equivalent one before.
    593      */
    594     bool idempotent;
    595 
    596     /**
    597      * Set to true if the order is in conflict with a
    598      * previous order with the same order ID.
    599      */
    600     bool conflict;
    601   } execute_order;
    602 
    603   struct
    604   {
    605     /**
    606      * Contract terms to store in the database.
    607      */
    608     json_t *contract;
    609   } serialize_order;
    610 
    611   /**
    612    * Connection of the request.
    613    */
    614   struct MHD_Connection *connection;
    615 
    616   /**
    617    * Kept in a DLL while suspended.
    618    */
    619   struct OrderContext *next;
    620 
    621   /**
    622    * Kept in a DLL while suspended.
    623    */
    624   struct OrderContext *prev;
    625 
    626   /**
    627    * Handler context for the request.
    628    */
    629   struct TMH_HandlerContext *hc;
    630 
    631   /**
    632    * #GNUNET_YES if suspended.
    633    */
    634   enum GNUNET_GenericReturnValue suspended;
    635 
    636   /**
    637    * Current phase of setting up the order.
    638    */
    639   enum
    640   {
    641     ORDER_PHASE_PARSE_REQUEST,
    642     ORDER_PHASE_PARSE_ORDER,
    643     ORDER_PHASE_PARSE_CHOICES,
    644     ORDER_PHASE_MERGE_INVENTORY,
    645     ORDER_PHASE_ADD_PAYMENT_DETAILS,
    646     ORDER_PHASE_SET_EXCHANGES,
    647     ORDER_PHASE_SELECT_WIRE_METHOD,
    648     ORDER_PHASE_SET_MAX_FEE,
    649     ORDER_PHASE_SERIALIZE_ORDER,
    650     ORDER_PHASE_SALT_FORGETTABLE,
    651     ORDER_PHASE_CHECK_CONTRACT,
    652     ORDER_PHASE_EXECUTE_ORDER,
    653 
    654     /**
    655      * Processing is done, we should return #MHD_YES.
    656      */
    657     ORDER_PHASE_FINISHED_MHD_YES,
    658 
    659     /**
    660      * Processing is done, we should return #MHD_NO.
    661      */
    662     ORDER_PHASE_FINISHED_MHD_NO
    663   } phase;
    664 
    665 
    666 };
    667 
    668 
    669 /**
    670  * Kept in a DLL while suspended.
    671  */
    672 static struct OrderContext *oc_head;
    673 
    674 /**
    675  * Kept in a DLL while suspended.
    676  */
    677 static struct OrderContext *oc_tail;
    678 
    679 
    680 void
    681 TMH_force_orders_resume ()
    682 {
    683   struct OrderContext *oc;
    684 
    685   while (NULL != (oc = oc_head))
    686   {
    687     GNUNET_CONTAINER_DLL_remove (oc_head,
    688                                  oc_tail,
    689                                  oc);
    690     oc->suspended = GNUNET_SYSERR;
    691     MHD_resume_connection (oc->connection);
    692   }
    693 }
    694 
    695 
    696 /**
    697  * Update the phase of @a oc based on @a mret.
    698  *
    699  * @param[in,out] oc order to update phase for
    700  * @param mret #MHD_NO to close with #MHD_NO
    701  *             #MHD_YES to close with #MHD_YES
    702  */
    703 static void
    704 finalize_order (struct OrderContext *oc,
    705                 enum MHD_Result mret)
    706 {
    707   oc->phase = (MHD_YES == mret)
    708     ? ORDER_PHASE_FINISHED_MHD_YES
    709     : ORDER_PHASE_FINISHED_MHD_NO;
    710 }
    711 
    712 
    713 /**
    714  * Update the phase of @a oc based on @a ret.
    715  *
    716  * @param[in,out] oc order to update phase for
    717  * @param ret #GNUNET_SYSERR to close with #MHD_NO
    718  *            #GNUNET_NO to close with #MHD_YES
    719  *            #GNUNET_OK is not allowed!
    720  */
    721 static void
    722 finalize_order2 (struct OrderContext *oc,
    723                  enum GNUNET_GenericReturnValue ret)
    724 {
    725   GNUNET_assert (GNUNET_OK != ret);
    726   oc->phase = (GNUNET_NO == ret)
    727     ? ORDER_PHASE_FINISHED_MHD_YES
    728     : ORDER_PHASE_FINISHED_MHD_NO;
    729 }
    730 
    731 
    732 /**
    733  * Generate an error response for @a oc.
    734  *
    735  * @param[in,out] oc order context to respond to
    736  * @param http_status HTTP status code to set
    737  * @param ec error code to set
    738  * @param detail error message detail to set
    739  */
    740 static void
    741 reply_with_error (struct OrderContext *oc,
    742                   unsigned int http_status,
    743                   enum TALER_ErrorCode ec,
    744                   const char *detail)
    745 {
    746   enum MHD_Result mret;
    747 
    748   mret = TALER_MHD_reply_with_error (oc->connection,
    749                                      http_status,
    750                                      ec,
    751                                      detail);
    752   finalize_order (oc,
    753                   mret);
    754 }
    755 
    756 
    757 /**
    758  * Clean up memory used by @a wmc.
    759  *
    760  * @param[in,out] oc order context the WMC is part of
    761  * @param[in] wmc wire method candidate to free
    762  */
    763 static void
    764 free_wmc (struct OrderContext *oc,
    765           struct WireMethodCandidate *wmc)
    766 {
    767   GNUNET_CONTAINER_DLL_remove (oc->add_payment_details.wmc_head,
    768                                oc->add_payment_details.wmc_tail,
    769                                wmc);
    770   TALER_amount_set_free (&wmc->total_exchange_limits);
    771   json_decref (wmc->exchanges);
    772   GNUNET_free (wmc);
    773 }
    774 
    775 
    776 /**
    777  * Clean up memory used by @a cls.
    778  *
    779  * @param[in] cls the `struct OrderContext` to clean up
    780  */
    781 static void
    782 clean_order (void *cls)
    783 {
    784   struct OrderContext *oc = cls;
    785   struct RekeyExchange *rx;
    786 
    787   while (NULL != oc->add_payment_details.wmc_head)
    788     free_wmc (oc,
    789               oc->add_payment_details.wmc_head);
    790   while (NULL != (rx = oc->set_exchanges.pending_reload_head))
    791   {
    792     GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
    793                                  oc->set_exchanges.pending_reload_tail,
    794                                  rx);
    795     TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
    796     GNUNET_free (rx->url);
    797     GNUNET_free (rx);
    798   }
    799   GNUNET_array_grow (oc->add_payment_details.max_choice_limits,
    800                      oc->add_payment_details.num_max_choice_limits,
    801                      0);
    802   if (NULL != oc->set_exchanges.wakeup_task)
    803   {
    804     GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
    805     oc->set_exchanges.wakeup_task = NULL;
    806   }
    807   if (NULL != oc->select_wire_method.exchanges)
    808   {
    809     json_decref (oc->select_wire_method.exchanges);
    810     oc->select_wire_method.exchanges = NULL;
    811   }
    812   if (NULL != oc->set_exchanges.exchange_rejections)
    813   {
    814     json_decref (oc->set_exchanges.exchange_rejections);
    815     oc->set_exchanges.exchange_rejections = NULL;
    816   }
    817   if (NULL != oc->parse_order.order)
    818   {
    819     switch (oc->parse_order.order->base->version)
    820     {
    821     case TALER_MERCHANT_CONTRACT_VERSION_0:
    822       break;
    823     case TALER_MERCHANT_CONTRACT_VERSION_1:
    824       GNUNET_free (oc->set_max_fee.details.v1.max_fees);
    825       GNUNET_free (oc->set_exchanges.details.v1.max_stefan_fees);
    826       break;
    827     }
    828     TALER_MERCHANT_order_free (oc->parse_order.order);
    829     oc->parse_order.order = NULL;
    830     GNUNET_free (oc->parse_order.merchant_base_url);
    831   }
    832   if (NULL != oc->merge_inventory.products)
    833   {
    834     json_decref (oc->merge_inventory.products);
    835     oc->merge_inventory.products = NULL;
    836   }
    837   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
    838   {
    839     TALER_MERCHANT_contract_choice_free (&oc->parse_choices.choices[i]);
    840   }
    841   GNUNET_array_grow (oc->parse_choices.choices,
    842                      oc->parse_choices.choices_len,
    843                      0);
    844   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
    845   {
    846     TALER_MERCHANT_contract_token_family_free (
    847       &oc->parse_choices.token_families[i]);
    848   }
    849   GNUNET_array_grow (oc->parse_choices.token_families,
    850                      oc->parse_choices.token_families_len,
    851                      0);
    852   GNUNET_array_grow (oc->parse_request.inventory_products,
    853                      oc->parse_request.inventory_products_length,
    854                      0);
    855   GNUNET_array_grow (oc->parse_request.uuids,
    856                      oc->parse_request.uuids_length,
    857                      0);
    858   GNUNET_free (oc->parse_request.pos_key);
    859   json_decref (oc->parse_request.order);
    860   json_decref (oc->serialize_order.contract);
    861   GNUNET_free (oc);
    862 }
    863 
    864 
    865 /* ***************** ORDER_PHASE_EXECUTE_ORDER **************** */
    866 
    867 /**
    868  * Compute the quantity (integer and fractional parts) of a product that is
    869  * actually available for a new order.  This excludes units already sold,
    870  * lost, or currently reserved by locks (shopping carts and unpaid orders).
    871  *
    872  * @param pd product details with current totals/sold/lost/locked
    873  * @param[out] available_value remaining whole units (normalized, non-negative)
    874  * @param[out] available_frac remaining fractional units (0..TALER_MERCHANT_UNIT_FRAC_BASE-1)
    875  */
    876 static void
    877 compute_available_quantity (
    878   const struct TALER_MERCHANTDB_ProductDetails *pd,
    879   uint64_t *available_value,
    880   uint32_t *available_frac)
    881 {
    882   int64_t value;
    883   int64_t frac;
    884 
    885   GNUNET_assert (NULL != available_value);
    886   GNUNET_assert (NULL != available_frac);
    887 
    888   if ( (INT64_MAX == pd->total_stock) &&
    889        (INT32_MAX == pd->total_stock_frac) )
    890   {
    891     *available_value = pd->total_stock;
    892     *available_frac = pd->total_stock_frac;
    893     return;
    894   }
    895 
    896   value = (int64_t) pd->total_stock
    897           - (int64_t) pd->total_sold
    898           - (int64_t) pd->total_lost
    899           - (int64_t) pd->total_locked;
    900   frac = (int64_t) pd->total_stock_frac
    901          - (int64_t) pd->total_sold_frac
    902          - (int64_t) pd->total_lost_frac
    903          - (int64_t) pd->total_locked_frac;
    904 
    905   if (frac < 0)
    906   {
    907     int64_t borrow = ((-frac) + TALER_MERCHANT_UNIT_FRAC_BASE - 1)
    908                      / TALER_MERCHANT_UNIT_FRAC_BASE;
    909 
    910     value -= borrow;
    911     frac += borrow * (int64_t) TALER_MERCHANT_UNIT_FRAC_BASE;
    912   }
    913   else if (frac >= TALER_MERCHANT_UNIT_FRAC_BASE)
    914   {
    915     int64_t carry = frac / TALER_MERCHANT_UNIT_FRAC_BASE;
    916 
    917     value += carry;
    918     frac -= carry * (int64_t) TALER_MERCHANT_UNIT_FRAC_BASE;
    919   }
    920 
    921   if (value < 0)
    922   {
    923     GNUNET_break (0);
    924     value = 0;
    925     frac = 0;
    926   }
    927 
    928   *available_value = (uint64_t) value;
    929   *available_frac = (uint32_t) frac;
    930 }
    931 
    932 
    933 /**
    934  * Execute the database transaction to setup the order.
    935  *
    936  * @param[in,out] oc order context
    937  * @return transaction status, #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if @a uuids were insufficient to reserve required inventory
    938  */
    939 static enum GNUNET_DB_QueryStatus
    940 execute_transaction (struct OrderContext *oc)
    941 {
    942   enum GNUNET_DB_QueryStatus qs;
    943   struct GNUNET_TIME_Timestamp timestamp;
    944   uint64_t order_serial;
    945 
    946   if (GNUNET_OK !=
    947       TALER_MERCHANTDB_start (TMH_db,
    948                               "insert_order"))
    949   {
    950     GNUNET_break (0);
    951     return GNUNET_DB_STATUS_HARD_ERROR;
    952   }
    953 
    954   /* Test if we already have an order with this id */
    955   {
    956     json_t *contract_terms;
    957     struct TALER_MerchantPostDataHashP orig_post;
    958 
    959     qs = TALER_MERCHANTDB_get_order (TMH_db,
    960                                      oc->hc->instance->settings.id,
    961                                      oc->parse_order.order->order_id,
    962                                      &oc->execute_order.token,
    963                                      &orig_post,
    964                                      &contract_terms);
    965     /* If yes, check for idempotency */
    966     if (0 > qs)
    967     {
    968       GNUNET_break (0);
    969       TALER_MERCHANTDB_rollback (TMH_db);
    970       return qs;
    971     }
    972     if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    973     {
    974       TALER_MERCHANTDB_rollback (TMH_db);
    975       json_decref (contract_terms);
    976       /* Comparing the contract terms is sufficient because all the other
    977          params get added to it at some point. */
    978       if (0 == GNUNET_memcmp (&orig_post,
    979                               &oc->parse_request.h_post_data))
    980       {
    981         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    982                     "Order creation idempotent\n");
    983         oc->execute_order.idempotent = true;
    984         return qs;
    985       }
    986       GNUNET_break_op (0);
    987       oc->execute_order.conflict = true;
    988       return qs;
    989     }
    990   }
    991 
    992   /* Setup order */
    993   qs = TALER_MERCHANTDB_insert_order (TMH_db,
    994                                       oc->hc->instance->settings.id,
    995                                       oc->parse_order.order->order_id,
    996                                       oc->parse_request.session_id,
    997                                       &oc->parse_request.h_post_data,
    998                                       oc->parse_order.order->pay_deadline,
    999                                       &oc->parse_request.claim_token,
   1000                                       oc->serialize_order.contract, /* called 'contract terms' at database. */
   1001                                       oc->parse_request.pos_key,
   1002                                       oc->parse_request.pos_algorithm,
   1003                                       /* the parser only accepts a challenge
   1004                                          together with these algorithms */
   1005                                       ( (TALER_MCA_ECDSA_CHALLENGE
   1006                                          == oc->parse_request.pos_algorithm) ||
   1007                                         (TALER_MCA_EDDSA_CHALLENGE
   1008                                          == oc->parse_request.pos_algorithm) )
   1009                                       ? &oc->parse_request.pos_challenge
   1010                                       : NULL);
   1011   if (qs <= 0)
   1012   {
   1013     /* qs == 0: probably instance does not exist (anymore) */
   1014     TALER_MERCHANTDB_rollback (TMH_db);
   1015     return qs;
   1016   }
   1017   /* Migrate locks from UUIDs to new order: first release old locks */
   1018   for (unsigned int i = 0; i<oc->parse_request.uuids_length; i++)
   1019   {
   1020     qs = TALER_MERCHANTDB_delete_inventory_lock (TMH_db,
   1021                                                  &oc->parse_request.uuids[i]);
   1022     if (qs < 0)
   1023     {
   1024       TALER_MERCHANTDB_rollback (TMH_db);
   1025       return qs;
   1026     }
   1027     /* qs == 0 is OK here, that just means we did not HAVE any lock under this
   1028        UUID */
   1029   }
   1030   /* Migrate locks from UUIDs to new order: acquire new locks
   1031      (note: this can basically ONLY fail on serializability OR
   1032      because the UUID locks were insufficient for the desired
   1033      quantities). */
   1034   for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   1035   {
   1036     qs = TALER_MERCHANTDB_insert_order_lock (
   1037       TMH_db,
   1038       oc->hc->instance->settings.id,
   1039       oc->parse_order.order->order_id,
   1040       oc->parse_request.inventory_products[i].product_id,
   1041       oc->parse_request.inventory_products[i].quantity,
   1042       oc->parse_request.inventory_products[i].quantity_frac);
   1043     if (qs < 0)
   1044     {
   1045       TALER_MERCHANTDB_rollback (TMH_db);
   1046       return qs;
   1047     }
   1048     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1049     {
   1050       /* qs == 0: lock acquisition failed due to insufficient stocks */
   1051       TALER_MERCHANTDB_rollback (TMH_db);
   1052       oc->execute_order.out_of_stock_index = i; /* indicate which product is causing the issue */
   1053       return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
   1054     }
   1055   }
   1056   oc->execute_order.out_of_stock_index = UINT_MAX;
   1057 
   1058   /* Get the order serial and timestamp for the order we just created to
   1059      update long-poll clients. */
   1060   qs = TALER_MERCHANTDB_get_order_summary (
   1061     TMH_db,
   1062     oc->hc->instance->settings.id,
   1063     oc->parse_order.order->order_id,
   1064     &timestamp,
   1065     &order_serial);
   1066   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
   1067   {
   1068     TALER_MERCHANTDB_rollback (TMH_db);
   1069     return qs;
   1070   }
   1071 
   1072   {
   1073     json_t *jhook;
   1074 
   1075     jhook = GNUNET_JSON_PACK (
   1076       GNUNET_JSON_pack_string ("order_id",
   1077                                oc->parse_order.order->order_id),
   1078       GNUNET_JSON_pack_object_incref ("contract",
   1079                                       oc->serialize_order.contract),
   1080       GNUNET_JSON_pack_string ("instance_id",
   1081                                oc->hc->instance->settings.id)
   1082       );
   1083     GNUNET_assert (NULL != jhook);
   1084     qs = TMH_trigger_webhook (oc->hc->instance->settings.id,
   1085                               "order_created",
   1086                               jhook);
   1087     json_decref (jhook);
   1088     if (0 > qs)
   1089     {
   1090       TALER_MERCHANTDB_rollback (TMH_db);
   1091       if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
   1092         return qs;
   1093       GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
   1094       reply_with_error (oc,
   1095                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1096                         TALER_EC_GENERIC_DB_STORE_FAILED,
   1097                         "failed to trigger webhooks");
   1098       return qs;
   1099     }
   1100   }
   1101 
   1102   TMH_notify_order_change (oc->hc->instance,
   1103                            TMH_OSF_NONE,
   1104                            timestamp,
   1105                            order_serial);
   1106   /* finally, commit transaction (note: if it fails, we ALSO re-acquire
   1107      the UUID locks, which is exactly what we want) */
   1108   qs = TALER_MERCHANTDB_commit (TMH_db);
   1109   if (0 > qs)
   1110     return qs;
   1111   return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;   /* 1 == success! */
   1112 }
   1113 
   1114 
   1115 /**
   1116  * The request was successful, generate the #MHD_HTTP_OK response.
   1117  *
   1118  * @param[in,out] oc context to update
   1119  * @param claim_token claim token to use, NULL if none
   1120  */
   1121 static void
   1122 yield_success_response (struct OrderContext *oc,
   1123                         const struct TALER_ClaimTokenP *claim_token)
   1124 {
   1125   enum MHD_Result ret;
   1126 
   1127   ret = TALER_MHD_REPLY_JSON_PACK (
   1128     oc->connection,
   1129     MHD_HTTP_OK,
   1130     GNUNET_JSON_pack_string ("order_id",
   1131                              oc->parse_order.order->order_id),
   1132     GNUNET_JSON_pack_timestamp ("pay_deadline",
   1133                                 oc->parse_order.order->pay_deadline),
   1134     GNUNET_JSON_pack_allow_null (
   1135       GNUNET_JSON_pack_data_auto (
   1136         "token",
   1137         claim_token)));
   1138   finalize_order (oc,
   1139                   ret);
   1140 }
   1141 
   1142 
   1143 /**
   1144  * Transform an order into a proposal and store it in the
   1145  * database. Write the resulting proposal or an error message
   1146  * of a MHD connection.
   1147  *
   1148  * @param[in,out] oc order context
   1149  */
   1150 static void
   1151 phase_execute_order (struct OrderContext *oc)
   1152 {
   1153   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   1154     &oc->hc->instance->settings;
   1155   enum GNUNET_DB_QueryStatus qs;
   1156 
   1157   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1158               "Executing database transaction to create order '%s' for instance '%s'\n",
   1159               oc->parse_order.order->order_id,
   1160               settings->id);
   1161   for (unsigned int i = 0; i<MAX_RETRIES; i++)
   1162   {
   1163     TALER_MERCHANTDB_preflight (TMH_db);
   1164     qs = execute_transaction (oc);
   1165     if (GNUNET_DB_STATUS_SOFT_ERROR != qs)
   1166       break;
   1167   }
   1168   if (0 >= qs)
   1169   {
   1170     /* Special report if retries insufficient */
   1171     if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
   1172     {
   1173       GNUNET_break (0);
   1174       reply_with_error (oc,
   1175                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1176                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1177                         NULL);
   1178       return;
   1179     }
   1180     if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1181     {
   1182       /* should be: contract (!) with same order ID
   1183          already exists */
   1184       reply_with_error (
   1185         oc,
   1186         MHD_HTTP_CONFLICT,
   1187         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS,
   1188         oc->parse_order.order->order_id);
   1189       return;
   1190     }
   1191     /* Other hard transaction error (disk full, etc.) */
   1192     GNUNET_break (0);
   1193     reply_with_error (
   1194       oc,
   1195       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1196       TALER_EC_GENERIC_DB_COMMIT_FAILED,
   1197       NULL);
   1198     return;
   1199   }
   1200 
   1201   /* DB transaction succeeded, check for idempotent */
   1202   if (oc->execute_order.idempotent)
   1203   {
   1204     yield_success_response (oc,
   1205                             GNUNET_is_zero (&oc->execute_order.token)
   1206                             ? NULL
   1207                             : &oc->execute_order.token);
   1208     return;
   1209   }
   1210   if (oc->execute_order.conflict)
   1211   {
   1212     reply_with_error (
   1213       oc,
   1214       MHD_HTTP_CONFLICT,
   1215       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_ALREADY_EXISTS,
   1216       oc->parse_order.order->order_id);
   1217     return;
   1218   }
   1219 
   1220   /* DB transaction succeeded, check for out-of-stock */
   1221   if (oc->execute_order.out_of_stock_index < UINT_MAX)
   1222   {
   1223     /* We had a product that has insufficient quantities,
   1224        generate the details for the response. */
   1225     struct TALER_MERCHANTDB_ProductDetails pd;
   1226     enum MHD_Result ret;
   1227     const struct InventoryProduct *ip;
   1228     size_t num_categories = 0;
   1229     uint64_t *categories = NULL;
   1230     uint64_t available_quantity;
   1231     uint32_t available_quantity_frac;
   1232     char requested_quantity_buf[64];
   1233     char available_quantity_buf[64];
   1234 
   1235     ip = &oc->parse_request.inventory_products[
   1236       oc->execute_order.out_of_stock_index];
   1237     memset (&pd,
   1238             0,
   1239             sizeof (pd));
   1240     qs = TALER_MERCHANTDB_get_product (
   1241       TMH_db,
   1242       oc->hc->instance->settings.id,
   1243       ip->product_id,
   1244       &pd,
   1245       &num_categories,
   1246       &categories);
   1247     switch (qs)
   1248     {
   1249     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1250       GNUNET_free (categories);
   1251       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1252                   "Order creation failed: product out of stock\n");
   1253 
   1254       compute_available_quantity (&pd,
   1255                                   &available_quantity,
   1256                                   &available_quantity_frac);
   1257       TALER_MERCHANT_vk_format_fractional_string (
   1258         TALER_MERCHANT_VK_QUANTITY,
   1259         ip->quantity,
   1260         ip->quantity_frac,
   1261         sizeof (requested_quantity_buf),
   1262         requested_quantity_buf);
   1263       TALER_MERCHANT_vk_format_fractional_string (
   1264         TALER_MERCHANT_VK_QUANTITY,
   1265         available_quantity,
   1266         available_quantity_frac,
   1267         sizeof (available_quantity_buf),
   1268         available_quantity_buf);
   1269       ret = TALER_MHD_REPLY_JSON_PACK (
   1270         oc->connection,
   1271         MHD_HTTP_GONE,
   1272         GNUNET_JSON_pack_string (
   1273           "product_id",
   1274           ip->product_id),
   1275         GNUNET_JSON_pack_uint64 (
   1276           "requested_quantity",
   1277           ip->quantity),
   1278         GNUNET_JSON_pack_string (
   1279           "unit_requested_quantity",
   1280           requested_quantity_buf),
   1281         GNUNET_JSON_pack_uint64 (
   1282           "available_quantity",
   1283           available_quantity),
   1284         GNUNET_JSON_pack_string (
   1285           "unit_available_quantity",
   1286           available_quantity_buf),
   1287         GNUNET_JSON_pack_allow_null (
   1288           GNUNET_JSON_pack_timestamp (
   1289             "restock_expected",
   1290             pd.next_restock)));
   1291       TALER_MERCHANTDB_product_details_free (&pd);
   1292       finalize_order (oc,
   1293                       ret);
   1294       return;
   1295     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1296       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1297                   "Order creation failed: unknown product out of stock\n");
   1298       finalize_order (oc,
   1299                       TALER_MHD_REPLY_JSON_PACK (
   1300                         oc->connection,
   1301                         MHD_HTTP_GONE,
   1302                         GNUNET_JSON_pack_string (
   1303                           "product_id",
   1304                           ip->product_id),
   1305                         GNUNET_JSON_pack_uint64 (
   1306                           "requested_quantity",
   1307                           ip->quantity),
   1308                         GNUNET_JSON_pack_uint64 (
   1309                           "available_quantity",
   1310                           0)));
   1311       return;
   1312     case GNUNET_DB_STATUS_SOFT_ERROR:
   1313       GNUNET_break (0);
   1314       reply_with_error (
   1315         oc,
   1316         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1317         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   1318         NULL);
   1319       return;
   1320     case GNUNET_DB_STATUS_HARD_ERROR:
   1321       GNUNET_break (0);
   1322       reply_with_error (
   1323         oc,
   1324         MHD_HTTP_INTERNAL_SERVER_ERROR,
   1325         TALER_EC_GENERIC_DB_FETCH_FAILED,
   1326         NULL);
   1327       return;
   1328     }
   1329     GNUNET_break (0);
   1330     oc->phase = ORDER_PHASE_FINISHED_MHD_NO;
   1331     return;
   1332   } /* end 'out of stock' case */
   1333 
   1334   /* Everything in-stock, generate positive response */
   1335   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1336               "Order creation succeeded\n");
   1337   yield_success_response (oc,
   1338                           GNUNET_is_zero (&oc->parse_request.claim_token)
   1339                           ? NULL
   1340                           : &oc->parse_request.claim_token);
   1341 }
   1342 
   1343 
   1344 /* ***************** ORDER_PHASE_CHECK_CONTRACT **************** */
   1345 
   1346 
   1347 /**
   1348  * Check that the contract is now well-formed. Upon success, continue
   1349  * processing with execute_order().
   1350  *
   1351  * @param[in,out] oc order context
   1352  */
   1353 static void
   1354 phase_check_contract (struct OrderContext *oc)
   1355 {
   1356   struct TALER_PrivateContractHashP h_control;
   1357 
   1358   switch (TALER_JSON_contract_hash (oc->serialize_order.contract,
   1359                                     &h_control))
   1360   {
   1361   case GNUNET_SYSERR:
   1362     GNUNET_break (0);
   1363     reply_with_error (
   1364       oc,
   1365       MHD_HTTP_INTERNAL_SERVER_ERROR,
   1366       TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
   1367       "could not compute hash of serialized order");
   1368     return;
   1369   case GNUNET_NO:
   1370     GNUNET_break_op (0);
   1371     reply_with_error (
   1372       oc,
   1373       MHD_HTTP_BAD_REQUEST,
   1374       TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
   1375       "order contained unallowed values");
   1376     return;
   1377   case GNUNET_OK:
   1378     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1379                 "Contract hash is %s\n",
   1380                 GNUNET_h2s (&h_control.hash));
   1381     oc->phase++;
   1382     return;
   1383   }
   1384   GNUNET_assert (0);
   1385 }
   1386 
   1387 
   1388 /* ***************** ORDER_PHASE_SALT_FORGETTABLE **************** */
   1389 
   1390 
   1391 /**
   1392  * Modify the final contract terms adding salts for
   1393  * items that are forgettable.
   1394  *
   1395  * @param[in,out] oc order context
   1396  */
   1397 static void
   1398 phase_salt_forgettable (struct OrderContext *oc)
   1399 {
   1400   if (GNUNET_OK !=
   1401       TALER_JSON_contract_seed_forgettable (oc->parse_request.order,
   1402                                             oc->serialize_order.contract))
   1403   {
   1404     GNUNET_break_op (0);
   1405     reply_with_error (
   1406       oc,
   1407       MHD_HTTP_BAD_REQUEST,
   1408       TALER_EC_GENERIC_JSON_INVALID,
   1409       "could not compute hash of order due to bogus forgettable fields");
   1410     return;
   1411   }
   1412   oc->phase++;
   1413 }
   1414 
   1415 
   1416 /* ***************** ORDER_PHASE_SERIALIZE_ORDER **************** */
   1417 
   1418 /**
   1419  * Find the family entry for the family of the given @a slug
   1420  * in @a oc.
   1421  *
   1422  * @param[in] oc order context to search
   1423  * @param slug slug to search for
   1424  * @return NULL if @a slug was not found
   1425  */
   1426 static struct TALER_MERCHANT_ContractTokenFamily *
   1427 find_family (const struct OrderContext *oc,
   1428              const char *slug)
   1429 {
   1430   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
   1431   {
   1432     if (0 == strcmp (oc->parse_choices.token_families[i].slug,
   1433                      slug))
   1434     {
   1435       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1436                   "Token family %s already in order\n",
   1437                   slug);
   1438       return &oc->parse_choices.token_families[i];
   1439     }
   1440   }
   1441   return NULL;
   1442 }
   1443 
   1444 
   1445 /**
   1446  * Function called with each applicable family key that should
   1447  * be added to the respective token family of the order.
   1448  *
   1449  * @param cls a `struct OrderContext *` to expand
   1450  * @param tfkd token family key details to add to the contract
   1451  */
   1452 static void
   1453 add_family_key (void *cls,
   1454                 const struct TALER_MERCHANTDB_TokenFamilyKeyDetails *tfkd)
   1455 {
   1456   struct OrderContext *oc = cls;
   1457   const struct TALER_MERCHANTDB_TokenFamilyDetails *tf = &tfkd->token_family;
   1458   struct TALER_MERCHANT_ContractTokenFamily *family;
   1459 
   1460   family = find_family (oc,
   1461                         tf->slug);
   1462   if (NULL == family)
   1463   {
   1464     /* Family not yet in our contract terms, create new entry */
   1465     struct TALER_MERCHANT_ContractTokenFamily new_family;
   1466 
   1467     TMH_token_family_to_contract (tf,
   1468                                   &new_family);
   1469     GNUNET_array_append (oc->parse_choices.token_families,
   1470                          oc->parse_choices.token_families_len,
   1471                          new_family);
   1472     family = &oc->parse_choices.token_families[
   1473       oc->parse_choices.token_families_len - 1];
   1474   }
   1475   if (NULL == tfkd->pub.public_key)
   1476     return;
   1477   for (unsigned int i = 0; i<family->keys_len; i++)
   1478   {
   1479     /* Note: cmp() returns 0 when the keys are EQUAL (memcmp-style). */
   1480     if (0 == TALER_token_issue_pub_cmp (&family->keys[i].pub,
   1481                                         &tfkd->pub))
   1482     {
   1483       /* A matching key is already in the list. */
   1484       return;
   1485     }
   1486   }
   1487 
   1488   {
   1489     struct TALER_MERCHANT_ContractTokenFamilyKey key;
   1490 
   1491     TALER_token_issue_pub_copy (&key.pub,
   1492                                 &tfkd->pub);
   1493     key.valid_after = tfkd->signature_validity_start;
   1494     key.valid_before = tfkd->signature_validity_end;
   1495     GNUNET_array_append (family->keys,
   1496                          family->keys_len,
   1497                          key);
   1498   }
   1499 }
   1500 
   1501 
   1502 /**
   1503  * Check if the token family with the given @a slug is already present in the
   1504  * list of token families for this order. If not, fetch its details and add it
   1505  * to the list.
   1506  *
   1507  * @param[in,out] oc order context
   1508  * @param slug slug of the token family
   1509  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1510  */
   1511 static enum GNUNET_GenericReturnValue
   1512 add_input_token_family (struct OrderContext *oc,
   1513                         const char *slug)
   1514 {
   1515   struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   1516   struct GNUNET_TIME_Timestamp end = oc->parse_order.order->pay_deadline;
   1517   enum GNUNET_DB_QueryStatus qs;
   1518   enum TALER_ErrorCode ec = TALER_EC_INVALID; /* make compiler happy */
   1519   unsigned int http_status = 0; /* make compiler happy */
   1520 
   1521   qs = TALER_MERCHANTDB_iterate_token_family_keys (
   1522     TMH_db,
   1523     oc->hc->instance->settings.id,
   1524     slug,
   1525     now,
   1526     end,
   1527     &add_family_key,
   1528     oc);
   1529   switch (qs)
   1530   {
   1531   case GNUNET_DB_STATUS_HARD_ERROR:
   1532     GNUNET_break (0);
   1533     http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   1534     ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
   1535     break;
   1536   case GNUNET_DB_STATUS_SOFT_ERROR:
   1537     GNUNET_break (0);
   1538     http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   1539     ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
   1540     break;
   1541   case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1542     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1543                 "Input token family slug %s unknown\n",
   1544                 slug);
   1545     http_status = MHD_HTTP_NOT_FOUND;
   1546     ec = TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_TOKEN_FAMILY_SLUG_UNKNOWN;
   1547     break;
   1548   default: /* one or more results are all OK */
   1549     return GNUNET_OK;
   1550   }
   1551   reply_with_error (oc,
   1552                     http_status,
   1553                     ec,
   1554                     slug);
   1555   return GNUNET_SYSERR;
   1556 }
   1557 
   1558 
   1559 /**
   1560  * Find the index of a key in the @a family that is valid at
   1561  * the time @a valid_at.
   1562  *
   1563  * @param family to search
   1564  * @param valid_at time when the key must be valid
   1565  * @param[out] key_index index to initialize
   1566  * @return #GNUNET_OK if a matching key was found
   1567  */
   1568 static enum GNUNET_GenericReturnValue
   1569 find_key_index (struct TALER_MERCHANT_ContractTokenFamily *family,
   1570                 struct GNUNET_TIME_Timestamp valid_at,
   1571                 unsigned int *key_index)
   1572 {
   1573   for (unsigned int i = 0; i<family->keys_len; i++)
   1574   {
   1575     if ( (GNUNET_TIME_timestamp_cmp (family->keys[i].valid_after,
   1576                                      <=,
   1577                                      valid_at)) &&
   1578          (GNUNET_TIME_timestamp_cmp (family->keys[i].valid_before,
   1579                                      >=,
   1580                                      valid_at)) )
   1581     {
   1582       /* The token family and a matching key already exist. */
   1583       *key_index = i;
   1584       return GNUNET_OK;
   1585     }
   1586   }
   1587   return GNUNET_NO;
   1588 }
   1589 
   1590 
   1591 /**
   1592  * Check if the token family with the given @a slug is already present in the
   1593  * list of token families for this order. If not, fetch its details and add it
   1594  * to the list. Also checks if there is a public key with that expires after
   1595  * the payment deadline.  If a key covering @a valid_at exists but its private
   1596  * key would be deleted before the payment deadline, the lifetime of that
   1597  * private key is extended; only if no key covers @a valid_at at all do we
   1598  * generate a new key pair and store it in the database.
   1599  *
   1600  * @param[in,out] oc order context
   1601  * @param slug slug of the token family
   1602  * @param valid_at time when the token returned must be valid
   1603  * @param[out] key_index set to the index of the respective public
   1604  *    key in the @a slug's token family keys array.
   1605  * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
   1606  */
   1607 static enum GNUNET_GenericReturnValue
   1608 add_output_token_family (struct OrderContext *oc,
   1609                          const char *slug,
   1610                          struct GNUNET_TIME_Timestamp valid_at,
   1611                          unsigned int *key_index)
   1612 {
   1613   struct TALER_MERCHANTDB_TokenFamilyKeyDetails key_details;
   1614   struct TALER_MERCHANT_ContractTokenFamily *family;
   1615   enum GNUNET_GenericReturnValue res;
   1616   bool minted;
   1617 
   1618   family = find_family (oc,
   1619                         slug);
   1620   if ( (NULL != family) &&
   1621        (GNUNET_OK ==
   1622         find_key_index (family,
   1623                         valid_at,
   1624                         key_index)) )
   1625   {
   1626     /* Even a key already in the contract must remain usable until
   1627        this order's payment deadline. */
   1628     res = TMH_token_key_extend (oc->connection,
   1629                                 oc->hc->instance->settings.id,
   1630                                 slug,
   1631                                 valid_at,
   1632                                 oc->parse_order.order->pay_deadline);
   1633     if (GNUNET_OK != res)
   1634     {
   1635       finalize_order2 (oc,
   1636                        res);
   1637       return GNUNET_SYSERR;
   1638     }
   1639     return GNUNET_OK;
   1640   }
   1641   res = TMH_token_key_ensure (oc->connection,
   1642                               oc->hc->instance->settings.id,
   1643                               slug,
   1644                               valid_at,
   1645                               oc->parse_order.order->pay_deadline,
   1646                               &key_details,
   1647                               &minted);
   1648   if (GNUNET_OK != res)
   1649   {
   1650     finalize_order2 (oc,
   1651                      res);
   1652     return GNUNET_SYSERR;
   1653   }
   1654   /* Add the result even if the family is already in the contract:
   1655      the database may have returned a key not yet listed there. */
   1656   add_family_key (oc,
   1657                   &key_details);
   1658   TMH_token_key_details_free (&key_details);
   1659   family = find_family (oc,
   1660                         slug);
   1661   GNUNET_assert (NULL != family);
   1662   if (minted)
   1663   {
   1664     /* Preserve the order path's choice of the newly appended key,
   1665        even if an older key covers an overlapping validity period. */
   1666     *key_index = family->keys_len - 1;
   1667   }
   1668   else
   1669   {
   1670     GNUNET_assert (GNUNET_OK ==
   1671                    find_key_index (family,
   1672                                    valid_at,
   1673                                    key_index));
   1674   }
   1675   return GNUNET_OK;
   1676 }
   1677 
   1678 
   1679 /**
   1680  * Build JSON array that represents all of the token families
   1681  * in the contract.
   1682  *
   1683  * @param[in] oc v1-style order context
   1684  * @return JSON array with token families for the contract
   1685  */
   1686 static json_t *
   1687 output_token_families (struct OrderContext *oc)
   1688 {
   1689   json_t *token_families = json_object ();
   1690 
   1691   GNUNET_assert (NULL != token_families);
   1692   for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++)
   1693   {
   1694     const struct TALER_MERCHANT_ContractTokenFamily *family
   1695       = &oc->parse_choices.token_families[i];
   1696     json_t *jfamily;
   1697 
   1698     jfamily = TALER_MERCHANT_json_from_token_family (family);
   1699 
   1700     GNUNET_assert (jfamily != NULL);
   1701 
   1702     GNUNET_assert (0 ==
   1703                    json_object_set_new (token_families,
   1704                                         family->slug,
   1705                                         jfamily));
   1706   }
   1707   return token_families;
   1708 }
   1709 
   1710 
   1711 /**
   1712  * Build JSON array that represents all of the contract choices
   1713  * in the contract.
   1714  *
   1715  * @param[in] oc v1-style order context
   1716  * @return JSON array with token families for the contract
   1717  */
   1718 static json_t *
   1719 output_contract_choices (struct OrderContext *oc)
   1720 {
   1721   json_t *choices = json_array ();
   1722 
   1723   GNUNET_assert (NULL != choices);
   1724   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   1725   {
   1726     oc->parse_choices.choices[i].max_fee =
   1727       oc->set_max_fee.details.v1.max_fees[i];
   1728     GNUNET_assert (0 == json_array_append_new (
   1729                      choices,
   1730                      TALER_MERCHANT_json_from_contract_choice (
   1731                        &oc->parse_choices.choices[i])));
   1732   }
   1733   return choices;
   1734 }
   1735 
   1736 
   1737 /**
   1738  * Serialize order into @a oc->serialize_order.contract,
   1739  * ready to be stored in the database. Upon success, continue
   1740  * processing with check_contract().
   1741  *
   1742  * @param[in,out] oc order context
   1743  */
   1744 static void
   1745 phase_serialize_order (struct OrderContext *oc)
   1746 {
   1747   json_t *merchant;
   1748 
   1749   merchant = TMH_instance_metadata_to_json (oc->hc->instance);
   1750   GNUNET_assert (NULL != merchant);
   1751 
   1752   oc->serialize_order.contract = GNUNET_JSON_PACK (
   1753     GNUNET_JSON_pack_string (
   1754       "order_id",
   1755       oc->parse_order.order->order_id),
   1756     GNUNET_JSON_pack_object_steal (
   1757       NULL,
   1758       TALER_MERCHANT_base_terms_serialize (oc->parse_order.order->base)),
   1759     GNUNET_JSON_pack_array_incref (
   1760       "products",
   1761       oc->merge_inventory.products),
   1762     GNUNET_JSON_pack_data_auto (
   1763       "h_wire",
   1764       &oc->select_wire_method.wm->h_wire),
   1765     GNUNET_JSON_pack_string (
   1766       "wire_method",
   1767       oc->select_wire_method.wm->wire_method),
   1768     GNUNET_JSON_pack_timestamp (
   1769       "timestamp",
   1770       oc->parse_order.order->timestamp),
   1771     GNUNET_JSON_pack_timestamp (
   1772       "pay_deadline",
   1773       oc->parse_order.order->pay_deadline),
   1774     GNUNET_JSON_pack_timestamp (
   1775       "wire_transfer_deadline",
   1776       oc->parse_order.order->wire_transfer_deadline),
   1777     GNUNET_JSON_pack_string (
   1778       "merchant_base_url",
   1779       oc->parse_order.merchant_base_url),
   1780     GNUNET_JSON_pack_object_steal (
   1781       "merchant",
   1782       merchant),
   1783     GNUNET_JSON_pack_data_auto (
   1784       "merchant_pub",
   1785       &oc->hc->instance->merchant_pub),
   1786     GNUNET_JSON_pack_array_incref (
   1787       "exchanges",
   1788       oc->select_wire_method.exchanges));
   1789 
   1790   {
   1791     json_t *xtra;
   1792 
   1793     switch (oc->parse_order.order->base->version)
   1794     {
   1795     case TALER_MERCHANT_CONTRACT_VERSION_0:
   1796       xtra = GNUNET_JSON_PACK (
   1797         TALER_JSON_pack_amount ("max_fee",
   1798                                 &oc->set_max_fee.details.v0.max_fee),
   1799         GNUNET_JSON_pack_allow_null (
   1800           TALER_JSON_pack_amount (
   1801             "tip",
   1802             oc->parse_order.order->details.v0.no_tip
   1803                                   ? NULL
   1804                                   : &oc->parse_order.order->details.v0.tip)),
   1805         TALER_JSON_pack_amount (
   1806           "amount",
   1807           &oc->parse_order.order->details.v0.brutto));
   1808       break;
   1809     case TALER_MERCHANT_CONTRACT_VERSION_1:
   1810       {
   1811         json_t *token_families = output_token_families (oc);
   1812         json_t *choices = output_contract_choices (oc);
   1813 
   1814         if ( (NULL == token_families) ||
   1815              (NULL == choices) )
   1816         {
   1817           GNUNET_break (0);
   1818           return;
   1819         }
   1820         xtra = GNUNET_JSON_PACK (
   1821           GNUNET_JSON_pack_array_steal ("choices",
   1822                                         choices),
   1823           GNUNET_JSON_pack_object_steal ("token_families",
   1824                                          token_families));
   1825         break;
   1826       }
   1827     default:
   1828       GNUNET_assert (0);
   1829     }
   1830     GNUNET_assert (0 ==
   1831                    json_object_update (oc->serialize_order.contract,
   1832                                        xtra));
   1833     json_decref (xtra);
   1834   }
   1835 
   1836 
   1837   /* Pack does not work here, because it doesn't set zero-values for timestamps */
   1838   GNUNET_assert (0 ==
   1839                  json_object_set_new (
   1840                    oc->serialize_order.contract,
   1841                    "refund_deadline",
   1842                    GNUNET_JSON_from_timestamp (
   1843                      oc->parse_order.order->refund_deadline)));
   1844   /* auto_refund should only be set if it is not 0 */
   1845   if (! GNUNET_TIME_relative_is_zero (
   1846         oc->parse_order.order->base->auto_refund))
   1847   {
   1848     /* Pack does not work here, because it sets zero-values for relative times */
   1849     GNUNET_assert (0 ==
   1850                    json_object_set_new (
   1851                      oc->serialize_order.contract,
   1852                      "auto_refund",
   1853                      GNUNET_JSON_from_time_rel (
   1854                        oc->parse_order.order->base->auto_refund)));
   1855   }
   1856 
   1857   oc->phase++;
   1858 }
   1859 
   1860 
   1861 /* ***************** ORDER_PHASE_SET_MAX_FEE **************** */
   1862 
   1863 
   1864 /**
   1865  * Set @a max_fee in @a oc based on @a max_stefan_fee value if not overridden
   1866  * by @a client_fee.  If neither is set, set the fee to zero using currency
   1867  * from @a brutto.
   1868  *
   1869  * @param[in,out] oc order context
   1870  * @param brutto brutto amount to compute fee for
   1871  * @param client_fee client-given fee override (or invalid)
   1872  * @param max_stefan_fee maximum STEFAN fee of any exchange
   1873  * @param max_fee set to the maximum stefan fee
   1874  */
   1875 static void
   1876 compute_fee (struct OrderContext *oc,
   1877              const struct TALER_Amount *brutto,
   1878              const struct TALER_Amount *client_fee,
   1879              const struct TALER_Amount *max_stefan_fee,
   1880              struct TALER_Amount *max_fee)
   1881 {
   1882   const struct TALER_MERCHANTDB_InstanceSettings *settings
   1883     = &oc->hc->instance->settings;
   1884 
   1885   if (GNUNET_OK ==
   1886       TALER_amount_is_valid (client_fee))
   1887   {
   1888     *max_fee = *client_fee;
   1889     return;
   1890   }
   1891   if ( (settings->use_stefan) &&
   1892        (NULL != max_stefan_fee) &&
   1893        (GNUNET_OK ==
   1894         TALER_amount_is_valid (max_stefan_fee)) )
   1895   {
   1896     *max_fee = *max_stefan_fee;
   1897     return;
   1898   }
   1899   GNUNET_assert (
   1900     GNUNET_OK ==
   1901     TALER_amount_set_zero (brutto->currency,
   1902                            max_fee));
   1903 }
   1904 
   1905 
   1906 /**
   1907  * Initialize "set_max_fee" in @a oc based on STEFAN value or client
   1908  * preference. Upon success, continue processing in next phase.
   1909  *
   1910  * @param[in,out] oc order context
   1911  */
   1912 static void
   1913 phase_set_max_fee (struct OrderContext *oc)
   1914 {
   1915   switch (oc->parse_order.order->base->version)
   1916   {
   1917   case TALER_MERCHANT_CONTRACT_VERSION_0:
   1918     compute_fee (oc,
   1919                  &oc->parse_order.order->details.v0.brutto,
   1920                  &oc->parse_order.order->details.v0.max_fee,
   1921                  &oc->set_exchanges.details.v0.max_stefan_fee,
   1922                  &oc->set_max_fee.details.v0.max_fee);
   1923     break;
   1924   case TALER_MERCHANT_CONTRACT_VERSION_1:
   1925     oc->set_max_fee.details.v1.max_fees
   1926       = GNUNET_new_array (oc->parse_choices.choices_len,
   1927                           struct TALER_Amount);
   1928     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   1929       compute_fee (oc,
   1930                    &oc->parse_choices.choices[i].amount,
   1931                    &oc->parse_choices.choices[i].max_fee,
   1932                    NULL != oc->set_exchanges.details.v1.max_stefan_fees
   1933                    ? &oc->set_exchanges.details.v1.max_stefan_fees[i]
   1934                    : NULL,
   1935                    &oc->set_max_fee.details.v1.max_fees[i]);
   1936     break;
   1937   default:
   1938     GNUNET_break (0);
   1939     break;
   1940   }
   1941   oc->phase++;
   1942 }
   1943 
   1944 
   1945 /* ***************** ORDER_PHASE_SELECT_WIRE_METHOD **************** */
   1946 
   1947 /**
   1948  * Phase to select a wire method that will be acceptable for the order.
   1949  * If none is "perfect" (allows all choices), might jump back to the
   1950  * previous phase to force "/keys" downloads to see if that helps.
   1951  *
   1952  * @param[in,out] oc order context
   1953  */
   1954 static void
   1955 phase_select_wire_method (struct OrderContext *oc)
   1956 {
   1957   const struct TALER_Amount *ea;
   1958   struct WireMethodCandidate *best = NULL;
   1959   unsigned int max_choices = 0;
   1960   unsigned int want_choices = 0;
   1961   bool zero_amount = false;
   1962 
   1963   switch (oc->parse_order.order->base->version)
   1964   {
   1965   case TALER_MERCHANT_CONTRACT_VERSION_0:
   1966     ea = &oc->parse_order.order->details.v0.brutto;
   1967     if (TALER_amount_is_zero (ea))
   1968       zero_amount = true;
   1969     break;
   1970   case TALER_MERCHANT_CONTRACT_VERSION_1:
   1971     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   1972     {
   1973       ea = &oc->parse_choices.choices[i].amount;
   1974       if (TALER_amount_is_zero (ea))
   1975         zero_amount = true;
   1976     }
   1977     break;
   1978   default:
   1979     GNUNET_assert (0);
   1980   }
   1981 
   1982   for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   1983        NULL != wmc;
   1984        wmc = wmc->next)
   1985   {
   1986     unsigned int num_choices = 0;
   1987 
   1988     switch (oc->parse_order.order->base->version)
   1989     {
   1990     case TALER_MERCHANT_CONTRACT_VERSION_0:
   1991       want_choices = 1;
   1992       ea = &oc->parse_order.order->details.v0.brutto;
   1993       if (TALER_amount_is_zero (ea) ||
   1994           TALER_amount_set_test_above (&wmc->total_exchange_limits,
   1995                                        ea))
   1996         num_choices++;
   1997       break;
   1998     case TALER_MERCHANT_CONTRACT_VERSION_1:
   1999       want_choices = oc->parse_choices.choices_len;
   2000       for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2001       {
   2002         ea = &oc->parse_choices.choices[i].amount;
   2003         if (TALER_amount_is_zero (ea) ||
   2004             TALER_amount_set_test_above (&wmc->total_exchange_limits,
   2005                                          ea))
   2006           num_choices++;
   2007       }
   2008       break;
   2009     default:
   2010       GNUNET_assert (0);
   2011     }
   2012     if (num_choices > max_choices)
   2013     {
   2014       best = wmc;
   2015       max_choices = num_choices;
   2016     }
   2017   }
   2018 
   2019   if ( (want_choices > max_choices) &&
   2020        (oc->set_exchanges.promising_exchange) &&
   2021        (! oc->set_exchanges.forced_reload) )
   2022   {
   2023     oc->set_exchanges.exchange_ok = false;
   2024     /* Not all choices in the contract can work with these
   2025        exchanges, try again with forcing /keys download */
   2026     for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2027          NULL != wmc;
   2028          wmc = wmc->next)
   2029     {
   2030       json_array_clear (wmc->exchanges);
   2031       TALER_amount_set_free (&wmc->total_exchange_limits);
   2032     }
   2033     oc->phase = ORDER_PHASE_SET_EXCHANGES;
   2034     return;
   2035   }
   2036 
   2037   if ( (NULL == best) &&
   2038        (! zero_amount) &&
   2039        (NULL != oc->parse_request.payment_target) )
   2040   {
   2041     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2042                 "Cannot create order: lacking suitable exchanges for payment target `%s'\n",
   2043                 oc->parse_request.payment_target);
   2044     reply_with_error (
   2045       oc,
   2046       MHD_HTTP_CONFLICT,
   2047       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGES_FOR_WIRE_METHOD,
   2048       oc->parse_request.payment_target);
   2049     return;
   2050   }
   2051 
   2052   if ( (NULL == best) &&
   2053        (! zero_amount) )
   2054   {
   2055     enum MHD_Result mret;
   2056 
   2057     /* We actually do not have ANY workable exchange(s) */
   2058     mret = TALER_MHD_reply_json_steal (
   2059       oc->connection,
   2060       GNUNET_JSON_PACK (
   2061         TALER_JSON_pack_ec (
   2062           TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_AMOUNT_EXCEEDS_LEGAL_LIMITS),
   2063         GNUNET_JSON_pack_allow_null (
   2064           GNUNET_JSON_pack_array_incref (
   2065             "exchange_rejections",
   2066             oc->set_exchanges.exchange_rejections))),
   2067       MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS);
   2068     finalize_order (oc,
   2069                     mret);
   2070     return;
   2071   }
   2072 
   2073   if (want_choices > max_choices)
   2074   {
   2075     /* Some choices are unpayable */
   2076     GNUNET_log (
   2077       GNUNET_ERROR_TYPE_WARNING,
   2078       "Creating order, but some choices do not work with the selected wire method\n");
   2079   }
   2080   if ( (0 == json_array_size (best->exchanges)) &&
   2081        (oc->add_payment_details.need_exchange) )
   2082   {
   2083     /* We did not find any reasonable exchange */
   2084     GNUNET_log (
   2085       GNUNET_ERROR_TYPE_WARNING,
   2086       "Creating order, but only for choices without payment\n");
   2087   }
   2088 
   2089   oc->select_wire_method.wm
   2090     = best->wm;
   2091   oc->select_wire_method.exchanges
   2092     = json_incref (best->exchanges);
   2093   oc->phase++;
   2094 }
   2095 
   2096 
   2097 /* ***************** ORDER_PHASE_SET_EXCHANGES **************** */
   2098 
   2099 /**
   2100  * Exchange `/keys` processing is done, resume handling
   2101  * the order.
   2102  *
   2103  * @param[in,out] oc context to resume
   2104  */
   2105 static void
   2106 resume_with_keys (struct OrderContext *oc)
   2107 {
   2108   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2109               "Resuming order processing after /keys downloads\n");
   2110   GNUNET_assert (GNUNET_YES == oc->suspended);
   2111   GNUNET_CONTAINER_DLL_remove (oc_head,
   2112                                oc_tail,
   2113                                oc);
   2114   oc->suspended = GNUNET_NO;
   2115   MHD_resume_connection (oc->connection);
   2116   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
   2117 }
   2118 
   2119 
   2120 /**
   2121  * Given a @a brutto amount for exchange with @a keys, set the
   2122  * @a stefan_fee. Note that @a stefan_fee is updated to the maximum
   2123  * of the input and the computed fee.
   2124  *
   2125  * @param[in,out] keys exchange keys
   2126  * @param brutto some brutto amount the client is to pay
   2127  * @param[in,out] stefan_fee set to STEFAN fee to be paid by the merchant
   2128  */
   2129 static void
   2130 compute_stefan_fee (const struct TALER_EXCHANGE_Keys *keys,
   2131                     const struct TALER_Amount *brutto,
   2132                     struct TALER_Amount *stefan_fee)
   2133 {
   2134   struct TALER_Amount net;
   2135 
   2136   if (GNUNET_SYSERR !=
   2137       TALER_EXCHANGE_keys_stefan_b2n (keys,
   2138                                       brutto,
   2139                                       &net))
   2140   {
   2141     struct TALER_Amount fee;
   2142 
   2143     TALER_EXCHANGE_keys_stefan_round (keys,
   2144                                       &net);
   2145     if (-1 == TALER_amount_cmp (brutto,
   2146                                 &net))
   2147     {
   2148       /* brutto < netto! */
   2149       /* => after rounding, there is no real difference */
   2150       net = *brutto;
   2151     }
   2152     GNUNET_assert (0 <=
   2153                    TALER_amount_subtract (&fee,
   2154                                           brutto,
   2155                                           &net));
   2156     if ( (GNUNET_OK !=
   2157           TALER_amount_is_valid (stefan_fee)) ||
   2158          (-1 == TALER_amount_cmp (stefan_fee,
   2159                                   &fee)) )
   2160     {
   2161       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2162                   "Updated STEFAN-based fee to %s\n",
   2163                   TALER_amount2s (&fee));
   2164       *stefan_fee = fee;
   2165     }
   2166   }
   2167 }
   2168 
   2169 
   2170 /**
   2171  * Update MAX STEFAN fees based on @a keys.
   2172  *
   2173  * @param[in,out] oc order context to update
   2174  * @param keys keys to derive STEFAN fees from
   2175  */
   2176 static void
   2177 update_stefan (struct OrderContext *oc,
   2178                const struct TALER_EXCHANGE_Keys *keys)
   2179 {
   2180   switch (oc->parse_order.order->base->version)
   2181   {
   2182   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2183     compute_stefan_fee (keys,
   2184                         &oc->parse_order.order->details.v0.brutto,
   2185                         &oc->set_exchanges.details.v0.max_stefan_fee);
   2186     break;
   2187   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2188     oc->set_exchanges.details.v1.max_stefan_fees
   2189       = GNUNET_new_array (oc->parse_choices.choices_len,
   2190                           struct TALER_Amount);
   2191     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2192       if (0 == strcasecmp (keys->currency,
   2193                            oc->parse_choices.choices[i].amount.currency))
   2194         compute_stefan_fee (keys,
   2195                             &oc->parse_choices.choices[i].amount,
   2196                             &oc->set_exchanges.details.v1.max_stefan_fees[i]);
   2197     break;
   2198   default:
   2199     GNUNET_assert (0);
   2200   }
   2201 }
   2202 
   2203 
   2204 /**
   2205  * Check our KYC status at all exchanges as our current limit is
   2206  * too low and we failed to create an order.
   2207  *
   2208  * @param oc order context
   2209  * @param wmc wire method candidate to notify for
   2210  * @param exchange_url exchange to notify about
   2211  */
   2212 static void
   2213 notify_kyc_required (const struct OrderContext *oc,
   2214                      const struct WireMethodCandidate *wmc,
   2215                      const char *exchange_url)
   2216 {
   2217   struct GNUNET_DB_EventHeaderP es = {
   2218     .size = htons (sizeof (es)),
   2219     .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
   2220   };
   2221   char *hws;
   2222   char *extra;
   2223 
   2224   hws = GNUNET_STRINGS_data_to_string_alloc (
   2225     &wmc->wm->h_wire,
   2226     sizeof (wmc->wm->h_wire));
   2227 
   2228   GNUNET_asprintf (&extra,
   2229                    "%s %s",
   2230                    hws,
   2231                    exchange_url);
   2232   TALER_MERCHANTDB_event_notify (TMH_db,
   2233                                  &es,
   2234                                  extra,
   2235                                  strlen (extra) + 1);
   2236   GNUNET_free (extra);
   2237   GNUNET_free (hws);
   2238 }
   2239 
   2240 
   2241 /**
   2242  * Add a reason why a particular exchange was rejected to our
   2243  * response data.
   2244  *
   2245  * @param[in,out] oc order context to update
   2246  * @param exchange_url exchange this is about
   2247  * @param ec error code to set for the exchange
   2248  */
   2249 static void
   2250 add_rejection (struct OrderContext *oc,
   2251                const char *exchange_url,
   2252                enum TALER_ErrorCode ec)
   2253 {
   2254   if (NULL == oc->set_exchanges.exchange_rejections)
   2255   {
   2256     oc->set_exchanges.exchange_rejections = json_array ();
   2257     GNUNET_assert (NULL != oc->set_exchanges.exchange_rejections);
   2258   }
   2259   GNUNET_assert (0 ==
   2260                  json_array_append_new (
   2261                    oc->set_exchanges.exchange_rejections,
   2262                    GNUNET_JSON_PACK (
   2263                      GNUNET_JSON_pack_string ("exchange_url",
   2264                                               exchange_url),
   2265                      TALER_JSON_pack_ec (ec))));
   2266 }
   2267 
   2268 
   2269 /**
   2270  * Checks the limits that apply for this @a exchange and
   2271  * the @a wmc and if the exchange is acceptable at all, adds it
   2272  * to the list of exchanges for the @a wmc.
   2273  *
   2274  * @param oc context of the order
   2275  * @param exchange internal handle for the exchange
   2276  * @param exchange_url base URL of this exchange
   2277  * @param wmc wire method to evaluate this exchange for
   2278  * @return true if the exchange is acceptable for the contract
   2279  */
   2280 static bool
   2281 get_acceptable (struct OrderContext *oc,
   2282                 const struct TMH_Exchange *exchange,
   2283                 const char *exchange_url,
   2284                 struct WireMethodCandidate *wmc)
   2285 {
   2286   const struct TALER_Amount *max_needed = NULL;
   2287   unsigned int priority = 42; /* make compiler happy */
   2288   json_t *j_exchange;
   2289   enum TMH_ExchangeStatus res;
   2290   struct TALER_Amount max_amount;
   2291 
   2292   for (unsigned int i = 0;
   2293        i<oc->add_payment_details.num_max_choice_limits;
   2294        i++)
   2295   {
   2296     const struct TALER_Amount *val
   2297       = &oc->add_payment_details.max_choice_limits[i];
   2298 
   2299     if (0 == strcasecmp (val->currency,
   2300                          TMH_EXCHANGES_get_currency (exchange)))
   2301     {
   2302       max_needed = val;
   2303       break;
   2304     }
   2305   }
   2306   if (NULL == max_needed)
   2307   {
   2308     /* exchange currency not relevant for any of our choices, skip it */
   2309     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2310                 "Exchange %s with currency `%s' is not applicable to this order\n",
   2311                 exchange_url,
   2312                 TMH_EXCHANGES_get_currency (exchange));
   2313     add_rejection (oc,
   2314                    exchange_url,
   2315                    TALER_EC_MERCHANT_GENERIC_CURRENCY_MISMATCH);
   2316     return false;
   2317   }
   2318 
   2319   max_amount = *max_needed;
   2320   res = TMH_exchange_check_debit (
   2321     oc->hc->instance->settings.id,
   2322     exchange,
   2323     wmc->wm,
   2324     &max_amount);
   2325   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2326               "Exchange %s evaluated at %d with max %s\n",
   2327               exchange_url,
   2328               res,
   2329               TALER_amount2s (&max_amount));
   2330   if (TALER_amount_is_zero (&max_amount))
   2331   {
   2332     if (! TALER_amount_is_zero (max_needed))
   2333     {
   2334       /* Trigger re-checking the current deposit limit when
   2335        * paying non-zero amount with zero deposit limit */
   2336       notify_kyc_required (oc,
   2337                            wmc,
   2338                            exchange_url);
   2339     }
   2340     /* If deposit is impossible, we don't list the
   2341      * exchange in the contract terms. */
   2342     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2343                 "Exchange %s deposit limit is zero, skipping it\n",
   2344                 exchange_url);
   2345     add_rejection (oc,
   2346                    exchange_url,
   2347                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_EXCHANGE_LEGALLY_REFUSED);
   2348     return false;
   2349   }
   2350   switch (res)
   2351   {
   2352   case TMH_ES_OK:
   2353   case TMH_ES_RETRY_OK:
   2354     priority = 1024;   /* high */
   2355     oc->set_exchanges.exchange_ok = true;
   2356     break;
   2357   case TMH_ES_NO_ACC:
   2358     if (oc->set_exchanges.forced_reload)
   2359       priority = 0;   /* fresh negative response */
   2360     else
   2361       priority = 512; /* stale negative response */
   2362     break;
   2363   case TMH_ES_NO_CURR:
   2364     if (oc->set_exchanges.forced_reload)
   2365       priority = 0;   /* fresh negative response */
   2366     else
   2367       priority = 512; /* stale negative response */
   2368     break;
   2369   case TMH_ES_NO_KEYS:
   2370     if (oc->set_exchanges.forced_reload)
   2371       priority = 256;   /* fresh, no accounts yet */
   2372     else
   2373       priority = 768;  /* stale, no accounts yet */
   2374     break;
   2375   case TMH_ES_NO_ACC_RETRY_OK:
   2376     if (oc->set_exchanges.forced_reload)
   2377     {
   2378       priority = 0;   /* fresh negative response */
   2379     }
   2380     else
   2381     {
   2382       oc->set_exchanges.promising_exchange = true;
   2383       priority = 512; /* stale negative response */
   2384     }
   2385     break;
   2386   case TMH_ES_NO_CURR_RETRY_OK:
   2387     if (oc->set_exchanges.forced_reload)
   2388       priority = 0;   /* fresh negative response */
   2389     else
   2390       priority = 512; /* stale negative response */
   2391     break;
   2392   case TMH_ES_NO_KEYS_RETRY_OK:
   2393     if (oc->set_exchanges.forced_reload)
   2394     {
   2395       priority = 256;   /* fresh, no accounts yet */
   2396     }
   2397     else
   2398     {
   2399       oc->set_exchanges.promising_exchange = true;
   2400       priority = 768;  /* stale, no accounts yet */
   2401     }
   2402     break;
   2403   }
   2404   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2405               "Exchange %s deposit limit is %s, adding it!\n",
   2406               exchange_url,
   2407               TALER_amount2s (&max_amount));
   2408 
   2409   j_exchange = GNUNET_JSON_PACK (
   2410     GNUNET_JSON_pack_string ("url",
   2411                              exchange_url),
   2412     GNUNET_JSON_pack_uint64 ("priority",
   2413                              priority),
   2414     TALER_JSON_pack_amount ("max_contribution",
   2415                             &max_amount),
   2416     GNUNET_JSON_pack_data_auto ("master_pub",
   2417                                 TMH_EXCHANGES_get_master_pub (exchange)));
   2418   GNUNET_assert (NULL != j_exchange);
   2419   /* Add exchange to list of exchanges for this wire method
   2420      candidate */
   2421   GNUNET_assert (0 ==
   2422                  json_array_append_new (wmc->exchanges,
   2423                                         j_exchange));
   2424   GNUNET_assert (0 <=
   2425                  TALER_amount_set_add (&wmc->total_exchange_limits,
   2426                                        &max_amount,
   2427                                        max_needed));
   2428   return true;
   2429 }
   2430 
   2431 
   2432 /**
   2433  * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
   2434  * operation.
   2435  *
   2436  * @param cls closure with our `struct RekeyExchange *`
   2437  * @param keys the keys of the exchange
   2438  * @param exchange representation of the exchange
   2439  */
   2440 static void
   2441 keys_cb (
   2442   void *cls,
   2443   struct TALER_EXCHANGE_Keys *keys,
   2444   struct TMH_Exchange *exchange)
   2445 {
   2446   struct RekeyExchange *rx = cls;
   2447   struct OrderContext *oc = rx->oc;
   2448   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   2449     &oc->hc->instance->settings;
   2450   bool applicable = false;
   2451 
   2452   rx->fo = NULL;
   2453   GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
   2454                                oc->set_exchanges.pending_reload_tail,
   2455                                rx);
   2456   if (NULL == keys)
   2457   {
   2458     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2459                 "Failed to download %skeys\n",
   2460                 rx->url);
   2461     oc->set_exchanges.promising_exchange = true;
   2462     add_rejection (oc,
   2463                    rx->url,
   2464                    TALER_EC_MERCHANT_GENERIC_EXCHANGE_KEYS_FAILURE);
   2465     goto cleanup;
   2466   }
   2467   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2468               "Got response for %skeys\n",
   2469               rx->url);
   2470 
   2471   /* Evaluate the use of this exchange for each wire method candidate.
   2472      Note that the exchange may have *several* accounts sharing the same
   2473      wire method; as get_acceptable() judges the exchange as a whole (and
   2474      not the individual account), it must be called at most once per wire
   2475      method candidate, or we would list the exchange more than once in the
   2476      contract terms and count its deposit limit more than once. */
   2477   for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2478        NULL != wmc;
   2479        wmc = wmc->next)
   2480   {
   2481     bool matches = false;
   2482 
   2483     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2484                 "Order could use wire method `%s'\n",
   2485                 wmc->wm->wire_method);
   2486     for (unsigned int j = 0; j<keys->accounts_len; j++)
   2487     {
   2488       struct TALER_FullPayto full_payto = keys->accounts[j].fpayto_uri;
   2489       char *wire_method = TALER_payto_get_method (full_payto.full_payto);
   2490 
   2491       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2492                   "Exchange `%s' has wire method `%s'\n",
   2493                   rx->url,
   2494                   wire_method);
   2495       matches = (0 == strcmp (wmc->wm->wire_method,
   2496                               wire_method));
   2497       GNUNET_free (wire_method);
   2498       if (matches)
   2499         break;
   2500     }
   2501     if (matches)
   2502       applicable |= get_acceptable (oc,
   2503                                     exchange,
   2504                                     rx->url,
   2505                                     wmc);
   2506   }
   2507   if ( (! applicable) &&
   2508        (! oc->set_exchanges.forced_reload) )
   2509   {
   2510     /* Checks for 'forced_reload' to not log the error *again*
   2511        if we forced a re-load and are encountering the
   2512        applicability error a 2nd time */
   2513     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2514                 "Exchange `%s' %u wire methods are not applicable to this order\n",
   2515                 rx->url,
   2516                 keys->accounts_len);
   2517     add_rejection (oc,
   2518                    rx->url,
   2519                    TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_WIRE_METHOD_UNSUPPORTED);
   2520   }
   2521   if (applicable &&
   2522       settings->use_stefan)
   2523     update_stefan (oc,
   2524                    keys);
   2525 cleanup:
   2526   GNUNET_free (rx->url);
   2527   GNUNET_free (rx);
   2528   if (NULL != oc->set_exchanges.pending_reload_head)
   2529     return;
   2530   resume_with_keys (oc);
   2531 }
   2532 
   2533 
   2534 /**
   2535  * Force re-downloading of /keys from @a exchange,
   2536  * we currently have no acceptable exchange, so we
   2537  * should try to get one.
   2538  *
   2539  * @param cls closure with our `struct OrderContext`
   2540  * @param url base URL of the exchange
   2541  * @param exchange internal handle for the exchange
   2542  */
   2543 static void
   2544 get_exchange_keys (void *cls,
   2545                    const char *url,
   2546                    const struct TMH_Exchange *exchange)
   2547 {
   2548   struct OrderContext *oc = cls;
   2549   struct RekeyExchange *rx;
   2550 
   2551   rx = GNUNET_new (struct RekeyExchange);
   2552   rx->oc = oc;
   2553   rx->url = GNUNET_strdup (url);
   2554   GNUNET_CONTAINER_DLL_insert (oc->set_exchanges.pending_reload_head,
   2555                                oc->set_exchanges.pending_reload_tail,
   2556                                rx);
   2557   if (oc->set_exchanges.forced_reload)
   2558     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2559                 "Forcing download of %skeys\n",
   2560                 url);
   2561   rx->fo = TMH_EXCHANGES_keys4exchange (url,
   2562                                         oc->set_exchanges.forced_reload,
   2563                                         &keys_cb,
   2564                                         rx);
   2565 }
   2566 
   2567 
   2568 /**
   2569  * Task run when we are timing out on /keys and will just
   2570  * proceed with what we got.
   2571  *
   2572  * @param cls our `struct OrderContext *` to resume
   2573  */
   2574 static void
   2575 wakeup_timeout (void *cls)
   2576 {
   2577   struct OrderContext *oc = cls;
   2578 
   2579   oc->set_exchanges.wakeup_task = NULL;
   2580   GNUNET_assert (GNUNET_YES == oc->suspended);
   2581   GNUNET_CONTAINER_DLL_remove (oc_head,
   2582                                oc_tail,
   2583                                oc);
   2584   MHD_resume_connection (oc->connection);
   2585   oc->suspended = GNUNET_NO;
   2586   TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
   2587 }
   2588 
   2589 
   2590 /**
   2591  * Set list of acceptable exchanges in @a oc. Upon success, continues
   2592  * processing with add_payment_details().
   2593  *
   2594  * @param[in,out] oc order context
   2595  * @return true to suspend execution
   2596  */
   2597 static bool
   2598 phase_set_exchanges (struct OrderContext *oc)
   2599 {
   2600   if (NULL != oc->set_exchanges.wakeup_task)
   2601   {
   2602     GNUNET_SCHEDULER_cancel (oc->set_exchanges.wakeup_task);
   2603     oc->set_exchanges.wakeup_task = NULL;
   2604   }
   2605 
   2606   if (! oc->add_payment_details.need_exchange)
   2607   {
   2608     /* Total amount is zero, so we don't actually need exchanges! */
   2609     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2610                 "Order total is zero, no need for exchanges\n");
   2611     oc->select_wire_method.exchanges = json_array ();
   2612     GNUNET_assert (NULL != oc->select_wire_method.exchanges);
   2613     /* Pick first one, doesn't matter as the amount is zero */
   2614     oc->select_wire_method.wm = oc->hc->instance->wm_head;
   2615     oc->phase = ORDER_PHASE_SET_MAX_FEE;
   2616     return false;
   2617   }
   2618   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2619               "Trying to find exchanges\n");
   2620   if (NULL == oc->set_exchanges.pending_reload_head)
   2621   {
   2622     if (! oc->set_exchanges.exchanges_tried)
   2623     {
   2624       oc->set_exchanges.exchanges_tried = true;
   2625       oc->set_exchanges.keys_timeout
   2626         = GNUNET_TIME_relative_to_absolute (MAX_KEYS_WAIT);
   2627       TMH_exchange_get_trusted (&get_exchange_keys,
   2628                                 oc);
   2629     }
   2630     else if ( (! oc->set_exchanges.forced_reload) &&
   2631               (oc->set_exchanges.promising_exchange) &&
   2632               (! oc->set_exchanges.exchange_ok) )
   2633     {
   2634       for (struct WireMethodCandidate *wmc = oc->add_payment_details.wmc_head;
   2635            NULL != wmc;
   2636            wmc = wmc->next)
   2637         GNUNET_break (0 ==
   2638                       json_array_clear (wmc->exchanges));
   2639       /* Try one more time with forcing /keys download */
   2640       oc->set_exchanges.forced_reload = true;
   2641       TMH_exchange_get_trusted (&get_exchange_keys,
   2642                                 oc);
   2643     }
   2644   }
   2645   if (GNUNET_TIME_absolute_is_past (oc->set_exchanges.keys_timeout))
   2646   {
   2647     struct RekeyExchange *rx;
   2648 
   2649     while (NULL != (rx = oc->set_exchanges.pending_reload_head))
   2650     {
   2651       GNUNET_CONTAINER_DLL_remove (oc->set_exchanges.pending_reload_head,
   2652                                    oc->set_exchanges.pending_reload_tail,
   2653                                    rx);
   2654       TMH_EXCHANGES_keys4exchange_cancel (rx->fo);
   2655       GNUNET_free (rx->url);
   2656       GNUNET_free (rx);
   2657     }
   2658   }
   2659   if (NULL != oc->set_exchanges.pending_reload_head)
   2660   {
   2661     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2662                 "Still trying to (re)load %skeys\n",
   2663                 oc->set_exchanges.pending_reload_head->url);
   2664     oc->set_exchanges.wakeup_task
   2665       = GNUNET_SCHEDULER_add_at (oc->set_exchanges.keys_timeout,
   2666                                  &wakeup_timeout,
   2667                                  oc);
   2668     MHD_suspend_connection (oc->connection);
   2669     oc->suspended = GNUNET_YES;
   2670     GNUNET_CONTAINER_DLL_insert (oc_head,
   2671                                  oc_tail,
   2672                                  oc);
   2673     return true; /* reloads pending */
   2674   }
   2675   oc->phase++;
   2676   return false;
   2677 }
   2678 
   2679 
   2680 /* ***************** ORDER_PHASE_ADD_PAYMENT_DETAILS **************** */
   2681 
   2682 /**
   2683  * Process the @a payment_target and add the details of how the
   2684  * order could be paid to @a order. On success, continue
   2685  * processing with add_payment_fees().
   2686  *
   2687  * @param[in,out] oc order context
   2688  */
   2689 static void
   2690 phase_add_payment_details (struct OrderContext *oc)
   2691 {
   2692   /* First, determine the maximum amounts that could be paid per currency */
   2693   switch (oc->parse_order.order->base->version)
   2694   {
   2695   case TALER_MERCHANT_CONTRACT_VERSION_0:
   2696     GNUNET_array_append (oc->add_payment_details.max_choice_limits,
   2697                          oc->add_payment_details.num_max_choice_limits,
   2698                          oc->parse_order.order->details.v0.brutto);
   2699     if (! TALER_amount_is_zero (
   2700           &oc->parse_order.order->details.v0.brutto))
   2701     {
   2702       oc->add_payment_details.need_exchange = true;
   2703     }
   2704     break;
   2705   case TALER_MERCHANT_CONTRACT_VERSION_1:
   2706     for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   2707     {
   2708       const struct TALER_Amount *amount
   2709         = &oc->parse_choices.choices[i].amount;
   2710       bool found = false;
   2711 
   2712       if (! TALER_amount_is_zero (amount))
   2713       {
   2714         oc->add_payment_details.need_exchange = true;
   2715       }
   2716       for (unsigned int j = 0;
   2717            j<oc->add_payment_details.num_max_choice_limits;
   2718            j++)
   2719       {
   2720         struct TALER_Amount *mx = &oc->add_payment_details.max_choice_limits[j];
   2721         if (GNUNET_YES ==
   2722             TALER_amount_cmp_currency (mx,
   2723                                        amount))
   2724         {
   2725           TALER_amount_max (mx,
   2726                             mx,
   2727                             amount);
   2728           found = true;
   2729           break;
   2730         }
   2731       }
   2732       if (! found)
   2733       {
   2734         GNUNET_array_append (oc->add_payment_details.max_choice_limits,
   2735                              oc->add_payment_details.num_max_choice_limits,
   2736                              *amount);
   2737       }
   2738     }
   2739     break;
   2740   default:
   2741     GNUNET_assert (0);
   2742   }
   2743 
   2744   /* Then, create a candidate for each available wire method */
   2745   for (struct TMH_WireMethod *wm = oc->hc->instance->wm_head;
   2746        NULL != wm;
   2747        wm = wm->next)
   2748   {
   2749     struct WireMethodCandidate *wmc;
   2750 
   2751     /* Locate wire method that has a matching payment target */
   2752     if (! wm->active)
   2753       continue; /* ignore inactive methods */
   2754     if ( (NULL != oc->parse_request.payment_target) &&
   2755          (0 != strcasecmp (oc->parse_request.payment_target,
   2756                            wm->wire_method) ) )
   2757       continue; /* honor client preference */
   2758     wmc = GNUNET_new (struct WireMethodCandidate);
   2759     wmc->wm = wm;
   2760     wmc->exchanges = json_array ();
   2761     GNUNET_assert (NULL != wmc->exchanges);
   2762     GNUNET_CONTAINER_DLL_insert (oc->add_payment_details.wmc_head,
   2763                                  oc->add_payment_details.wmc_tail,
   2764                                  wmc);
   2765   }
   2766 
   2767   if (NULL == oc->add_payment_details.wmc_head)
   2768   {
   2769     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2770                 "No wire method available for instance '%s'\n",
   2771                 oc->hc->instance->settings.id);
   2772     reply_with_error (oc,
   2773                       MHD_HTTP_NOT_FOUND,
   2774                       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_INSTANCE_CONFIGURATION_LACKS_WIRE,
   2775                       oc->parse_request.payment_target);
   2776     return;
   2777   }
   2778 
   2779   /* next, we'll evaluate available exchanges */
   2780   oc->phase++;
   2781 }
   2782 
   2783 
   2784 /* ***************** ORDER_PHASE_MERGE_INVENTORY **************** */
   2785 
   2786 
   2787 /**
   2788  * Helper function to sort uint64_t array with qsort().
   2789  *
   2790  * @param a pointer to element to compare
   2791  * @param b pointer to element to compare
   2792  * @return 0 on equal, -1 on smaller, 1 on larger
   2793  */
   2794 static int
   2795 uint64_cmp (const void *a,
   2796             const void *b)
   2797 {
   2798   uint64_t ua = *(const uint64_t *) a;
   2799   uint64_t ub = *(const uint64_t *) b;
   2800 
   2801   if (ua < ub)
   2802     return -1;
   2803   if (ua > ub)
   2804     return 1;
   2805   return 0;
   2806 }
   2807 
   2808 
   2809 /**
   2810  * Merge the inventory products into products, querying the
   2811  * database about the details of those products. Upon success,
   2812  * continue processing by calling add_payment_details().
   2813  *
   2814  * @param[in,out] oc order context to process
   2815  */
   2816 static void
   2817 phase_merge_inventory (struct OrderContext *oc)
   2818 {
   2819   uint64_t pots[oc->parse_order.order->products_len + 1];
   2820   size_t pots_off = 0;
   2821 
   2822   if (0 != oc->parse_order.order->base->default_money_pot)
   2823     pots[pots_off++] = oc->parse_order.order->base->default_money_pot;
   2824   /**
   2825    * parse_request.inventory_products => instructions to add products to contract terms
   2826    * parse_order.products => contains products that are not from the backend-managed inventory.
   2827    */
   2828   oc->merge_inventory.products = json_array ();
   2829   for (size_t i = 0; i<oc->parse_order.order->products_len; i++)
   2830   {
   2831     GNUNET_assert (
   2832       0 ==
   2833       json_array_append_new (
   2834         oc->merge_inventory.products,
   2835         TALER_MERCHANT_product_sold_serialize (
   2836           &oc->parse_order.order->products[i])));
   2837     if (0 != oc->parse_order.order->products[i].product_money_pot)
   2838       pots[pots_off++] = oc->parse_order.order->products[i].product_money_pot;
   2839   }
   2840 
   2841   /* make sure pots array only has distinct elements */
   2842   qsort (pots,
   2843          pots_off,
   2844          sizeof (uint64_t),
   2845          &uint64_cmp);
   2846   {
   2847     size_t e = 0;
   2848 
   2849     for (size_t i = 1; i<pots_off; i++)
   2850     {
   2851       if (pots[e] != pots[i])
   2852         pots[++e] = pots[i];
   2853     }
   2854     if (pots_off > 0)
   2855       e++;
   2856     pots_off = e;
   2857   }
   2858   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2859               "Found %u unique money pots in order\n",
   2860               (unsigned int) pots_off);
   2861 
   2862   /* check if all money pots exist; note that we do NOT treat
   2863      the inventory products to this check, as (1) the foreign key
   2864      constraint should ensure this, and (2) if the money pot
   2865      were deleted (concurrently), the value is specified to be
   2866      considered 0 (aka none) and so we can proceed anyway. */
   2867   if (pots_off > 0)
   2868   {
   2869     enum GNUNET_DB_QueryStatus qs;
   2870     uint64_t pot_missing;
   2871 
   2872     qs = TALER_MERCHANTDB_get_missing_money_pot (TMH_db,
   2873                                                  oc->hc->instance->settings.id,
   2874                                                  pots_off,
   2875                                                  pots,
   2876                                                  &pot_missing);
   2877     switch (qs)
   2878     {
   2879     case GNUNET_DB_STATUS_HARD_ERROR:
   2880     case GNUNET_DB_STATUS_SOFT_ERROR:
   2881       GNUNET_break (0);
   2882       reply_with_error (oc,
   2883                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   2884                         TALER_EC_GENERIC_DB_FETCH_FAILED,
   2885                         "get_missing_money_pot");
   2886       return;
   2887     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   2888       /* great, good case! */
   2889       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2890                   "All money pots exist\n");
   2891       break;
   2892     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   2893       {
   2894         char mstr[32];
   2895 
   2896         GNUNET_snprintf (mstr,
   2897                          sizeof (mstr),
   2898                          "%llu",
   2899                          (unsigned long long) pot_missing);
   2900         reply_with_error (oc,
   2901                           MHD_HTTP_NOT_FOUND,
   2902                           TALER_EC_MERCHANT_GENERIC_MONEY_POT_UNKNOWN,
   2903                           mstr);
   2904         return;
   2905       }
   2906     }
   2907   }
   2908 
   2909   /* Populate products from inventory product array and database */
   2910   {
   2911     GNUNET_assert (NULL != oc->merge_inventory.products);
   2912     for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   2913     {
   2914       struct InventoryProduct *ip
   2915         = &oc->parse_request.inventory_products[i];
   2916       struct TALER_MERCHANTDB_ProductDetails pd;
   2917       enum GNUNET_DB_QueryStatus qs;
   2918       size_t num_categories = 0;
   2919       uint64_t *categories = NULL;
   2920 
   2921       qs = TALER_MERCHANTDB_get_product (TMH_db,
   2922                                          oc->hc->instance->settings.id,
   2923                                          ip->product_id,
   2924                                          &pd,
   2925                                          &num_categories,
   2926                                          &categories);
   2927       if (qs <= 0)
   2928       {
   2929         enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
   2930         unsigned int http_status = 0;
   2931 
   2932         switch (qs)
   2933         {
   2934         case GNUNET_DB_STATUS_HARD_ERROR:
   2935           GNUNET_break (0);
   2936           http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   2937           ec = TALER_EC_GENERIC_DB_FETCH_FAILED;
   2938           break;
   2939         case GNUNET_DB_STATUS_SOFT_ERROR:
   2940           GNUNET_break (0);
   2941           http_status = MHD_HTTP_INTERNAL_SERVER_ERROR;
   2942           ec = TALER_EC_GENERIC_DB_SOFT_FAILURE;
   2943           break;
   2944         case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   2945           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2946                       "Product %s from order unknown\n",
   2947                       ip->product_id);
   2948           http_status = MHD_HTTP_NOT_FOUND;
   2949           ec = TALER_EC_MERCHANT_GENERIC_PRODUCT_UNKNOWN;
   2950           break;
   2951         case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   2952           /* case listed to make compilers happy */
   2953           GNUNET_assert (0);
   2954         }
   2955         reply_with_error (oc,
   2956                           http_status,
   2957                           ec,
   2958                           ip->product_id);
   2959         return;
   2960       }
   2961       GNUNET_free (categories);
   2962       oc->parse_order.order->base->minimum_age
   2963         = GNUNET_MAX (oc->parse_order.order->base->minimum_age,
   2964                       pd.minimum_age);
   2965       {
   2966         const char *eparam;
   2967 
   2968         if ( (! ip->quantity_missing) &&
   2969              (ip->quantity > (uint64_t) INT64_MAX) )
   2970         {
   2971           GNUNET_break_op (0);
   2972           reply_with_error (oc,
   2973                             MHD_HTTP_BAD_REQUEST,
   2974                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   2975                             "quantity");
   2976           TALER_MERCHANTDB_product_details_free (&pd);
   2977           return;
   2978         }
   2979         if (GNUNET_OK !=
   2980             TALER_MERCHANT_vk_process_quantity_inputs (
   2981               TALER_MERCHANT_VK_QUANTITY,
   2982               pd.allow_fractional_quantity,
   2983               ip->quantity_missing,
   2984               (int64_t) ip->quantity,
   2985               ip->unit_quantity_missing,
   2986               ip->unit_quantity,
   2987               &ip->quantity,
   2988               &ip->quantity_frac,
   2989               &eparam))
   2990         {
   2991           GNUNET_break_op (0);
   2992           reply_with_error (oc,
   2993                             MHD_HTTP_BAD_REQUEST,
   2994                             TALER_EC_GENERIC_PARAMETER_MALFORMED,
   2995                             eparam);
   2996           TALER_MERCHANTDB_product_details_free (&pd);
   2997           return;
   2998         }
   2999       }
   3000       {
   3001         struct TALER_MERCHANT_ProductSold ps = {
   3002           .product_id = (char *) ip->product_id,
   3003           .product_name = pd.product_name,
   3004           .description = pd.description,
   3005           .description_i18n = pd.description_i18n,
   3006           .unit_quantity.integer = ip->quantity,
   3007           .unit_quantity.fractional = ip->quantity_frac,
   3008           .prices_length = pd.price_array_length,
   3009           .prices = GNUNET_new_array (pd.price_array_length,
   3010                                       struct TALER_Amount),
   3011           .prices_are_net = pd.price_is_net,
   3012           .image = pd.image,
   3013           .taxes = pd.taxes,
   3014           .delivery_date = oc->parse_order.order->base->delivery_date,
   3015           .product_money_pot = pd.money_pot_id,
   3016           .unit = pd.unit,
   3017 
   3018         };
   3019         json_t *p;
   3020         char unit_quantity_buf[64];
   3021 
   3022         for (size_t j = 0; j<pd.price_array_length; j++)
   3023         {
   3024           struct TALER_Amount atomic_amount;
   3025 
   3026           GNUNET_assert (
   3027             GNUNET_OK ==
   3028             TALER_amount_set_zero (pd.price_array[j].currency,
   3029                                    &atomic_amount));
   3030           atomic_amount.fraction = 1;
   3031           GNUNET_assert (
   3032             GNUNET_OK ==
   3033             TALER_MERCHANT_amount_multiply_by_quantity (
   3034               &ps.prices[j],
   3035               &pd.price_array[j],
   3036               &ps.unit_quantity,
   3037               TALER_MERCHANT_ROUND_UP,
   3038               &atomic_amount));
   3039         }
   3040 
   3041         TALER_MERCHANT_vk_format_fractional_string (
   3042           TALER_MERCHANT_VK_QUANTITY,
   3043           ip->quantity,
   3044           ip->quantity_frac,
   3045           sizeof (unit_quantity_buf),
   3046           unit_quantity_buf);
   3047         if (0 != pd.money_pot_id)
   3048           pots[pots_off++] = pd.money_pot_id;
   3049         p = TALER_MERCHANT_product_sold_serialize (&ps);
   3050         GNUNET_assert (NULL != p);
   3051         GNUNET_free (ps.prices);
   3052         GNUNET_assert (0 ==
   3053                        json_array_append_new (oc->merge_inventory.products,
   3054                                               p));
   3055       }
   3056       TALER_MERCHANTDB_product_details_free (&pd);
   3057     }
   3058   }
   3059 
   3060   /* check if final product list is well-formed */
   3061   if (! TMH_products_array_valid (oc->merge_inventory.products))
   3062   {
   3063     GNUNET_break_op (0);
   3064     reply_with_error (oc,
   3065                       MHD_HTTP_BAD_REQUEST,
   3066                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3067                       "order:products");
   3068     return;
   3069   }
   3070   oc->phase++;
   3071 }
   3072 
   3073 
   3074 /* ***************** ORDER_PHASE_PARSE_CHOICES **************** */
   3075 
   3076 /**
   3077  * Callback function that is called for each donau instance.
   3078  * It simply adds the provided donau_url to the json.
   3079  *
   3080  * @param cls closure with our `struct TALER_MERCHANT_ContractOutput *`
   3081  * @param donau_url the URL of the donau instance
   3082  */
   3083 static void
   3084 add_donau_url (void *cls,
   3085                const char *donau_url)
   3086 {
   3087   struct TALER_MERCHANT_ContractOutput *output = cls;
   3088 
   3089   GNUNET_array_append (output->details.donation_receipt.donau_urls,
   3090                        output->details.donation_receipt.donau_urls_len,
   3091                        GNUNET_strdup (donau_url));
   3092 }
   3093 
   3094 
   3095 /**
   3096  * Add the donau output to the contract output.
   3097  *
   3098  * @param oc order context
   3099  * @param output contract output to add donau URLs to
   3100  */
   3101 static bool
   3102 add_donau_output (struct OrderContext *oc,
   3103                   struct TALER_MERCHANT_ContractOutput *output)
   3104 {
   3105   enum GNUNET_DB_QueryStatus qs;
   3106 
   3107   qs = TALER_MERCHANTDB_iterate_donau_instances_filtered (
   3108     TMH_db,
   3109     output->details.donation_receipt.amount.currency,
   3110     &add_donau_url,
   3111     output);
   3112   if (qs < 0)
   3113   {
   3114     GNUNET_break (0);
   3115     reply_with_error (oc,
   3116                       MHD_HTTP_INTERNAL_SERVER_ERROR,
   3117                       TALER_EC_GENERIC_DB_FETCH_FAILED,
   3118                       "donau url parsing db call");
   3119     for (unsigned int i = 0;
   3120          i < output->details.donation_receipt.donau_urls_len;
   3121          i++)
   3122       GNUNET_free (output->details.donation_receipt.donau_urls[i]);
   3123     GNUNET_array_grow (output->details.donation_receipt.donau_urls,
   3124                        output->details.donation_receipt.donau_urls_len,
   3125                        0);
   3126     return false;
   3127   }
   3128   return true;
   3129 }
   3130 
   3131 
   3132 /**
   3133  * Parse contract choices. Upon success, continue
   3134  * processing with merge_inventory().
   3135  *
   3136  * @param[in,out] oc order context
   3137  */
   3138 static void
   3139 phase_parse_choices (struct OrderContext *oc)
   3140 {
   3141   switch (oc->parse_order.order->base->version)
   3142   {
   3143   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3144     oc->phase++;
   3145     return;
   3146   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3147     /* handle below */
   3148     break;
   3149   default:
   3150     GNUNET_assert (0);
   3151   }
   3152 
   3153   /* Convert order choices to contract choices */
   3154   GNUNET_array_grow (oc->parse_choices.choices,
   3155                      oc->parse_choices.choices_len,
   3156                      oc->parse_order.order->details.v1.choices_len);
   3157   for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
   3158   {
   3159     const struct TALER_MERCHANT_OrderChoice *ochoice
   3160       = &oc->parse_order.order->details.v1.choices[i];
   3161     struct TALER_MERCHANT_ContractChoice *cchoice
   3162       = &oc->parse_choices.choices[i];
   3163     unsigned int off;
   3164 
   3165     if (! TMH_test_exchange_configured_for_currency (
   3166           ochoice->amount.currency))
   3167     {
   3168       GNUNET_break_op (0);
   3169       reply_with_error (oc,
   3170                         MHD_HTTP_CONFLICT,
   3171                         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
   3172                         ochoice->amount.currency);
   3173       return;
   3174     }
   3175     cchoice->amount = ochoice->amount;
   3176     cchoice->tip = ochoice->tip;
   3177     cchoice->no_tip = ochoice->no_tip;
   3178     if (NULL != ochoice->description)
   3179       cchoice->description = GNUNET_strdup (ochoice->description);
   3180     if (NULL != ochoice->description_i18n)
   3181       cchoice->description_i18n = json_incref (ochoice->description_i18n);
   3182     cchoice->max_fee = ochoice->max_fee;
   3183 
   3184     /* convert inputs */
   3185     GNUNET_array_grow (cchoice->inputs,
   3186                        cchoice->inputs_len,
   3187                        ochoice->inputs_len);
   3188     off = 0;
   3189     for (unsigned int j = 0; j < ochoice->inputs_len; j++)
   3190     {
   3191       const struct TALER_MERCHANT_OrderInput *order_input
   3192         = &ochoice->inputs[j];
   3193       struct TALER_MERCHANT_ContractInput *contract_input
   3194         = &cchoice->inputs[off];
   3195 
   3196       contract_input->type = order_input->type;
   3197       switch (order_input->type)
   3198       {
   3199       case TALER_MERCHANT_CONTRACT_INPUT_TYPE_INVALID:
   3200         GNUNET_assert (0);
   3201         break;
   3202       case TALER_MERCHANT_CONTRACT_INPUT_TYPE_TOKEN:
   3203         /* Ignore inputs tokens with 'count' field set to 0 */
   3204         if (0 == order_input->details.token.count)
   3205           continue;
   3206         contract_input->details.token.count
   3207           = order_input->details.token.count;
   3208         contract_input->details.token.token_family_slug
   3209           = order_input->details.token.token_family_slug;
   3210         if (GNUNET_OK !=
   3211             add_input_token_family (oc,
   3212                                     contract_input->details.token.token_family_slug))
   3213         {
   3214           GNUNET_break_op (0);
   3215           return;
   3216         }
   3217         off++;
   3218         continue;
   3219       } /* switch input type */
   3220       GNUNET_assert (0);
   3221     } /* for all inputs */
   3222     GNUNET_array_grow (cchoice->inputs,
   3223                        cchoice->inputs_len,
   3224                        off);
   3225 
   3226     /* convert outputs */
   3227     GNUNET_array_grow (cchoice->outputs,
   3228                        cchoice->outputs_len,
   3229                        ochoice->outputs_len);
   3230     off = 0;
   3231     for (unsigned int j = 0; j < ochoice->outputs_len; j++)
   3232     {
   3233       const struct TALER_MERCHANT_OrderOutput *order_output
   3234         = &ochoice->outputs[j];
   3235       struct TALER_MERCHANT_ContractOutput *contract_output
   3236         = &cchoice->outputs[off];
   3237 
   3238       contract_output->type = order_output->type;
   3239       switch (order_output->type)
   3240       {
   3241       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_INVALID:
   3242         GNUNET_assert (0);
   3243         break;
   3244       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
   3245         if (order_output->details.donation_receipt.no_amount)
   3246         {
   3247           contract_output->details.donation_receipt.amount
   3248             = ochoice->amount;
   3249         }
   3250         else
   3251         {
   3252           contract_output->details.donation_receipt.amount
   3253             = order_output->details.donation_receipt.amount;
   3254         }
   3255         if (! add_donau_output (oc,
   3256                                 contract_output))
   3257         {
   3258           GNUNET_break (0);
   3259           return;
   3260         }
   3261         off++;
   3262         continue;
   3263       case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN:
   3264         /* Ignore inputs tokens with 'count' field set to 0 */
   3265         if (0 == order_output->details.token.count)
   3266           continue;
   3267 
   3268         contract_output->details.token.token_family_slug
   3269           = order_output->details.token.token_family_slug;
   3270         contract_output->details.token.count
   3271           = order_output->details.token.count;
   3272         if (0 == order_output->details.token.valid_at.abs_time.abs_value_us)
   3273           contract_output->details.token.valid_at
   3274             = GNUNET_TIME_timestamp_get ();
   3275         else
   3276           contract_output->details.token.valid_at
   3277             = order_output->details.token.valid_at;
   3278         if (GNUNET_OK !=
   3279             add_output_token_family (
   3280               oc,
   3281               contract_output->details.token.token_family_slug,
   3282               contract_output->details.token.valid_at,
   3283               &contract_output->details.token.key_index))
   3284 
   3285         {
   3286           /* note: reply_with_error() was already called */
   3287           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3288                       "Could not handle output token family `%s'\n",
   3289                       contract_output->details.token.token_family_slug);
   3290           return;
   3291         }
   3292         off++;
   3293         continue;
   3294       } /* end switch */
   3295       GNUNET_assert (0);
   3296     } /* for outputs */
   3297     GNUNET_array_grow (cchoice->outputs,
   3298                        cchoice->outputs_len,
   3299                        off);
   3300   } /* for all choices */
   3301   oc->phase++;
   3302 }
   3303 
   3304 
   3305 /* ***************** ORDER_PHASE_PARSE_ORDER **************** */
   3306 
   3307 
   3308 /**
   3309  * Parse the order field of the request. Upon success, continue
   3310  * processing with parse_choices().
   3311  *
   3312  * @param[in,out] oc order context
   3313  */
   3314 static void
   3315 phase_parse_order (struct OrderContext *oc)
   3316 {
   3317   const struct TALER_MERCHANTDB_InstanceSettings *settings =
   3318     &oc->hc->instance->settings;
   3319   bool computed_refund_deadline = false;
   3320 
   3321   oc->parse_order.order
   3322     = TALER_MERCHANT_order_parse (
   3323         oc->parse_request.order);
   3324   if (NULL == oc->parse_order.order)
   3325   {
   3326     GNUNET_break_op (0);
   3327     reply_with_error (oc,
   3328                       MHD_HTTP_BAD_REQUEST,
   3329                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3330                       "order");
   3331     return;
   3332   }
   3333 
   3334   switch (oc->parse_order.order->base->version)
   3335   {
   3336   case TALER_MERCHANT_CONTRACT_VERSION_0:
   3337     if (! TMH_test_exchange_configured_for_currency (
   3338           oc->parse_order.order->details.v0.brutto.currency))
   3339     {
   3340       GNUNET_break_op (0);
   3341       reply_with_error (
   3342         oc,
   3343         MHD_HTTP_CONFLICT,
   3344         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_EXCHANGE_FOR_CURRENCY,
   3345         oc->parse_order.order->details.v0.brutto.currency);
   3346       return;
   3347     }
   3348     break;
   3349   case TALER_MERCHANT_CONTRACT_VERSION_1:
   3350     break;
   3351   default:
   3352     GNUNET_break_op (0);
   3353     reply_with_error (oc,
   3354                       MHD_HTTP_BAD_REQUEST,
   3355                       TALER_EC_GENERIC_VERSION_MALFORMED,
   3356                       "invalid version specified in order, supported are null, '0' or '1'");
   3357     return;
   3358   }
   3359 
   3360   /* Add order_id if it doesn't exist. */
   3361   if (NULL == oc->parse_order.order->order_id)
   3362   {
   3363     char buf[256];
   3364     time_t timer;
   3365     struct tm *tm_info;
   3366     size_t off;
   3367     uint64_t rand;
   3368     char *last;
   3369 
   3370     time (&timer);
   3371     tm_info = localtime (&timer);
   3372     if (NULL == tm_info)
   3373     {
   3374       reply_with_error (
   3375         oc,
   3376         MHD_HTTP_INTERNAL_SERVER_ERROR,
   3377         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_NO_LOCALTIME,
   3378         NULL);
   3379       return;
   3380     }
   3381     off = strftime (buf,
   3382                     sizeof (buf) - 1,
   3383                     "%Y.%j",
   3384                     tm_info);
   3385     /* Check for error state of strftime */
   3386     GNUNET_assert (0 != off);
   3387     buf[off++] = '-';
   3388     /* The encoded suffix is raw identifier entropy, not a bounded number. */
   3389     GNUNET_CRYPTO_random_block (&rand,
   3390                                 sizeof (rand));
   3391     last = GNUNET_STRINGS_data_to_string (&rand,
   3392                                           sizeof (uint64_t),
   3393                                           &buf[off],
   3394                                           sizeof (buf) - off);
   3395     GNUNET_assert (NULL != last);
   3396     *last = '\0';
   3397 
   3398     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3399                 "Assigning order ID `%s' server-side\n",
   3400                 buf);
   3401     oc->parse_order.order->order_id = GNUNET_strdup (buf);
   3402   }
   3403 
   3404   /* Patch fulfillment URL with order_id (implements #6467). */
   3405   if (NULL != oc->parse_order.order->base->fulfillment_url)
   3406   {
   3407     const char *pos;
   3408 
   3409     pos = strstr (oc->parse_order.order->base->fulfillment_url,
   3410                   "${ORDER_ID}");
   3411     if (NULL != pos)
   3412     {
   3413       /* replace ${ORDER_ID} with the real order_id */
   3414       char *nurl;
   3415 
   3416       /* We only allow one placeholder */
   3417       if (strstr (pos + strlen ("${ORDER_ID}"),
   3418                   "${ORDER_ID}"))
   3419       {
   3420         GNUNET_break_op (0);
   3421         reply_with_error (oc,
   3422                           MHD_HTTP_BAD_REQUEST,
   3423                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3424                           "fulfillment_url");
   3425         return;
   3426       }
   3427 
   3428       GNUNET_asprintf (
   3429         &nurl,
   3430         "%.*s%s%s",
   3431         /* first output URL until ${ORDER_ID} */
   3432         (int) (pos - oc->parse_order.order->base->fulfillment_url),
   3433         oc->parse_order.order->base->fulfillment_url,
   3434         /* replace ${ORDER_ID} with the right order_id */
   3435         oc->parse_order.order->order_id,
   3436         /* append rest of original URL */
   3437         pos + strlen ("${ORDER_ID}"));
   3438       oc->parse_order.order->base->fulfillment_url = GNUNET_strdup (nurl);
   3439       GNUNET_free (nurl);
   3440     }
   3441   }
   3442 
   3443   if ( (GNUNET_TIME_absolute_is_zero (
   3444           oc->parse_order.order->pay_deadline.abs_time)) ||
   3445        (GNUNET_TIME_absolute_is_never (
   3446           oc->parse_order.order->pay_deadline.abs_time)) )
   3447   {
   3448     oc->parse_order.order->pay_deadline
   3449       = GNUNET_TIME_relative_to_timestamp (
   3450           settings->default_pay_delay);
   3451     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3452                 "Pay deadline was zero (or never), setting to %s\n",
   3453                 GNUNET_TIME_timestamp2s (
   3454                   oc->parse_order.order->pay_deadline));
   3455   }
   3456   else if (GNUNET_TIME_absolute_is_past (
   3457              oc->parse_order.order->pay_deadline.abs_time))
   3458   {
   3459     GNUNET_break_op (0);
   3460     reply_with_error (
   3461       oc,
   3462       MHD_HTTP_BAD_REQUEST,
   3463       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_PAY_DEADLINE_IN_PAST,
   3464       NULL);
   3465     return;
   3466   }
   3467   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3468               "Pay deadline is %s\n",
   3469               GNUNET_TIME_timestamp2s (
   3470                 oc->parse_order.order->pay_deadline));
   3471 
   3472   /* Check soundness of refund deadline, and that a timestamp
   3473    * is actually present.  */
   3474   {
   3475     struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get ();
   3476 
   3477     /* Add timestamp if it doesn't exist (or is zero) */
   3478     if (GNUNET_TIME_absolute_is_zero (
   3479           oc->parse_order.order->timestamp.abs_time))
   3480     {
   3481       oc->parse_order.order->timestamp = now;
   3482     }
   3483 
   3484     /* If no refund_deadline given, set one based on refund_delay.  */
   3485     if (GNUNET_TIME_absolute_is_never (
   3486           oc->parse_order.order->refund_deadline.abs_time))
   3487     {
   3488       if (GNUNET_TIME_relative_is_zero (
   3489             oc->parse_request.refund_delay))
   3490       {
   3491         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3492                     "Refund delay is zero, no refunds are possible for this order\n");
   3493         oc->parse_order.order->refund_deadline = GNUNET_TIME_UNIT_ZERO_TS;
   3494       }
   3495       else
   3496       {
   3497         computed_refund_deadline = true;
   3498         oc->parse_order.order->refund_deadline
   3499           = GNUNET_TIME_absolute_to_timestamp (
   3500               GNUNET_TIME_absolute_add (
   3501                 oc->parse_order.order->pay_deadline.abs_time,
   3502                 oc->parse_request.refund_delay));
   3503       }
   3504     }
   3505 
   3506     if ( (! GNUNET_TIME_absolute_is_zero (
   3507             oc->parse_order.order->base->delivery_date.abs_time)) &&
   3508          (GNUNET_TIME_absolute_is_past (
   3509             oc->parse_order.order->base->delivery_date.abs_time)) )
   3510     {
   3511       GNUNET_break_op (0);
   3512       reply_with_error (
   3513         oc,
   3514         MHD_HTTP_BAD_REQUEST,
   3515         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_DELIVERY_DATE_IN_PAST,
   3516         NULL);
   3517       return;
   3518     }
   3519   }
   3520 
   3521   if ( (! GNUNET_TIME_absolute_is_zero (
   3522           oc->parse_order.order->refund_deadline.abs_time)) &&
   3523        (GNUNET_TIME_absolute_is_past (
   3524           oc->parse_order.order->refund_deadline.abs_time)) )
   3525   {
   3526     GNUNET_break_op (0);
   3527     reply_with_error (
   3528       oc,
   3529       MHD_HTTP_BAD_REQUEST,
   3530       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_DEADLINE_IN_PAST,
   3531       NULL);
   3532     return;
   3533   }
   3534 
   3535   if (GNUNET_TIME_absolute_is_never (
   3536         oc->parse_order.order->wire_transfer_deadline.abs_time))
   3537   {
   3538     struct GNUNET_TIME_Absolute start;
   3539 
   3540     start = GNUNET_TIME_absolute_max (
   3541       oc->parse_order.order->refund_deadline.abs_time,
   3542       oc->parse_order.order->pay_deadline.abs_time);
   3543     oc->parse_order.order->wire_transfer_deadline
   3544       = GNUNET_TIME_absolute_to_timestamp (
   3545           GNUNET_TIME_round_up (
   3546             GNUNET_TIME_absolute_add (
   3547               start,
   3548               settings->default_wire_transfer_delay),
   3549             settings->default_wire_transfer_rounding_interval));
   3550     if (GNUNET_TIME_absolute_is_never (
   3551           oc->parse_order.order->wire_transfer_deadline.abs_time))
   3552     {
   3553       GNUNET_break_op (0);
   3554       reply_with_error (
   3555         oc,
   3556         MHD_HTTP_BAD_REQUEST,
   3557         TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_WIRE_DEADLINE_IS_NEVER,
   3558         "order:wire_transfer_deadline");
   3559       return;
   3560     }
   3561   }
   3562   else if (computed_refund_deadline)
   3563   {
   3564     /* if we computed the refund_deadline from default settings
   3565        and did have a configured wire_deadline, make sure that
   3566        the refund_deadline is at or below the wire_deadline. */
   3567     oc->parse_order.order->refund_deadline
   3568       = GNUNET_TIME_timestamp_min (
   3569           oc->parse_order.order->refund_deadline,
   3570           oc->parse_order.order->wire_transfer_deadline);
   3571   }
   3572   if (GNUNET_TIME_timestamp_cmp (
   3573         oc->parse_order.order->wire_transfer_deadline,
   3574         <,
   3575         oc->parse_order.order->refund_deadline))
   3576   {
   3577     GNUNET_break_op (0);
   3578     reply_with_error (
   3579       oc,
   3580       MHD_HTTP_BAD_REQUEST,
   3581       TALER_EC_MERCHANT_PRIVATE_POST_ORDERS_REFUND_AFTER_WIRE_DEADLINE,
   3582       "order:wire_transfer_deadline;order:refund_deadline");
   3583     return;
   3584   }
   3585 
   3586   {
   3587     char *url;
   3588 
   3589     url = make_merchant_base_url (oc->connection,
   3590                                   settings->id);
   3591     if (NULL == url)
   3592     {
   3593       GNUNET_break_op (0);
   3594       reply_with_error (
   3595         oc,
   3596         MHD_HTTP_BAD_REQUEST,
   3597         TALER_EC_GENERIC_PARAMETER_MISSING,
   3598         "order:merchant_base_url");
   3599       return;
   3600     }
   3601     oc->parse_order.merchant_base_url = url;
   3602   }
   3603 
   3604   // FIXME: move to util during parsing!
   3605   if ( (NULL != oc->parse_order.order->base->delivery_location) &&
   3606        (! TMH_location_object_valid (oc->parse_order.order->base->delivery_location)) )
   3607   {
   3608     GNUNET_break_op (0);
   3609     reply_with_error (oc,
   3610                       MHD_HTTP_BAD_REQUEST,
   3611                       TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3612                       "delivery_location");
   3613     return;
   3614   }
   3615 
   3616   oc->phase++;
   3617 }
   3618 
   3619 
   3620 /* ***************** ORDER_PHASE_PARSE_REQUEST **************** */
   3621 
   3622 /**
   3623  * Parse the client request. Upon success,
   3624  * continue processing by calling parse_order().
   3625  *
   3626  * @param[in,out] oc order context to process
   3627  */
   3628 static void
   3629 phase_parse_request (struct OrderContext *oc)
   3630 {
   3631   const json_t *ip = NULL;
   3632   const json_t *uuid = NULL;
   3633   const char *otp_id = NULL;
   3634   bool create_token = true; /* default */
   3635   bool no_challenge = true;
   3636   struct GNUNET_JSON_Specification spec[] = {
   3637     GNUNET_JSON_spec_json ("order",
   3638                            &oc->parse_request.order),
   3639     GNUNET_JSON_spec_mark_optional (
   3640       GNUNET_JSON_spec_relative_time ("refund_delay",
   3641                                       &oc->parse_request.refund_delay),
   3642       NULL),
   3643     GNUNET_JSON_spec_mark_optional (
   3644       GNUNET_JSON_spec_string ("payment_target",
   3645                                &oc->parse_request.payment_target),
   3646       NULL),
   3647     GNUNET_JSON_spec_mark_optional (
   3648       GNUNET_JSON_spec_array_const ("inventory_products",
   3649                                     &ip),
   3650       NULL),
   3651     GNUNET_JSON_spec_mark_optional (
   3652       TALER_JSON_spec_session_id ("session_id",
   3653                                   &oc->parse_request.session_id),
   3654       NULL),
   3655     GNUNET_JSON_spec_mark_optional (
   3656       GNUNET_JSON_spec_array_const ("lock_uuids",
   3657                                     &uuid),
   3658       NULL),
   3659     GNUNET_JSON_spec_mark_optional (
   3660       GNUNET_JSON_spec_bool ("create_token",
   3661                              &create_token),
   3662       NULL),
   3663     GNUNET_JSON_spec_mark_optional (
   3664       TALER_JSON_spec_slug ("otp_id",
   3665                             &otp_id),
   3666       NULL),
   3667     GNUNET_JSON_spec_mark_optional (
   3668       GNUNET_JSON_spec_fixed_auto ("challenge",
   3669                                    &oc->parse_request.pos_challenge),
   3670       &no_challenge),
   3671     GNUNET_JSON_spec_end ()
   3672   };
   3673   enum GNUNET_GenericReturnValue ret;
   3674 
   3675   oc->parse_request.refund_delay
   3676     = oc->hc->instance->settings.default_refund_delay;
   3677   ret = TALER_MHD_parse_json_data (oc->connection,
   3678                                    oc->hc->request_body,
   3679                                    spec);
   3680   if (GNUNET_OK != ret)
   3681   {
   3682     GNUNET_break_op (0);
   3683     finalize_order2 (oc,
   3684                      ret);
   3685     return;
   3686   }
   3687   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   3688               "Refund delay is %s\n",
   3689               GNUNET_TIME_relative2s (oc->parse_request.refund_delay,
   3690                                       false));
   3691   TALER_MERCHANTDB_do_expire_locks (TMH_db);
   3692   if (NULL != otp_id)
   3693   {
   3694     struct TALER_MERCHANTDB_OtpDeviceDetails td;
   3695     enum GNUNET_DB_QueryStatus qs;
   3696 
   3697     memset (&td,
   3698             0,
   3699             sizeof (td));
   3700     qs = TALER_MERCHANTDB_get_otp_device (TMH_db,
   3701                                           oc->hc->instance->settings.id,
   3702                                           otp_id,
   3703                                           &td);
   3704     switch (qs)
   3705     {
   3706     case GNUNET_DB_STATUS_HARD_ERROR:
   3707       GNUNET_break (0);
   3708       reply_with_error (oc,
   3709                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   3710                         TALER_EC_GENERIC_DB_FETCH_FAILED,
   3711                         "get_otp_device");
   3712       return;
   3713     case GNUNET_DB_STATUS_SOFT_ERROR:
   3714       GNUNET_break (0);
   3715       reply_with_error (oc,
   3716                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   3717                         TALER_EC_GENERIC_DB_SOFT_FAILURE,
   3718                         "get_otp_device");
   3719       return;
   3720     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   3721       reply_with_error (oc,
   3722                         MHD_HTTP_NOT_FOUND,
   3723                         TALER_EC_MERCHANT_GENERIC_OTP_DEVICE_UNKNOWN,
   3724                         otp_id);
   3725       return;
   3726     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   3727       break;
   3728     }
   3729     oc->parse_request.pos_key = td.otp_key;
   3730     oc->parse_request.pos_algorithm = td.otp_algorithm;
   3731     GNUNET_free (td.otp_description);
   3732     GNUNET_free (td.otp_device_pub);
   3733   }
   3734   /* pos_algorithm is TALER_MCA_NONE when the order references no OTP
   3735      device, so this also rejects a challenge sent on its own */
   3736   {
   3737     switch (oc->parse_request.pos_algorithm)
   3738     {
   3739     case TALER_MCA_ECDSA_CHALLENGE:
   3740     case TALER_MCA_EDDSA_CHALLENGE:
   3741       /* the confirmation is a signature over the challenge, so
   3742          without one there would be nothing to sign at payment time */
   3743       if (no_challenge)
   3744       {
   3745         GNUNET_break_op (0);
   3746         reply_with_error (oc,
   3747                           MHD_HTTP_BAD_REQUEST,
   3748                           TALER_EC_GENERIC_PARAMETER_MISSING,
   3749                           "challenge");
   3750         return;
   3751       }
   3752       break;
   3753     case TALER_MCA_NONE:
   3754     case TALER_MCA_WITHOUT_PRICE:
   3755     case TALER_MCA_WITH_PRICE:
   3756       /* these are time-based; a challenge would never be looked at */
   3757       if (! no_challenge)
   3758       {
   3759         GNUNET_break_op (0);
   3760         reply_with_error (oc,
   3761                           MHD_HTTP_BAD_REQUEST,
   3762                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3763                           "challenge");
   3764         return;
   3765       }
   3766       break;
   3767     }
   3768   }
   3769   if (create_token)
   3770   {
   3771     GNUNET_CRYPTO_random_block (&oc->parse_request.claim_token,
   3772                                 sizeof (oc->parse_request.claim_token));
   3773   }
   3774   /* Compute h_post_data (for idempotency check) */
   3775   {
   3776     char *req_body_enc;
   3777 
   3778     /* Dump normalized JSON to string. */
   3779     if (NULL == (req_body_enc
   3780                    = json_dumps (oc->hc->request_body,
   3781                                  JSON_ENCODE_ANY
   3782                                  | JSON_COMPACT
   3783                                  | JSON_SORT_KEYS)))
   3784     {
   3785       GNUNET_break (0);
   3786       GNUNET_JSON_parse_free (spec);
   3787       reply_with_error (oc,
   3788                         MHD_HTTP_INTERNAL_SERVER_ERROR,
   3789                         TALER_EC_GENERIC_ALLOCATION_FAILURE,
   3790                         "request body normalization for hashing");
   3791       return;
   3792     }
   3793     GNUNET_CRYPTO_hash (req_body_enc,
   3794                         strlen (req_body_enc),
   3795                         &oc->parse_request.h_post_data.hash);
   3796     GNUNET_free (req_body_enc);
   3797   }
   3798 
   3799   /* parse the inventory_products (optionally given) */
   3800   if (NULL != ip)
   3801   {
   3802     unsigned int ipl = (unsigned int) json_array_size (ip);
   3803 
   3804     if ( (json_array_size (ip) != (size_t) ipl) ||
   3805          (ipl > MAX_PRODUCTS) )
   3806     {
   3807       GNUNET_break_op (0);
   3808       GNUNET_JSON_parse_free (spec);
   3809       reply_with_error (oc,
   3810                         MHD_HTTP_BAD_REQUEST,
   3811                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3812                         "inventory_products (too many)");
   3813       return;
   3814     }
   3815     GNUNET_array_grow (oc->parse_request.inventory_products,
   3816                        oc->parse_request.inventory_products_length,
   3817                        (unsigned int) json_array_size (ip));
   3818     for (unsigned int i = 0; i<oc->parse_request.inventory_products_length; i++)
   3819     {
   3820       struct InventoryProduct *ipr = &oc->parse_request.inventory_products[i];
   3821       const char *error_name;
   3822       unsigned int error_line;
   3823       struct GNUNET_JSON_Specification ispec[] = {
   3824         TALER_JSON_spec_slug ("product_id",
   3825                               &ipr->product_id),
   3826         GNUNET_JSON_spec_mark_optional (
   3827           GNUNET_JSON_spec_uint64 ("quantity",
   3828                                    &ipr->quantity),
   3829           &ipr->quantity_missing),
   3830         GNUNET_JSON_spec_mark_optional (
   3831           GNUNET_JSON_spec_string ("unit_quantity",
   3832                                    &ipr->unit_quantity),
   3833           &ipr->unit_quantity_missing),
   3834         GNUNET_JSON_spec_mark_optional (
   3835           GNUNET_JSON_spec_uint64 ("product_money_pot",
   3836                                    &ipr->product_money_pot),
   3837           NULL),
   3838         GNUNET_JSON_spec_end ()
   3839       };
   3840 
   3841       ret = GNUNET_JSON_parse (json_array_get (ip,
   3842                                                i),
   3843                                ispec,
   3844                                &error_name,
   3845                                &error_line);
   3846       if (GNUNET_OK != ret)
   3847       {
   3848         GNUNET_break_op (0);
   3849         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3850                     "Product parsing failed at #%u: %s:%u\n",
   3851                     i,
   3852                     error_name,
   3853                     error_line);
   3854         reply_with_error (oc,
   3855                           MHD_HTTP_BAD_REQUEST,
   3856                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3857                           "inventory_products");
   3858         return;
   3859       }
   3860       if (ipr->quantity_missing && ipr->unit_quantity_missing)
   3861       {
   3862         ipr->quantity = 1;
   3863         ipr->quantity_missing = false;
   3864       }
   3865     }
   3866   }
   3867 
   3868   /* parse the lock_uuids (optionally given) */
   3869   if (NULL != uuid)
   3870   {
   3871     GNUNET_array_grow (oc->parse_request.uuids,
   3872                        oc->parse_request.uuids_length,
   3873                        json_array_size (uuid));
   3874     for (unsigned int i = 0; i<oc->parse_request.uuids_length; i++)
   3875     {
   3876       json_t *ui = json_array_get (uuid,
   3877                                    i);
   3878 
   3879       if (! json_is_string (ui))
   3880       {
   3881         GNUNET_break_op (0);
   3882         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   3883                     "UUID parsing failed at #%u\n",
   3884                     i);
   3885         reply_with_error (oc,
   3886                           MHD_HTTP_BAD_REQUEST,
   3887                           TALER_EC_GENERIC_PARAMETER_MALFORMED,
   3888                           "lock_uuids");
   3889         return;
   3890       }
   3891       TMH_uuid_from_string (json_string_value (ui),
   3892                             &oc->parse_request.uuids[i]);
   3893     }
   3894   }
   3895   oc->phase++;
   3896 }
   3897 
   3898 
   3899 /* ***************** Main handler **************** */
   3900 
   3901 
   3902 enum MHD_Result
   3903 TMH_private_post_orders (
   3904   const struct TMH_RequestHandler *rh,
   3905   struct MHD_Connection *connection,
   3906   struct TMH_HandlerContext *hc)
   3907 {
   3908   struct OrderContext *oc = hc->ctx;
   3909 
   3910   if (NULL == oc)
   3911   {
   3912     oc = GNUNET_new (struct OrderContext);
   3913     hc->ctx = oc;
   3914     hc->cc = &clean_order;
   3915     oc->connection = connection;
   3916     oc->hc = hc;
   3917   }
   3918   while (1)
   3919   {
   3920     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3921                 "Processing order in phase %d\n",
   3922                 oc->phase);
   3923     switch (oc->phase)
   3924     {
   3925     case ORDER_PHASE_PARSE_REQUEST:
   3926       phase_parse_request (oc);
   3927       break;
   3928     case ORDER_PHASE_PARSE_ORDER:
   3929       phase_parse_order (oc);
   3930       break;
   3931     case ORDER_PHASE_PARSE_CHOICES:
   3932       phase_parse_choices (oc);
   3933       break;
   3934     case ORDER_PHASE_MERGE_INVENTORY:
   3935       phase_merge_inventory (oc);
   3936       break;
   3937     case ORDER_PHASE_ADD_PAYMENT_DETAILS:
   3938       phase_add_payment_details (oc);
   3939       break;
   3940     case ORDER_PHASE_SET_EXCHANGES:
   3941       if (phase_set_exchanges (oc))
   3942         return MHD_YES;
   3943       break;
   3944     case ORDER_PHASE_SELECT_WIRE_METHOD:
   3945       phase_select_wire_method (oc);
   3946       break;
   3947     case ORDER_PHASE_SET_MAX_FEE:
   3948       phase_set_max_fee (oc);
   3949       break;
   3950     case ORDER_PHASE_SERIALIZE_ORDER:
   3951       phase_serialize_order (oc);
   3952       break;
   3953     case ORDER_PHASE_CHECK_CONTRACT:
   3954       phase_check_contract (oc);
   3955       break;
   3956     case ORDER_PHASE_SALT_FORGETTABLE:
   3957       phase_salt_forgettable (oc);
   3958       break;
   3959     case ORDER_PHASE_EXECUTE_ORDER:
   3960       phase_execute_order (oc);
   3961       break;
   3962     case ORDER_PHASE_FINISHED_MHD_YES:
   3963       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3964                   "Finished processing order (1)\n");
   3965       return MHD_YES;
   3966     case ORDER_PHASE_FINISHED_MHD_NO:
   3967       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   3968                   "Finished processing order (0)\n");
   3969       return MHD_NO;
   3970     }
   3971   }
   3972 }
   3973 
   3974 
   3975 /* end of taler-merchant-httpd_post-private-orders.c */