merchant

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

taler-merchant-httpd_private-post-orders.c (139427B)


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