merchant

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

taler-merchant-httpd_get-private-orders-ORDER_ID.c (65987B)


      1 /*
      2   This file is part of TALER
      3   (C) 2017-2024, 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file src/backend/taler-merchant-httpd_get-private-orders-ORDER_ID.c
     18  * @brief implementation of GET /private/orders/ID handler
     19  * @author Florian Dold
     20  * @author Christian Grothoff
     21  * @author Bohdan Potuzhnyi
     22  * @author Iván Ávalos
     23  */
     24 #include "platform.h"
     25 #include <taler/taler_json_lib.h>
     26 #include <taler/taler_dbevents.h>
     27 #include <taler/taler_error_codes.h>
     28 #include <taler/taler_util.h>
     29 #include <gnunet/gnunet_common.h>
     30 #include <gnunet/gnunet_json_lib.h>
     31 #include "taler/taler_merchant_util.h"
     32 #include "taler-merchant-httpd_helper.h"
     33 #include "taler-merchant-httpd_get-private-orders.h"
     34 #include "taler-merchant-httpd_get-private-orders-ORDER_ID.h"
     35 #include "merchant-database/get_contract_terms_status.h"
     36 #include "merchant-database/iterate_deposits_by_order.h"
     37 #include "merchant-database/get_order.h"
     38 #include "merchant-database/get_order_by_fulfillment.h"
     39 #include "merchant-database/iterate_refunds_detailed.h"
     40 #include "merchant-database/iterate_external_refunds.h"
     41 #include "merchant-database/iterate_transfer_details_by_order.h"
     42 #include "merchant-database/update_to_contract_terms_wired.h"
     43 #include "merchant-database/preflight.h"
     44 #include "merchant-database/event_listen.h"
     45 
     46 /**
     47  * Data structure we keep for a check payment request.
     48  */
     49 struct GetOrderRequestContext;
     50 
     51 
     52 /**
     53  * Request to an exchange for details about wire transfers
     54  * in response to a coin's deposit operation.
     55  */
     56 struct TransferQuery
     57 {
     58 
     59   /**
     60    * Kept in a DLL.
     61    */
     62   struct TransferQuery *next;
     63 
     64   /**
     65    * Kept in a DLL.
     66    */
     67   struct TransferQuery *prev;
     68 
     69   /**
     70    * Base URL of the exchange.
     71    */
     72   char *exchange_url;
     73 
     74   /**
     75    * Overall request this TQ belongs with.
     76    */
     77   struct GetOrderRequestContext *gorc;
     78 
     79   /**
     80    * Hash of the merchant's bank account the transfer (presumably) went to.
     81    */
     82   struct TALER_MerchantWireHashP h_wire;
     83 
     84   /**
     85    * Value deposited (including deposit fee).
     86    */
     87   struct TALER_Amount amount_with_fee;
     88 
     89   /**
     90    * Deposit fee paid for this coin.
     91    */
     92   struct TALER_Amount deposit_fee;
     93 
     94   /**
     95    * Total amount refunded so far for this coin in this order.  The
     96    * exchange only returns @e deposit_fee to us once this reaches
     97    * @e amount_with_fee.
     98    */
     99   struct TALER_Amount refunded_total;
    100 
    101   /**
    102    * Public key of the coin this is about.
    103    */
    104   struct TALER_CoinSpendPublicKeyP coin_pub;
    105 
    106   /**
    107    * Which deposit operation is this about?
    108    */
    109   uint64_t deposit_serial;
    110 
    111 };
    112 
    113 
    114 /**
    115  * Phases of order processing.
    116  */
    117 enum GetOrderPhase
    118 {
    119   /**
    120    * Initialization.
    121    */
    122   GOP_INIT = 0,
    123 
    124   /**
    125    * Obtain contract terms from database.
    126    */
    127   GOP_FETCH_CONTRACT = 1,
    128 
    129   /**
    130    * Parse the contract terms.
    131    */
    132   GOP_PARSE_CONTRACT = 2,
    133 
    134   /**
    135    * Check if the contract was fully paid.
    136    */
    137   GOP_CHECK_PAID = 3,
    138 
    139   /**
    140    * Check if the wallet may have purchased an equivalent
    141    * order before and we need to redirect the wallet to
    142    * an existing paid order.
    143    */
    144   GOP_CHECK_REPURCHASE = 4,
    145 
    146   /**
    147    * Terminate processing of unpaid orders, either by
    148    * suspending until payment or by returning the
    149    * unpaid order status.
    150    */
    151   GOP_UNPAID_FINISH = 5,
    152 
    153   /**
    154    * Load all deposits associated with the order.
    155    */
    156   GOP_CHECK_DEPOSITS = 6,
    157 
    158   /**
    159    * Check if the (paid) order was refunded.
    160    */
    161   GOP_CHECK_REFUNDS = 7,
    162 
    163   /**
    164    * Check local records for transfers of funds to
    165    * the merchant.
    166    */
    167   GOP_CHECK_LOCAL_TRANSFERS = 8,
    168 
    169   /**
    170    * Generate final comprehensive result.
    171    */
    172   GOP_REPLY_RESULT = 9,
    173 
    174   /**
    175    * End with the HTTP status and error code in
    176    * wire_hc and wire_ec.
    177    */
    178   GOP_ERROR = 10,
    179 
    180   /**
    181    * We are suspended awaiting payment.
    182    */
    183   GOP_SUSPENDED_ON_UNPAID = 11,
    184 
    185   /**
    186    * Processing is done, return #MHD_YES.
    187    */
    188   GOP_END_YES = 12,
    189 
    190   /**
    191    * Processing is done, return #MHD_NO.
    192    */
    193   GOP_END_NO = 13
    194 
    195 };
    196 
    197 
    198 /**
    199  * Data structure we keep for a check payment request.
    200  */
    201 struct GetOrderRequestContext
    202 {
    203 
    204   /**
    205    * Processing phase we are in.
    206    */
    207   enum GetOrderPhase phase;
    208 
    209   /**
    210    * Entry in the #resume_timeout_heap for this check payment, if we are
    211    * suspended.
    212    */
    213   struct TMH_SuspendedConnection sc;
    214 
    215   /**
    216    * Which merchant instance is this for?
    217    */
    218   struct TMH_HandlerContext *hc;
    219 
    220   /**
    221    * session of the client
    222    */
    223   const char *session_id;
    224 
    225   /**
    226    * Kept in a DLL while suspended on exchange.
    227    */
    228   struct GetOrderRequestContext *next;
    229 
    230   /**
    231    * Kept in a DLL while suspended on exchange.
    232    */
    233   struct GetOrderRequestContext *prev;
    234 
    235   /**
    236    * Head of DLL of individual queries for transfer data.
    237    */
    238   struct TransferQuery *tq_head;
    239 
    240   /**
    241    * Tail of DLL of individual queries for transfer data.
    242    */
    243   struct TransferQuery *tq_tail;
    244 
    245   /**
    246    * Timeout task while waiting on exchange.
    247    */
    248   struct GNUNET_SCHEDULER_Task *tt;
    249 
    250   /**
    251    * Database event we are waiting on to be resuming
    252    * for payment or refunds.
    253    */
    254   struct GNUNET_DB_EventHandler *eh;
    255 
    256   /**
    257    * Database event we are waiting on to be resuming
    258    * for session capture.
    259    */
    260   struct GNUNET_DB_EventHandler *session_eh;
    261 
    262   /**
    263    * Contract terms of the payment we are checking. NULL when they
    264    * are not (yet) known.
    265    */
    266   json_t *contract_terms_json;
    267 
    268   /**
    269    * Parsed contract terms, NULL when parsing failed
    270    */
    271   struct TALER_MERCHANT_Contract *contract_terms;
    272 
    273   /**
    274    * Proto-contract. Be careful: do NOT free this
    275    * if @e contract_terms is not NULL!
    276    */
    277   struct TALER_MERCHANT_ProtoContract *pc;
    278 
    279   /**
    280    * Order terms of the payment we are checking. NULL when we have
    281    * a contract.
    282    */
    283   json_t *order_json;
    284 
    285   /**
    286    * Parsed order details, NULL when parsing failed or we have a contract.
    287    */
    288   struct TALER_MERCHANT_Order *order;
    289 
    290   /**
    291    * Common terms of @e order and @e contract.
    292    */
    293   const struct TALER_MERCHANT_ContractBaseTerms *ct;
    294 
    295   /**
    296    * Timestamp of the contract or order.
    297    */
    298   struct GNUNET_TIME_Timestamp timestamp;
    299 
    300   /**
    301    * Claim token of the order.
    302    */
    303   struct TALER_ClaimTokenP claim_token;
    304 
    305   /**
    306    * Timestamp of the last payment.
    307    */
    308   struct GNUNET_TIME_Timestamp last_payment;
    309 
    310   /**
    311    * Wire details for the payment, to be returned in the reply. NULL
    312    * if not available.
    313    */
    314   json_t *wire_details;
    315 
    316   /**
    317    * Details about refunds, NULL if there are no refunds.
    318    */
    319   json_t *refund_details;
    320 
    321   /**
    322    * Details about external refunds, empty array if there are none.
    323    */
    324   json_t *refunds_external;
    325 
    326   /**
    327    * Amount of the order, unset for unpaid v1 orders.
    328    */
    329   struct TALER_Amount contract_amount;
    330 
    331   /**
    332    * Maximum fee the merchant is willing to pay for this order/choice.
    333    * Only valid if @e has_max_fee is true.
    334    */
    335   struct TALER_Amount max_fee;
    336 
    337   /**
    338    * True if @e max_fee was provided by the contract.
    339    */
    340   bool has_max_fee;
    341 
    342   /**
    343    * Hash over the @e contract_terms.
    344    */
    345   struct TALER_PrivateContractHashP h_contract_terms;
    346 
    347   /**
    348    * Set to the Etag of a response already known to the
    349    * client. We should only return from long-polling
    350    * on timeout (with "Not Modified") or when the Etag
    351    * of the response differs from what is given here.
    352    * Only set if @a have_lp_not_etag is true.
    353    * Set from "lp_etag" query parameter.
    354    */
    355   struct GNUNET_ShortHashCode lp_not_etag;
    356 
    357   /**
    358    * Total amount the exchange deposited into our bank account
    359    * (confirmed or unconfirmed), excluding fees.
    360    */
    361   struct TALER_Amount deposits_total;
    362 
    363   /**
    364    * Total amount in deposit fees we paid for all coins.
    365    */
    366   struct TALER_Amount deposit_fees_total;
    367 
    368   /**
    369    * Total amount in deposit fees cancelled due to refunds for all coins.
    370    */
    371   struct TALER_Amount deposit_fees_refunded_total;
    372 
    373   /**
    374    * Total value of the coins that the exchange deposited into our bank
    375    * account (confirmed or unconfirmed), including deposit fees.
    376    */
    377   struct TALER_Amount value_total;
    378 
    379   /**
    380    * Serial ID of the order.
    381    */
    382   uint64_t order_serial;
    383 
    384   /**
    385    * Index of selected choice from ``choices`` array in the contract_terms.
    386    * Is -1 for orders without choices.
    387    */
    388   int16_t choice_index;
    389 
    390   /**
    391    * Total refunds granted for this payment. Only initialized
    392    * if @e refunded is set to true.
    393    */
    394   struct TALER_Amount refund_amount;
    395 
    396   /**
    397    * Exchange HTTP error code encountered while trying to determine wire transfer
    398    * details. #TALER_EC_NONE for no error encountered.
    399    */
    400   unsigned int exchange_hc;
    401 
    402   /**
    403    * Exchange error code encountered while trying to determine wire transfer
    404    * details. #TALER_EC_NONE for no error encountered.
    405    */
    406   enum TALER_ErrorCode exchange_ec;
    407 
    408   /**
    409    * Error code encountered while trying to determine wire transfer
    410    * details. #TALER_EC_NONE for no error encountered.
    411    */
    412   enum TALER_ErrorCode wire_ec;
    413 
    414   /**
    415    * Set to YES if refunded orders should be included when
    416    * doing repurchase detection.
    417    */
    418   enum TALER_EXCHANGE_YesNoAll allow_refunded_for_repurchase;
    419 
    420   /**
    421    * HTTP status to return with @e wire_ec, 0 if @e wire_ec is #TALER_EC_NONE.
    422    */
    423   unsigned int wire_hc;
    424 
    425   /**
    426    * Did we suspend @a connection and are thus in
    427    * the #gorc_head DLL (#GNUNET_YES). Set to
    428    * #GNUNET_NO if we are not suspended, and to
    429    * #GNUNET_SYSERR if we should close the connection
    430    * without a response due to shutdown.
    431    */
    432   enum GNUNET_GenericReturnValue suspended;
    433 
    434   /**
    435    * Set to true if this payment has been refunded and
    436    * @e refund_amount is initialized.
    437    */
    438   bool refunded;
    439 
    440   /**
    441    * True if @e lp_not_etag was given.
    442    */
    443   bool have_lp_not_etag;
    444 
    445   /**
    446    * True if the order was paid.
    447    */
    448   bool paid;
    449 
    450   /**
    451    * True if the paid session in the database matches
    452    * our @e session_id.
    453    */
    454   bool paid_session_matches;
    455 
    456   /**
    457    * When we install the @e session_eh listener, we already checked
    458    * the order status. We could not do it earlier, because the
    459    * fulfillment URL was unavailable. However, this leaves a chance
    460    * for a payment event to be missed if it happens before the first
    461    * order status check and us installing the event listener. Thus,
    462    * if we afterwards suspend, we should once *immediately* check the
    463    * order status a 2nd time before we really suspend. This flag is
    464    * set to true to handle this case.
    465    */
    466   bool instant_retry;
    467 
    468   /**
    469    * True if the exchange wired the money to the merchant.
    470    */
    471   bool wired;
    472 
    473   /**
    474    * True if the order remains unclaimed.
    475    */
    476   bool order_only;
    477 
    478   /**
    479    * Set to true if this payment has been refunded and
    480    * some refunds remain to be picked up by the wallet.
    481    */
    482   bool refund_pending;
    483 
    484   /**
    485    * Set to true if our database (incorrectly) has refunds
    486    * in a different currency than the currency of the
    487    * original payment for the order.
    488    */
    489   bool refund_currency_mismatch;
    490 
    491   /**
    492    * Set to true if our database (incorrectly) has deposits
    493    * in a different currency than the currency of the
    494    * original payment for the order.
    495    */
    496   bool deposit_currency_mismatch;
    497 };
    498 
    499 
    500 /**
    501  * Head of list of suspended requests waiting on the exchange.
    502  */
    503 static struct GetOrderRequestContext *gorc_head;
    504 
    505 /**
    506  * Tail of list of suspended requests waiting on the exchange.
    507  */
    508 static struct GetOrderRequestContext *gorc_tail;
    509 
    510 
    511 void
    512 TMH_force_gorc_resume (void)
    513 {
    514   struct GetOrderRequestContext *gorc;
    515 
    516   while (NULL != (gorc = gorc_head))
    517   {
    518     GNUNET_CONTAINER_DLL_remove (gorc_head,
    519                                  gorc_tail,
    520                                  gorc);
    521     GNUNET_assert (GNUNET_YES == gorc->suspended);
    522     gorc->suspended = GNUNET_SYSERR;
    523     MHD_resume_connection (gorc->sc.con);
    524   }
    525 }
    526 
    527 
    528 /**
    529  * Discard the list of deposits collected for @a gorc.
    530  *
    531  * @param[in,out] gorc order context to update
    532  */
    533 static void
    534 clear_transfer_queries (struct GetOrderRequestContext *gorc)
    535 {
    536   struct TransferQuery *tq;
    537 
    538   while (NULL != (tq = gorc->tq_head))
    539   {
    540     GNUNET_CONTAINER_DLL_remove (gorc->tq_head,
    541                                  gorc->tq_tail,
    542                                  tq);
    543     GNUNET_free (tq->exchange_url);
    544     GNUNET_free (tq);
    545   }
    546 }
    547 
    548 
    549 /**
    550  * We have received a trigger from the database
    551  * that we should (possibly) resume the request.
    552  *
    553  * @param cls a `struct GetOrderRequestContext` to resume
    554  * @param extra string encoding refund amount (or NULL)
    555  * @param extra_size number of bytes in @a extra
    556  */
    557 static void
    558 resume_by_event (void *cls,
    559                  const void *extra,
    560                  size_t extra_size)
    561 {
    562   struct GetOrderRequestContext *gorc = cls;
    563 
    564   (void) extra;
    565   (void) extra_size;
    566   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    567               "Resuming request for order %s by trigger\n",
    568               gorc->hc->infix);
    569   if (GNUNET_NO == gorc->suspended)
    570     return; /* duplicate event is possible */
    571   gorc->suspended = GNUNET_NO;
    572   gorc->phase = GOP_FETCH_CONTRACT;
    573   GNUNET_CONTAINER_DLL_remove (gorc_head,
    574                                gorc_tail,
    575                                gorc);
    576   MHD_resume_connection (gorc->sc.con);
    577   TALER_MHD_daemon_trigger ();   /* we resumed, kick MHD */
    578 }
    579 
    580 
    581 /**
    582  * Clean up the session state for a GET /private/order/ID request.
    583  *
    584  * @param cls closure, must be a `struct GetOrderRequestContext *`
    585  */
    586 static void
    587 gorc_cleanup (void *cls)
    588 {
    589   struct GetOrderRequestContext *gorc = cls;
    590 
    591   clear_transfer_queries (gorc);
    592   if (NULL != gorc->contract_terms_json)
    593   {
    594     json_decref (gorc->contract_terms_json);
    595     gorc->contract_terms_json = NULL;
    596   }
    597   if (NULL != gorc->order_json)
    598   {
    599     json_decref (gorc->order_json);
    600     gorc->order_json = NULL;
    601   }
    602   if (NULL != gorc->contract_terms)
    603   {
    604     TALER_MERCHANT_contract_free (gorc->contract_terms);
    605     gorc->contract_terms = NULL;
    606     gorc->pc = NULL; /* was an alias! */
    607   }
    608   if (NULL != gorc->pc)
    609   {
    610     TALER_MERCHANT_proto_contract_free (gorc->pc);
    611     gorc->pc = NULL;
    612   }
    613   if (NULL != gorc->order)
    614   {
    615     TALER_MERCHANT_order_free (gorc->order);
    616     gorc->order = NULL;
    617   }
    618   gorc->ct = NULL; /* avoid dangling pointer */
    619   if (NULL != gorc->wire_details)
    620     json_decref (gorc->wire_details);
    621   if (NULL != gorc->refund_details)
    622     json_decref (gorc->refund_details);
    623   if (NULL != gorc->refunds_external)
    624     json_decref (gorc->refunds_external);
    625   if (NULL != gorc->tt)
    626   {
    627     GNUNET_SCHEDULER_cancel (gorc->tt);
    628     gorc->tt = NULL;
    629   }
    630   if (NULL != gorc->eh)
    631   {
    632     TALER_MERCHANTDB_event_listen_cancel (gorc->eh);
    633     gorc->eh = NULL;
    634   }
    635   if (NULL != gorc->session_eh)
    636   {
    637     TALER_MERCHANTDB_event_listen_cancel (gorc->session_eh);
    638     gorc->session_eh = NULL;
    639   }
    640   GNUNET_free (gorc);
    641 }
    642 
    643 
    644 /**
    645  * Processing the request @a gorc is finished, set the
    646  * final return value in phase based on @a mret.
    647  *
    648  * @param[in,out] gorc order context to initialize
    649  * @param mret MHD HTTP response status to return
    650  */
    651 static void
    652 phase_end (struct GetOrderRequestContext *gorc,
    653            enum MHD_Result mret)
    654 {
    655   gorc->phase = (MHD_YES == mret)
    656     ? GOP_END_YES
    657     : GOP_END_NO;
    658 }
    659 
    660 
    661 /**
    662  * Initialize event callbacks for the order processing.
    663  *
    664  * @param[in,out] gorc order context to initialize
    665  */
    666 static void
    667 phase_init (struct GetOrderRequestContext *gorc)
    668 {
    669   struct TMH_HandlerContext *hc = gorc->hc;
    670   struct TMH_OrderPayEventP pay_eh = {
    671     .header.size = htons (sizeof (pay_eh)),
    672     .header.type = htons (TALER_DBEVENT_MERCHANT_ORDER_STATUS_CHANGED),
    673     .merchant_pub = hc->instance->merchant_pub
    674   };
    675 
    676   if (! GNUNET_TIME_absolute_is_future (gorc->sc.long_poll_timeout))
    677   {
    678     gorc->phase++;
    679     return;
    680   }
    681 
    682   GNUNET_CRYPTO_hash (hc->infix,
    683                       strlen (hc->infix),
    684                       &pay_eh.h_order_id);
    685   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    686               "Subscribing to payment triggers for %p\n",
    687               gorc);
    688   gorc->eh = TALER_MERCHANTDB_event_listen (
    689     TMH_db,
    690     &pay_eh.header,
    691     GNUNET_TIME_absolute_get_remaining (gorc->sc.long_poll_timeout),
    692     &resume_by_event,
    693     gorc);
    694   gorc->phase++;
    695 }
    696 
    697 
    698 /**
    699  * Obtain latest contract terms from the database.
    700  *
    701  * @param[in,out] gorc order context to update
    702  */
    703 static void
    704 phase_fetch_contract (struct GetOrderRequestContext *gorc)
    705 {
    706   struct TMH_HandlerContext *hc = gorc->hc;
    707   enum GNUNET_DB_QueryStatus qs;
    708 
    709   if (NULL != gorc->contract_terms_json)
    710   {
    711     /* Free memory filled with old contract terms before fetching the latest
    712        ones from the DB.  Note that we cannot simply skip the database
    713        interaction as the contract terms loaded previously might be from an
    714        earlier *unclaimed* order state (which we loaded in a previous
    715        invocation of this function and we are back here due to long polling)
    716        and thus the contract terms could have changed during claiming. Thus,
    717        we need to fetch the latest contract terms from the DB again. */
    718     json_decref (gorc->contract_terms_json);
    719     gorc->contract_terms_json = NULL;
    720     gorc->order_only = false;
    721   }
    722   TALER_MERCHANTDB_preflight (TMH_db);
    723   qs = TALER_MERCHANTDB_get_contract_terms_status (TMH_db,
    724                                                    hc->instance->settings.id,
    725                                                    hc->infix,
    726                                                    gorc->session_id,
    727                                                    &gorc->contract_terms_json,
    728                                                    &gorc->order_serial,
    729                                                    &gorc->paid,
    730                                                    &gorc->wired,
    731                                                    &gorc->paid_session_matches,
    732                                                    &gorc->claim_token,
    733                                                    &gorc->choice_index);
    734   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    735               "get_contract_terms (%s) returned %d\n",
    736               hc->infix,
    737               (int) qs);
    738   if (0 > qs)
    739   {
    740     /* single, read-only SQL statements should never cause
    741        serialization problems */
    742     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    743     /* Always report on hard error as well to enable diagnostics */
    744     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    745     phase_end (gorc,
    746                TALER_MHD_reply_with_error (gorc->sc.con,
    747                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    748                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    749                                            "contract terms"));
    750     return;
    751   }
    752   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    753   {
    754     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    755                 "Order %s is %s (%s) according to database, choice %d\n",
    756                 hc->infix,
    757                 gorc->paid ? "paid" : "unpaid",
    758                 gorc->wired ? "wired" : "unwired",
    759                 (int) gorc->choice_index);
    760     gorc->phase++;
    761     return;
    762   }
    763   GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
    764   GNUNET_assert (! gorc->paid);
    765   /* No contract, only order, fetch from orders table */
    766   gorc->order_only = true;
    767   {
    768     struct TALER_MerchantPostDataHashP unused;
    769 
    770     /* We need the order for two cases:  Either when the contract doesn't exist yet,
    771      * or when the order is claimed but unpaid, and we need the claim token. */
    772     qs = TALER_MERCHANTDB_get_order (TMH_db,
    773                                      hc->instance->settings.id,
    774                                      hc->infix,
    775                                      &gorc->claim_token,
    776                                      &unused,
    777                                      &gorc->contract_terms_json);
    778   }
    779   if (0 > qs)
    780   {
    781     /* single, read-only SQL statements should never cause
    782        serialization problems */
    783     GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs);
    784     /* Always report on hard error as well to enable diagnostics */
    785     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
    786     phase_end (gorc,
    787                TALER_MHD_reply_with_error (gorc->sc.con,
    788                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    789                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
    790                                            "order"));
    791     return;
    792   }
    793   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    794   {
    795     phase_end (gorc,
    796                TALER_MHD_reply_with_error (gorc->sc.con,
    797                                            MHD_HTTP_NOT_FOUND,
    798                                            TALER_EC_MERCHANT_GENERIC_ORDER_UNKNOWN,
    799                                            hc->infix));
    800     return;
    801   }
    802   gorc->phase++;
    803 }
    804 
    805 
    806 /**
    807  * Obtain parse contract terms of the order.  Extracts the fulfillment URL,
    808  * total amount, summary and timestamp from the contract terms!
    809  *
    810  * @param[in,out] gorc order context to update
    811  */
    812 static void
    813 phase_parse_contract (struct GetOrderRequestContext *gorc)
    814 {
    815   struct TMH_HandlerContext *hc = gorc->hc;
    816 
    817   if ( (NULL == gorc->order) &&
    818        (NULL != gorc->order_json) )
    819   {
    820     gorc->order = TALER_MERCHANT_order_parse (
    821       gorc->order_json);
    822 
    823     if (NULL == gorc->order)
    824     {
    825       GNUNET_break (0);
    826       phase_end (gorc,
    827                  TALER_MHD_reply_with_error (
    828                    gorc->sc.con,
    829                    MHD_HTTP_INTERNAL_SERVER_ERROR,
    830                    TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
    831                    hc->infix));
    832       return;
    833     }
    834     gorc->ct = gorc->order->base;
    835     gorc->timestamp = gorc->order->timestamp;
    836   }
    837   if ( (NULL == gorc->contract_terms) &&
    838        (NULL != gorc->contract_terms_json) )
    839   {
    840     if (NULL ==
    841         json_object_get (gorc->contract_terms_json,
    842                          "nonce"))
    843     {
    844       /* only have a proto contract */
    845       gorc->pc = TALER_MERCHANT_proto_contract_parse (
    846         gorc->contract_terms_json);
    847 
    848       if (NULL == gorc->pc)
    849       {
    850         GNUNET_break (0);
    851         phase_end (gorc,
    852                    TALER_MHD_reply_with_error (
    853                      gorc->sc.con,
    854                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    855                      TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
    856                      hc->infix));
    857         return;
    858       }
    859       gorc->ct = gorc->pc->base;
    860       gorc->timestamp = gorc->pc->timestamp;
    861     }
    862     else
    863     {
    864       gorc->contract_terms = TALER_MERCHANT_contract_parse (
    865         gorc->contract_terms_json);
    866       if (NULL == gorc->contract_terms)
    867       {
    868         GNUNET_break (0);
    869         phase_end (gorc,
    870                    TALER_MHD_reply_with_error (
    871                      gorc->sc.con,
    872                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    873                      TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
    874                      hc->infix));
    875         return;
    876       }
    877       gorc->pc = gorc->contract_terms->pc;
    878       gorc->ct = gorc->pc->base;
    879       gorc->timestamp = gorc->contract_terms->pc->timestamp;
    880     }
    881   }
    882 
    883   /* Now that the contract terms (and thus the fulfillment URL) are
    884      available, subscribe to session-capture triggers if requested.
    885      The @e session_eh guard makes this idempotent across the phase
    886      re-runs of the long-polling loop; @e gorc->session_eh is cancelled
    887      in gorc_cleanup(). */
    888   if ( (NULL != gorc->session_id) &&
    889        (NULL != gorc->ct->fulfillment_url) &&
    890        (NULL == gorc->session_eh) )
    891   {
    892     struct TMH_SessionEventP session_eh = {
    893       .header.size = htons (sizeof (session_eh)),
    894       .header.type = htons (TALER_DBEVENT_MERCHANT_SESSION_CAPTURED),
    895       .merchant_pub = hc->instance->merchant_pub
    896     };
    897 
    898     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    899                 "Subscribing to session triggers for %p\n",
    900                 gorc);
    901     GNUNET_CRYPTO_hash (gorc->session_id,
    902                         strlen (gorc->session_id),
    903                         &session_eh.h_session_id);
    904     GNUNET_CRYPTO_hash (gorc->ct->fulfillment_url,
    905                         strlen (gorc->ct->fulfillment_url),
    906                         &session_eh.h_fulfillment_url);
    907     gorc->session_eh
    908       = TALER_MERCHANTDB_event_listen (
    909           TMH_db,
    910           &session_eh.header,
    911           GNUNET_TIME_absolute_get_remaining (gorc->sc.long_poll_timeout),
    912           &resume_by_event,
    913           gorc);
    914     gorc->instant_retry = true;
    915   }
    916 
    917   switch (gorc->ct->version)
    918   {
    919   case TALER_MERCHANT_CONTRACT_VERSION_0:
    920     gorc->contract_amount
    921       = (NULL != gorc->pc)
    922       ? gorc->pc->details.v0.brutto
    923       : gorc->order->details.v0.brutto;
    924     gorc->max_fee
    925       = (NULL != gorc->pc)
    926       ? gorc->pc->details.v0.max_fee
    927       : gorc->order->details.v0.max_fee;
    928     gorc->has_max_fee
    929       = (NULL != gorc->pc)
    930       ? true
    931       : ! gorc->order->details.v0.no_max_fee;
    932     break;
    933   case TALER_MERCHANT_CONTRACT_VERSION_1:
    934     if (gorc->choice_index >= 0)
    935     {
    936       if (gorc->choice_index >=
    937           ( (NULL != gorc->pc)
    938             ? gorc->pc->details.v1.choices_len
    939             : gorc->order->details.v1.choices_len) )
    940       {
    941         GNUNET_break (0);
    942         phase_end (gorc,
    943                    TALER_MHD_reply_with_error (
    944                      gorc->sc.con,
    945                      MHD_HTTP_INTERNAL_SERVER_ERROR,
    946                      TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
    947                      NULL));
    948         return;
    949       }
    950       gorc->contract_amount
    951         = (NULL != gorc->pc)
    952         ? gorc->pc->details.v1.choices[gorc->choice_index].amount
    953         : gorc->order->details.v1.choices[gorc->choice_index].amount;
    954       gorc->max_fee
    955         = (NULL != gorc->pc)
    956         ? gorc->pc->details.v1.choices[gorc->choice_index].max_fee
    957         : gorc->order->details.v1.choices[gorc->choice_index].max_fee;
    958       gorc->has_max_fee
    959         = (NULL != gorc->pc)
    960         ? true
    961         : ! gorc->order->details.v1.choices[gorc->choice_index].no_max_fee;
    962     }
    963     else
    964     {
    965       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    966                   "Choice index %i is invalid",
    967                   gorc->choice_index);
    968     }
    969     break;
    970   default:
    971     {
    972       GNUNET_break (0);
    973       phase_end (gorc,
    974                  TALER_MHD_reply_with_error (
    975                    gorc->sc.con,
    976                    MHD_HTTP_INTERNAL_SERVER_ERROR,
    977                    TALER_EC_MERCHANT_GET_ORDERS_ID_INVALID_CONTRACT_VERSION,
    978                    NULL));
    979       return;
    980     }
    981   }
    982 
    983   if ( (NULL != gorc->contract_terms) &&
    984        (GNUNET_OK !=
    985         TALER_JSON_contract_hash (gorc->contract_terms_json,
    986                                   &gorc->h_contract_terms)) )
    987   {
    988     GNUNET_break (0);
    989     phase_end (gorc,
    990                TALER_MHD_reply_with_error (gorc->sc.con,
    991                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    992                                            TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
    993                                            NULL));
    994     return;
    995   }
    996   GNUNET_assert ( (NULL != gorc->contract_terms_json) ||
    997                   (NULL != gorc->order_json) );
    998   GNUNET_assert ( (NULL != gorc->pc) ||
    999                   (NULL != gorc->order) );
   1000   gorc->phase++;
   1001 }
   1002 
   1003 
   1004 /**
   1005  * Check payment status of the order.
   1006  *
   1007  * @param[in,out] gorc order context to update
   1008  */
   1009 static void
   1010 phase_check_paid (struct GetOrderRequestContext *gorc)
   1011 {
   1012   struct TMH_HandlerContext *hc = gorc->hc;
   1013 
   1014   if (gorc->order_only)
   1015   {
   1016     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1017                 "Order %s unclaimed, no need to lookup payment status\n",
   1018                 hc->infix);
   1019     GNUNET_assert (! gorc->paid);
   1020     GNUNET_assert (! gorc->wired);
   1021     gorc->phase++;
   1022     return;
   1023   }
   1024   if (NULL == gorc->session_id)
   1025   {
   1026     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1027                 "No session ID, do not need to lookup session-ID specific payment status (%s/%s)\n",
   1028                 gorc->paid ? "paid" : "unpaid",
   1029                 gorc->wired ? "wired" : "unwired");
   1030     gorc->phase++;
   1031     return;
   1032   }
   1033   if (! gorc->paid_session_matches)
   1034   {
   1035     gorc->paid = false;
   1036     gorc->wired = false;
   1037   }
   1038   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1039               "Order %s %s for session %s (%s)\n",
   1040               hc->infix,
   1041               gorc->paid ? "paid" : "unpaid",
   1042               gorc->session_id,
   1043               gorc->wired ? "wired" : "unwired");
   1044   gorc->phase++;
   1045 }
   1046 
   1047 
   1048 /**
   1049  * Check if the @a reply satisfies the long-poll not_etag
   1050  * constraint. If so, return it as a response for @a gorc,
   1051  * otherwise suspend and wait for a change.
   1052  *
   1053  * @param[in,out] gorc request to handle
   1054  * @param reply body for JSON response (#MHD_HTTP_OK)
   1055  */
   1056 static void
   1057 check_reply (struct GetOrderRequestContext *gorc,
   1058              const json_t *reply)
   1059 {
   1060   struct GNUNET_ShortHashCode sh;
   1061   unsigned int http_response_code;
   1062   bool not_modified;
   1063   struct MHD_Response *response;
   1064   char *can;
   1065 
   1066   can = TALER_JSON_canonicalize (reply);
   1067   GNUNET_assert (GNUNET_YES ==
   1068                  GNUNET_CRYPTO_hkdf_gnunet (&sh,
   1069                                             sizeof (sh),
   1070                                             "GOR-SALT",
   1071                                             strlen ("GOR-SALT"),
   1072                                             can,
   1073                                             strlen (can)));
   1074   not_modified = gorc->have_lp_not_etag &&
   1075                  (0 == GNUNET_memcmp (&sh,
   1076                                       &gorc->lp_not_etag));
   1077 
   1078   if (not_modified &&
   1079       (! GNUNET_TIME_absolute_is_past (gorc->sc.long_poll_timeout)) )
   1080   {
   1081     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1082                 "Status unchanged, not returning response yet\n");
   1083     GNUNET_assert (GNUNET_NO == gorc->suspended);
   1084     if (gorc->instant_retry)
   1085     {
   1086       gorc->instant_retry = false;
   1087       gorc->phase = GOP_FETCH_CONTRACT;
   1088       GNUNET_free (can);
   1089       return;
   1090     }
   1091     /* note: not necessarily actually unpaid ... */
   1092     GNUNET_CONTAINER_DLL_insert (gorc_head,
   1093                                  gorc_tail,
   1094                                  gorc);
   1095     gorc->phase = GOP_SUSPENDED_ON_UNPAID;
   1096     gorc->suspended = GNUNET_YES;
   1097     MHD_suspend_connection (gorc->sc.con);
   1098     GNUNET_free (can);
   1099     return;
   1100   }
   1101   {
   1102     const char *inm;
   1103 
   1104     inm = MHD_lookup_connection_value (gorc->sc.con,
   1105                                        MHD_HEADER_KIND,
   1106                                        MHD_HTTP_HEADER_IF_NONE_MATCH);
   1107     if ( (NULL == inm) ||
   1108          ('"' != inm[0]) ||
   1109          ('"' != inm[strlen (inm) - 1]) ||
   1110          (0 != strncmp (inm + 1,
   1111                         can,
   1112                         strlen (can))) )
   1113       not_modified = false; /* must return full response */
   1114   }
   1115   GNUNET_free (can);
   1116   http_response_code = not_modified
   1117     ? MHD_HTTP_NOT_MODIFIED
   1118     : MHD_HTTP_OK;
   1119   response = TALER_MHD_make_json (reply);
   1120   {
   1121     char *etag;
   1122     char *qetag;
   1123 
   1124     etag = GNUNET_STRINGS_data_to_string_alloc (&sh,
   1125                                                 sizeof (sh));
   1126     GNUNET_asprintf (&qetag,
   1127                      "\"%s\"",
   1128                      etag);
   1129     GNUNET_break (MHD_YES ==
   1130                   MHD_add_response_header (response,
   1131                                            MHD_HTTP_HEADER_ETAG,
   1132                                            qetag));
   1133     GNUNET_free (qetag);
   1134     GNUNET_free (etag);
   1135   }
   1136 
   1137   {
   1138     enum MHD_Result ret;
   1139 
   1140     ret = MHD_queue_response (gorc->sc.con,
   1141                               http_response_code,
   1142                               response);
   1143     MHD_destroy_response (response);
   1144     phase_end (gorc,
   1145                ret);
   1146   }
   1147 }
   1148 
   1149 
   1150 /**
   1151  * Check if re-purchase detection applies to the order.
   1152  *
   1153  * @param[in,out] gorc order context to update
   1154  */
   1155 static void
   1156 phase_check_repurchase (struct GetOrderRequestContext *gorc)
   1157 {
   1158   struct TMH_HandlerContext *hc = gorc->hc;
   1159   char *already_paid_order_id = NULL;
   1160   enum GNUNET_DB_QueryStatus qs;
   1161   char *taler_pay_uri;
   1162   char *order_status_url;
   1163   json_t *reply;
   1164 
   1165   if ( (gorc->paid) ||
   1166        (NULL == gorc->ct->fulfillment_url) ||
   1167        (NULL == gorc->session_id) )
   1168   {
   1169     /* Repurchase cannot apply */
   1170     gorc->phase++;
   1171     return;
   1172   }
   1173   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1174               "Running re-purchase detection for %s/%s\n",
   1175               gorc->session_id,
   1176               gorc->ct->fulfillment_url);
   1177   qs = TALER_MERCHANTDB_get_order_by_fulfillment (
   1178     TMH_db,
   1179     hc->instance->settings.id,
   1180     gorc->ct->fulfillment_url,
   1181     gorc->session_id,
   1182     TALER_EXCHANGE_YNA_NO !=
   1183     gorc->allow_refunded_for_repurchase,
   1184     &already_paid_order_id);
   1185   if (0 > qs)
   1186   {
   1187     /* single, read-only SQL statements should never cause
   1188        serialization problems, and the entry should exist as per above */
   1189     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
   1190     phase_end (gorc,
   1191                TALER_MHD_reply_with_error (gorc->sc.con,
   1192                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1193                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1194                                            "order by fulfillment"));
   1195     return;
   1196   }
   1197   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1198   {
   1199     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1200                 "No already paid order for %s/%s\n",
   1201                 gorc->session_id,
   1202                 gorc->ct->fulfillment_url);
   1203     gorc->phase++;
   1204     return;
   1205   }
   1206 
   1207   /* User did pay for this order, but under a different session; ask wallet to
   1208      switch order ID */
   1209   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1210               "Found already paid order %s\n",
   1211               already_paid_order_id);
   1212   taler_pay_uri = TMH_make_taler_pay_uri (gorc->sc.con,
   1213                                           hc->infix,
   1214                                           gorc->session_id,
   1215                                           hc->instance->settings.id,
   1216                                           &gorc->claim_token);
   1217   order_status_url = TMH_make_order_status_url (gorc->sc.con,
   1218                                                 hc->infix,
   1219                                                 gorc->session_id,
   1220                                                 hc->instance->settings.id,
   1221                                                 &gorc->claim_token,
   1222                                                 NULL);
   1223   if ( (NULL == taler_pay_uri) ||
   1224        (NULL == order_status_url) )
   1225   {
   1226     GNUNET_break_op (0);
   1227     GNUNET_free (taler_pay_uri);
   1228     GNUNET_free (order_status_url);
   1229     phase_end (gorc,
   1230                TALER_MHD_reply_with_error (gorc->sc.con,
   1231                                            MHD_HTTP_BAD_REQUEST,
   1232                                            TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED,
   1233                                            "host"));
   1234     return;
   1235   }
   1236   reply = GNUNET_JSON_PACK (
   1237     GNUNET_JSON_pack_string ("taler_pay_uri",
   1238                              taler_pay_uri),
   1239     GNUNET_JSON_pack_string ("order_status_url",
   1240                              order_status_url),
   1241     GNUNET_JSON_pack_string ("order_status",
   1242                              "unpaid"),
   1243     GNUNET_JSON_pack_string ("already_paid_order_id",
   1244                              already_paid_order_id),
   1245     GNUNET_JSON_pack_string ("already_paid_fulfillment_url",
   1246                              gorc->ct->fulfillment_url),
   1247     /* undefined for unpaid v1 contracts */
   1248     GNUNET_JSON_pack_allow_null (
   1249       TALER_JSON_pack_amount ("total_amount",
   1250                               TALER_amount_is_valid (&gorc->contract_amount)
   1251                               ? &gorc->contract_amount
   1252                               : NULL)),
   1253     GNUNET_JSON_pack_object_incref ("proto_contract_terms",
   1254                                     gorc->contract_terms_json),
   1255     GNUNET_JSON_pack_string ("summary",
   1256                              gorc->ct->summary),
   1257     GNUNET_JSON_pack_timestamp ("pay_deadline",
   1258                                 NULL != gorc->pc
   1259                                 ? gorc->pc->pay_deadline
   1260                                 : gorc->order->pay_deadline),
   1261     GNUNET_JSON_pack_timestamp ("creation_time",
   1262                                 gorc->timestamp));
   1263 
   1264   GNUNET_free (order_status_url);
   1265   GNUNET_free (taler_pay_uri);
   1266   GNUNET_free (already_paid_order_id);
   1267   check_reply (gorc,
   1268                reply);
   1269   json_decref (reply);
   1270 }
   1271 
   1272 
   1273 /**
   1274  * Check if we should suspend until the order is paid.
   1275  *
   1276  * @param[in,out] gorc order context to update
   1277  */
   1278 static void
   1279 phase_unpaid_finish (struct GetOrderRequestContext *gorc)
   1280 {
   1281   struct TMH_HandlerContext *hc = gorc->hc;
   1282   char *order_status_url;
   1283 
   1284   if (gorc->paid)
   1285   {
   1286     gorc->phase++;
   1287     return;
   1288   }
   1289   /* User never paid for this order, suspend waiting
   1290      on payment or return details. */
   1291   if (GNUNET_TIME_absolute_is_future (gorc->sc.long_poll_timeout) &&
   1292       (! gorc->have_lp_not_etag) )
   1293   {
   1294     if (gorc->instant_retry)
   1295     {
   1296       gorc->instant_retry = false;
   1297       gorc->phase = GOP_FETCH_CONTRACT;
   1298       return;
   1299     }
   1300     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1301                 "Suspending GET /private/orders/%s\n",
   1302                 hc->infix);
   1303     GNUNET_CONTAINER_DLL_insert (gorc_head,
   1304                                  gorc_tail,
   1305                                  gorc);
   1306     gorc->phase = GOP_SUSPENDED_ON_UNPAID;
   1307     gorc->suspended = GNUNET_YES;
   1308     MHD_suspend_connection (gorc->sc.con);
   1309     return;
   1310   }
   1311   order_status_url = TMH_make_order_status_url (gorc->sc.con,
   1312                                                 hc->infix,
   1313                                                 gorc->session_id,
   1314                                                 hc->instance->settings.id,
   1315                                                 &gorc->claim_token,
   1316                                                 NULL);
   1317   if (! gorc->order_only)
   1318   {
   1319     json_t *reply;
   1320 
   1321     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1322                 "Order %s claimed but not paid yet\n",
   1323                 hc->infix);
   1324     reply = GNUNET_JSON_PACK (
   1325       GNUNET_JSON_pack_string ("order_status_url",
   1326                                order_status_url),
   1327       GNUNET_JSON_pack_object_incref ("contract_terms",
   1328                                       gorc->contract_terms_json),
   1329       GNUNET_JSON_pack_string ("order_status",
   1330                                "claimed"));
   1331     GNUNET_free (order_status_url);
   1332     check_reply (gorc,
   1333                  reply);
   1334     json_decref (reply);
   1335     return;
   1336   }
   1337   {
   1338     char *taler_pay_uri;
   1339     json_t *reply;
   1340 
   1341     taler_pay_uri = TMH_make_taler_pay_uri (gorc->sc.con,
   1342                                             hc->infix,
   1343                                             gorc->session_id,
   1344                                             hc->instance->settings.id,
   1345                                             &gorc->claim_token);
   1346     reply = GNUNET_JSON_PACK (
   1347       GNUNET_JSON_pack_string ("taler_pay_uri",
   1348                                taler_pay_uri),
   1349       GNUNET_JSON_pack_string ("order_status_url",
   1350                                order_status_url),
   1351       GNUNET_JSON_pack_string ("order_status",
   1352                                "unpaid"),
   1353       GNUNET_JSON_pack_object_incref ("proto_contract_terms",
   1354                                       gorc->contract_terms_json),
   1355       /* undefined for unpaid v1 contracts */
   1356       GNUNET_JSON_pack_allow_null (
   1357         TALER_JSON_pack_amount ("total_amount",
   1358                                 &gorc->contract_amount)),
   1359       GNUNET_JSON_pack_string ("summary",
   1360                                gorc->ct->summary),
   1361       GNUNET_JSON_pack_timestamp ("creation_time",
   1362                                   gorc->timestamp));
   1363     check_reply (gorc,
   1364                  reply);
   1365     json_decref (reply);
   1366     GNUNET_free (taler_pay_uri);
   1367   }
   1368   GNUNET_free (order_status_url);
   1369 }
   1370 
   1371 
   1372 /**
   1373  * Function called with each @a coin_pub that was deposited into the
   1374  * @a h_wire account of the merchant for the @a deposit_serial as part
   1375  * of the payment for the order identified by @a cls.
   1376  *
   1377  * Queries the exchange for the payment status associated with the
   1378  * given coin.
   1379  *
   1380  * @param cls a `struct GetOrderRequestContext`
   1381  * @param deposit_serial identifies the deposit operation
   1382  * @param exchange_url URL of the exchange that issued @a coin_pub
   1383  * @param h_wire hash of the merchant's wire account into which the deposit was made
   1384  * @param deposit_timestamp when was the deposit made
   1385  * @param amount_with_fee amount the exchange will deposit for this coin
   1386  * @param deposit_fee fee the exchange will charge for this coin
   1387  * @param coin_pub public key of the deposited coin
   1388  */
   1389 static void
   1390 deposit_cb (
   1391   void *cls,
   1392   uint64_t deposit_serial,
   1393   const char *exchange_url,
   1394   const struct TALER_MerchantWireHashP *h_wire,
   1395   struct GNUNET_TIME_Timestamp deposit_timestamp,
   1396   const struct TALER_Amount *amount_with_fee,
   1397   const struct TALER_Amount *deposit_fee,
   1398   const struct TALER_CoinSpendPublicKeyP *coin_pub)
   1399 {
   1400   struct GetOrderRequestContext *gorc = cls;
   1401   struct TransferQuery *tq;
   1402 
   1403   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1404               "Checking deposit status for coin %s (over %s)\n",
   1405               TALER_B2S (coin_pub),
   1406               TALER_amount2s (amount_with_fee));
   1407   if ( (GNUNET_OK !=
   1408         TALER_amount_cmp_currency (&gorc->deposit_fees_total,
   1409                                    amount_with_fee)) ||
   1410        (GNUNET_OK !=
   1411         TALER_amount_cmp_currency (&gorc->deposit_fees_total,
   1412                                    deposit_fee)) )
   1413   {
   1414     GNUNET_break (0);
   1415     gorc->deposit_currency_mismatch = true;
   1416     return;
   1417   }
   1418   gorc->last_payment
   1419     = GNUNET_TIME_timestamp_max (gorc->last_payment,
   1420                                  deposit_timestamp);
   1421   tq = GNUNET_new (struct TransferQuery);
   1422   tq->gorc = gorc;
   1423   tq->exchange_url = GNUNET_strdup (exchange_url);
   1424   tq->deposit_serial = deposit_serial;
   1425   GNUNET_CONTAINER_DLL_insert (gorc->tq_head,
   1426                                gorc->tq_tail,
   1427                                tq);
   1428   tq->coin_pub = *coin_pub;
   1429   tq->h_wire = *h_wire;
   1430   tq->amount_with_fee = *amount_with_fee;
   1431   tq->deposit_fee = *deposit_fee;
   1432   GNUNET_assert (GNUNET_OK ==
   1433                  TALER_amount_set_zero (amount_with_fee->currency,
   1434                                         &tq->refunded_total));
   1435   GNUNET_assert (0 <=
   1436                  TALER_amount_add (&gorc->deposit_fees_total,
   1437                                    &gorc->deposit_fees_total,
   1438                                    deposit_fee));
   1439 }
   1440 
   1441 
   1442 /**
   1443  * Check wire transfer status for the order at the exchange.
   1444  *
   1445  * @param[in,out] gorc order context to update
   1446  */
   1447 static void
   1448 phase_check_deposits (struct GetOrderRequestContext *gorc)
   1449 {
   1450   GNUNET_assert (! gorc->order_only);
   1451   GNUNET_assert (gorc->paid);
   1452 
   1453   /* amount must be always valid for paid orders */
   1454   GNUNET_assert (GNUNET_OK ==
   1455                  TALER_amount_is_valid (&gorc->contract_amount));
   1456   /* We may be running again due to long-polling;
   1457      clear left-overs from previous iterations */
   1458   clear_transfer_queries (gorc);
   1459   GNUNET_assert (GNUNET_OK ==
   1460                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1461                                         &gorc->deposits_total));
   1462   GNUNET_assert (GNUNET_OK ==
   1463                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1464                                         &gorc->deposit_fees_total));
   1465   GNUNET_assert (GNUNET_OK ==
   1466                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1467                                         &gorc->deposit_fees_refunded_total));
   1468   TALER_MERCHANTDB_iterate_deposits_by_order (TMH_db,
   1469                                               gorc->order_serial,
   1470                                               &deposit_cb,
   1471                                               gorc);
   1472   if (gorc->deposit_currency_mismatch)
   1473   {
   1474     GNUNET_break (0);
   1475     phase_end (gorc,
   1476                TALER_MHD_reply_with_error (
   1477                  gorc->sc.con,
   1478                  MHD_HTTP_INTERNAL_SERVER_ERROR,
   1479                  TALER_EC_GENERIC_DB_FETCH_FAILED,
   1480                  "deposits in different currency than original order price"));
   1481     return;
   1482   }
   1483   gorc->phase++;
   1484 }
   1485 
   1486 
   1487 /**
   1488  * Function called with information about a refund.
   1489  * It is responsible for summing up the refund amount.
   1490  *
   1491  * @param cls closure
   1492  * @param refund_serial unique serial number of the refund
   1493  * @param timestamp time of the refund (for grouping of refunds in the wallet UI)
   1494  * @param coin_pub public coin from which the refund comes from
   1495  * @param exchange_url URL of the exchange that issued @a coin_pub
   1496  * @param rtransaction_id identificator of the refund
   1497  * @param reason human-readable explanation of the refund
   1498  * @param refund_amount refund amount which is being taken from @a coin_pub
   1499  * @param pending true if the this refund was not yet processed by the wallet/exchange
   1500  */
   1501 static void
   1502 process_refunds_cb (
   1503   void *cls,
   1504   uint64_t refund_serial,
   1505   struct GNUNET_TIME_Timestamp timestamp,
   1506   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   1507   const char *exchange_url,
   1508   uint64_t rtransaction_id,
   1509   const char *reason,
   1510   const struct TALER_Amount *refund_amount,
   1511   bool pending)
   1512 {
   1513   struct GetOrderRequestContext *gorc = cls;
   1514 
   1515   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1516               "Found refund %llu over %s for reason %s\n",
   1517               (unsigned long long) rtransaction_id,
   1518               TALER_amount2s (refund_amount),
   1519               reason);
   1520   GNUNET_assert (
   1521     0 ==
   1522     json_array_append_new (
   1523       gorc->refund_details,
   1524       GNUNET_JSON_PACK (
   1525         TALER_JSON_pack_amount ("amount",
   1526                                 refund_amount),
   1527         GNUNET_JSON_pack_bool ("pending",
   1528                                pending),
   1529         GNUNET_JSON_pack_timestamp ("timestamp",
   1530                                     timestamp),
   1531         GNUNET_JSON_pack_string ("reason",
   1532                                  reason))));
   1533   /* Add up the refunds per coin; #phase_check_refunds() checks if
   1534      the total is high enough to void the deposit fee. */
   1535   for (struct TransferQuery *tq = gorc->tq_head;
   1536        NULL != tq;
   1537        tq = tq->next)
   1538   {
   1539     if (0 !=
   1540         strcmp (exchange_url,
   1541                 tq->exchange_url))
   1542       continue;
   1543     if (0 !=
   1544         GNUNET_memcmp (&tq->coin_pub,
   1545                        coin_pub))
   1546       continue;
   1547     if (GNUNET_OK !=
   1548         TALER_amount_cmp_currency (
   1549           &tq->refunded_total,
   1550           refund_amount))
   1551     {
   1552       gorc->refund_currency_mismatch = true;
   1553       return;
   1554     }
   1555     GNUNET_assert (
   1556       0 <=
   1557       TALER_amount_add (&tq->refunded_total,
   1558                         &tq->refunded_total,
   1559                         refund_amount));
   1560   }
   1561   if (GNUNET_OK !=
   1562       TALER_amount_cmp_currency (
   1563         &gorc->refund_amount,
   1564         refund_amount))
   1565   {
   1566     gorc->refund_currency_mismatch = true;
   1567     return;
   1568   }
   1569   GNUNET_assert (0 <=
   1570                  TALER_amount_add (&gorc->refund_amount,
   1571                                    &gorc->refund_amount,
   1572                                    refund_amount));
   1573   gorc->refunded = true;
   1574   gorc->refund_pending |= pending;
   1575 }
   1576 
   1577 
   1578 /**
   1579  * Function called with information about an external refund.
   1580  * Appends the refund entry to the "refunds_external" array.
   1581  *
   1582  * @param cls a `struct GetOrderRequestContext`
   1583  * @param refund_id identifier of the refund within the order
   1584  * @param refund_timestamp when was the refund recorded
   1585  * @param method external payment method used for the refund
   1586  * @param payment_id id of the original external payment entry
   1587  * @param amount amount returned to the customer
   1588  * @param reason human-readable refund justification
   1589  */
   1590 static void
   1591 process_external_refunds_cb (void *cls,
   1592                              const char *refund_id,
   1593                              struct GNUNET_TIME_Timestamp refund_timestamp,
   1594                              const char *method,
   1595                              const char *payment_id,
   1596                              const struct TALER_Amount *amount,
   1597                              const char *reason)
   1598 {
   1599   struct GetOrderRequestContext *gorc = cls;
   1600 
   1601   GNUNET_assert (
   1602     0 ==
   1603     json_array_append_new (
   1604       gorc->refunds_external,
   1605       GNUNET_JSON_PACK (
   1606         GNUNET_JSON_pack_string ("id",
   1607                                  refund_id),
   1608         GNUNET_JSON_pack_string ("method",
   1609                                  method),
   1610         GNUNET_JSON_pack_allow_null (
   1611           GNUNET_JSON_pack_string ("payment_id",
   1612                                    payment_id)),
   1613         TALER_JSON_pack_amount ("amount",
   1614                                 amount),
   1615         GNUNET_JSON_pack_string ("reason",
   1616                                  reason),
   1617         GNUNET_JSON_pack_timestamp ("timestamp",
   1618                                     refund_timestamp))));
   1619 }
   1620 
   1621 
   1622 /**
   1623  * Check refund status for the order.
   1624  *
   1625  * @param[in,out] gorc order context to update
   1626  */
   1627 static void
   1628 phase_check_refunds (struct GetOrderRequestContext *gorc)
   1629 {
   1630   struct TMH_HandlerContext *hc = gorc->hc;
   1631   enum GNUNET_DB_QueryStatus qs;
   1632 
   1633   GNUNET_assert (! gorc->order_only);
   1634   GNUNET_assert (gorc->paid);
   1635 
   1636   /* Accumulate refunds, if any. */
   1637   GNUNET_assert (GNUNET_OK ==
   1638                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1639                                         &gorc->refund_amount));
   1640   json_array_clear (gorc->refund_details);
   1641   qs = TALER_MERCHANTDB_iterate_refunds_detailed (
   1642     TMH_db,
   1643     hc->instance->settings.id,
   1644     &gorc->h_contract_terms,
   1645     &process_refunds_cb,
   1646     gorc);
   1647   if (0 > qs)
   1648   {
   1649     GNUNET_break (0);
   1650     phase_end (gorc,
   1651                TALER_MHD_reply_with_error (
   1652                  gorc->sc.con,
   1653                  MHD_HTTP_INTERNAL_SERVER_ERROR,
   1654                  TALER_EC_GENERIC_DB_FETCH_FAILED,
   1655                  "detailed refunds"));
   1656     return;
   1657   }
   1658   if (gorc->refund_currency_mismatch)
   1659   {
   1660     GNUNET_break (0);
   1661     phase_end (gorc,
   1662                TALER_MHD_reply_with_error (
   1663                  gorc->sc.con,
   1664                  MHD_HTTP_INTERNAL_SERVER_ERROR,
   1665                  TALER_EC_GENERIC_DB_FETCH_FAILED,
   1666                  "refunds in different currency than original order price"));
   1667     return;
   1668   }
   1669   /* Exchange cancels deposit fees of fully refunded coins, check for that case */
   1670   for (struct TransferQuery *tq = gorc->tq_head;
   1671        NULL != tq;
   1672        tq = tq->next)
   1673   {
   1674     if (0 !=
   1675         TALER_amount_cmp (&tq->refunded_total,
   1676                           &tq->amount_with_fee))
   1677       continue; /* not refunded in full, we still owe the deposit fee */
   1678     GNUNET_assert (
   1679       0 <=
   1680       TALER_amount_add (&gorc->deposit_fees_refunded_total,
   1681                         &gorc->deposit_fees_refunded_total,
   1682                         &tq->deposit_fee));
   1683   }
   1684   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1685               "Total refunds are %s\n",
   1686               TALER_amount2s (&gorc->refund_amount));
   1687   json_array_clear (gorc->refunds_external);
   1688   qs = TALER_MERCHANTDB_iterate_external_refunds (
   1689     TMH_db,
   1690     hc->instance->settings.id,
   1691     hc->infix,
   1692     &process_external_refunds_cb,
   1693     gorc);
   1694   if (0 > qs)
   1695   {
   1696     GNUNET_break (0);
   1697     phase_end (gorc,
   1698                TALER_MHD_reply_with_error (
   1699                  gorc->sc.con,
   1700                  MHD_HTTP_INTERNAL_SERVER_ERROR,
   1701                  TALER_EC_GENERIC_DB_FETCH_FAILED,
   1702                  "external refunds"));
   1703     return;
   1704   }
   1705   gorc->phase++;
   1706 }
   1707 
   1708 
   1709 /**
   1710  * Function called with available wire details, to be added to
   1711  * the response.
   1712  *
   1713  * @param cls a `struct GetOrderRequestContext`
   1714  * @param wtid wire transfer subject of the wire transfer for the coin
   1715  * @param exchange_url base URL of the exchange that made the payment
   1716  * @param execution_time when was the payment made
   1717  * @param deposit_value contribution of the coin to the total wire transfer value
   1718  * @param deposit_fee deposit fee charged by the exchange for the coin
   1719  * @param transfer_confirmed did the merchant confirm that a wire transfer with
   1720  *        @a wtid over the total amount happened?
   1721  * @param expected_credit_serial row for the expected wire transfer this
   1722  *   entry references
   1723  */
   1724 static void
   1725 process_transfer_details (
   1726   void *cls,
   1727   const struct TALER_WireTransferIdentifierRawP *wtid,
   1728   const char *exchange_url,
   1729   struct GNUNET_TIME_Timestamp execution_time,
   1730   const struct TALER_Amount *deposit_value,
   1731   const struct TALER_Amount *deposit_fee,
   1732   bool transfer_confirmed,
   1733   uint64_t expected_credit_serial)
   1734 {
   1735   struct GetOrderRequestContext *gorc = cls;
   1736   json_t *wire_details = gorc->wire_details;
   1737   struct TALER_Amount wired;
   1738 
   1739   if ( (GNUNET_OK !=
   1740         TALER_amount_cmp_currency (&gorc->deposits_total,
   1741                                    deposit_value)) ||
   1742        (GNUNET_OK !=
   1743         TALER_amount_cmp_currency (&gorc->deposit_fees_total,
   1744                                    deposit_fee)) )
   1745   {
   1746     GNUNET_break (0);
   1747     gorc->deposit_currency_mismatch = true;
   1748     return;
   1749   }
   1750 
   1751   /* Compute total amount *wired*.  Note that @e deposit_fees_total is
   1752      deliberately not touched here: it covers every coin of the order,
   1753      while this callback only sees the coins whose wire transfer we
   1754      already know about. */
   1755   GNUNET_assert (0 <=
   1756                  TALER_amount_add (&gorc->deposits_total,
   1757                                    &gorc->deposits_total,
   1758                                    deposit_value));
   1759   GNUNET_assert (0 <= TALER_amount_subtract (&wired,
   1760                                              deposit_value,
   1761                                              deposit_fee));
   1762   GNUNET_assert (0 ==
   1763                  json_array_append_new (
   1764                    wire_details,
   1765                    GNUNET_JSON_PACK (
   1766                      GNUNET_JSON_pack_data_auto ("wtid",
   1767                                                  wtid),
   1768                      GNUNET_JSON_pack_string ("exchange_url",
   1769                                               exchange_url),
   1770                      TALER_JSON_pack_amount ("amount",
   1771                                              &wired),
   1772                      TALER_JSON_pack_amount ("deposit_fee",
   1773                                              deposit_fee),
   1774                      GNUNET_JSON_pack_timestamp ("execution_time",
   1775                                                  execution_time),
   1776                      GNUNET_JSON_pack_bool ("confirmed",
   1777                                             transfer_confirmed),
   1778                      GNUNET_JSON_pack_uint64 ("expected_transfer_serial_id",
   1779                                               expected_credit_serial))));
   1780 }
   1781 
   1782 
   1783 /**
   1784  * Check transfer status in local database.
   1785  *
   1786  * @param[in,out] gorc order context to update
   1787  */
   1788 static void
   1789 phase_check_local_transfers (struct GetOrderRequestContext *gorc)
   1790 {
   1791   struct TMH_HandlerContext *hc = gorc->hc;
   1792   enum GNUNET_DB_QueryStatus qs;
   1793 
   1794   GNUNET_assert (gorc->paid);
   1795   GNUNET_assert (! gorc->order_only);
   1796 
   1797   GNUNET_assert (GNUNET_OK ==
   1798                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1799                                         &gorc->deposits_total));
   1800   GNUNET_assert (NULL != gorc->wire_details);
   1801   /* We may be running again due to long-polling, clear state first */
   1802   json_array_clear (gorc->wire_details);
   1803   qs = TALER_MERCHANTDB_iterate_transfer_details_by_order (TMH_db,
   1804                                                            gorc->order_serial,
   1805                                                            &process_transfer_details,
   1806                                                            gorc);
   1807   if (0 > qs)
   1808   {
   1809     GNUNET_break (0);
   1810     phase_end (gorc,
   1811                TALER_MHD_reply_with_error (gorc->sc.con,
   1812                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1813                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1814                                            "transfer details"));
   1815     return;
   1816   }
   1817   if (gorc->deposit_currency_mismatch)
   1818   {
   1819     GNUNET_break (0);
   1820     phase_end (gorc,
   1821                TALER_MHD_reply_with_error (gorc->sc.con,
   1822                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1823                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1824                                            "deposits in different currency than original order price"));
   1825     return;
   1826   }
   1827 
   1828   if (! gorc->wired)
   1829   {
   1830     /* we believe(d) the wire transfer did not happen yet, check if maybe
   1831        in light of new evidence it did */
   1832     struct TALER_Amount expect_total;
   1833     enum GNUNET_GenericReturnValue fee_ret;
   1834 
   1835     fee_ret = TMH_compute_expected_transfer (
   1836       &gorc->contract_amount,
   1837       &gorc->refund_amount,
   1838       &gorc->deposit_fees_total,
   1839       &gorc->deposit_fees_refunded_total,
   1840       gorc->has_max_fee ? &gorc->max_fee : NULL,
   1841       gorc->has_max_fee,
   1842       &expect_total);
   1843     switch (fee_ret)
   1844     {
   1845     case GNUNET_OK:
   1846       break;
   1847     case GNUNET_SYSERR:
   1848       GNUNET_break (0);
   1849       phase_end (gorc,
   1850                  TALER_MHD_reply_with_error (
   1851                    gorc->sc.con,
   1852                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1853                    TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
   1854                    "refund or refunded deposit fees exceed allowed total"));
   1855       return;
   1856     case GNUNET_NO:
   1857       GNUNET_break (0);
   1858       phase_end (gorc,
   1859                  TALER_MHD_reply_with_error (
   1860                    gorc->sc.con,
   1861                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1862                    TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
   1863                    "deposit fees exceed total minus refunds"));
   1864       return;
   1865     default:
   1866       GNUNET_break (0);
   1867       phase_end (gorc,
   1868                  TALER_MHD_reply_with_error (
   1869                    gorc->sc.con,
   1870                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1871                    TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
   1872                    "unexpected fee computation result"));
   1873       return;
   1874     }
   1875     if (0 >=
   1876         TALER_amount_cmp (&expect_total,
   1877                           &gorc->deposits_total))
   1878     {
   1879       /* expect_total <= gorc->deposits_total: good: we got the wire transfer */
   1880       gorc->wired = true;
   1881       qs = TALER_MERCHANTDB_update_to_contract_terms_wired (TMH_db,
   1882                                                             gorc->order_serial);
   1883       GNUNET_break (qs >= 0);   /* just warn if transaction failed */
   1884       TMH_notify_order_change (hc->instance,
   1885                                TMH_OSF_PAID
   1886                                | TMH_OSF_WIRED,
   1887                                gorc->timestamp,
   1888                                gorc->order_serial);
   1889     }
   1890   }
   1891   gorc->phase++;
   1892 }
   1893 
   1894 
   1895 /**
   1896  * Generate final result for the status request.
   1897  *
   1898  * @param[in,out] gorc order context to update
   1899  */
   1900 static void
   1901 phase_reply_result (struct GetOrderRequestContext *gorc)
   1902 {
   1903   struct TMH_HandlerContext *hc = gorc->hc;
   1904   char *order_status_url;
   1905 
   1906   GNUNET_assert (gorc->paid);
   1907   GNUNET_assert (! gorc->order_only);
   1908 
   1909   {
   1910     struct TALER_PrivateContractHashP *h_contract = NULL;
   1911 
   1912     /* In a session-bound payment, allow the browser to check the order
   1913      * status page (e.g. to get a refund).
   1914      *
   1915      * Note that we don't allow this outside of session-based payment, as
   1916      * otherwise this becomes an oracle to convert order_id to h_contract.
   1917      */
   1918     if (NULL != gorc->session_id)
   1919       h_contract = &gorc->h_contract_terms;
   1920 
   1921     order_status_url =
   1922       TMH_make_order_status_url (gorc->sc.con,
   1923                                  hc->infix,
   1924                                  gorc->session_id,
   1925                                  hc->instance->settings.id,
   1926                                  &gorc->claim_token,
   1927                                  h_contract);
   1928   }
   1929   if (GNUNET_TIME_absolute_is_zero (gorc->last_payment.abs_time))
   1930   {
   1931     GNUNET_break (GNUNET_YES ==
   1932                   TALER_amount_is_zero (&gorc->contract_amount));
   1933     gorc->last_payment = gorc->timestamp;
   1934   }
   1935   {
   1936     json_t *reply;
   1937 
   1938     reply = GNUNET_JSON_PACK (
   1939       // Deprecated in protocol v6!
   1940       GNUNET_JSON_pack_array_steal ("wire_reports",
   1941                                     json_array ()),
   1942       GNUNET_JSON_pack_uint64 ("exchange_code",
   1943                                gorc->exchange_ec),
   1944       GNUNET_JSON_pack_uint64 ("exchange_http_status",
   1945                                gorc->exchange_hc),
   1946       /* legacy: */
   1947       GNUNET_JSON_pack_uint64 ("exchange_ec",
   1948                                gorc->exchange_ec),
   1949       /* legacy: */
   1950       GNUNET_JSON_pack_uint64 ("exchange_hc",
   1951                                gorc->exchange_hc),
   1952       TALER_JSON_pack_amount ("deposit_total",
   1953                               &gorc->deposits_total),
   1954       GNUNET_JSON_pack_object_incref ("contract_terms",
   1955                                       gorc->contract_terms_json),
   1956       GNUNET_JSON_pack_string ("order_status",
   1957                                "paid"),
   1958       GNUNET_JSON_pack_timestamp ("last_payment",
   1959                                   gorc->last_payment),
   1960       GNUNET_JSON_pack_bool ("refunded",
   1961                              gorc->refunded),
   1962       GNUNET_JSON_pack_bool ("wired",
   1963                              gorc->wired),
   1964       GNUNET_JSON_pack_bool ("refund_pending",
   1965                              gorc->refund_pending),
   1966       GNUNET_JSON_pack_allow_null (
   1967         TALER_JSON_pack_amount ("refund_amount",
   1968                                 &gorc->refund_amount)),
   1969       GNUNET_JSON_pack_array_incref ("wire_details",
   1970                                      gorc->wire_details),
   1971       GNUNET_JSON_pack_array_incref ("refund_details",
   1972                                      gorc->refund_details),
   1973       GNUNET_JSON_pack_array_incref ("refunds_external",
   1974                                      gorc->refunds_external),
   1975       GNUNET_JSON_pack_string ("order_status_url",
   1976                                order_status_url),
   1977       (gorc->choice_index >= 0)
   1978       ? GNUNET_JSON_pack_int64 ("choice_index",
   1979                                 gorc->choice_index)
   1980       : GNUNET_JSON_pack_end_ ());
   1981     check_reply (gorc,
   1982                  reply);
   1983     json_decref (reply);
   1984   }
   1985   GNUNET_free (order_status_url);
   1986 }
   1987 
   1988 
   1989 /**
   1990  * End with error status in wire_hc and wire_ec.
   1991  *
   1992  * @param[in,out] gorc order context to update
   1993  */
   1994 static void
   1995 phase_error (struct GetOrderRequestContext *gorc)
   1996 {
   1997   GNUNET_assert (TALER_EC_NONE != gorc->wire_ec);
   1998   phase_end (gorc,
   1999              TALER_MHD_reply_with_error (gorc->sc.con,
   2000                                          gorc->wire_hc,
   2001                                          gorc->wire_ec,
   2002                                          NULL));
   2003 }
   2004 
   2005 
   2006 enum MHD_Result
   2007 TMH_private_get_orders_ID (
   2008   const struct TMH_RequestHandler *rh,
   2009   struct MHD_Connection *connection,
   2010   struct TMH_HandlerContext *hc)
   2011 {
   2012   struct GetOrderRequestContext *gorc = hc->ctx;
   2013 
   2014   if (NULL == gorc)
   2015   {
   2016     /* First time here, parse request and check order is known */
   2017     GNUNET_assert (NULL != hc->infix);
   2018     gorc = GNUNET_new (struct GetOrderRequestContext);
   2019     hc->cc = &gorc_cleanup;
   2020     hc->ctx = gorc;
   2021     gorc->sc.con = connection;
   2022     gorc->hc = hc;
   2023     gorc->wire_details = json_array ();
   2024     GNUNET_assert (NULL != gorc->wire_details);
   2025     gorc->refund_details = json_array ();
   2026     GNUNET_assert (NULL != gorc->refund_details);
   2027     gorc->refunds_external = json_array ();
   2028     GNUNET_assert (NULL != gorc->refunds_external);
   2029     gorc->session_id = MHD_lookup_connection_value (connection,
   2030                                                     MHD_GET_ARGUMENT_KIND,
   2031                                                     "session_id");
   2032     if (! (TALER_MHD_arg_to_yna (connection,
   2033                                  "allow_refunded_for_repurchase",
   2034                                  TALER_EXCHANGE_YNA_NO,
   2035                                  &gorc->allow_refunded_for_repurchase)) )
   2036       return TALER_MHD_reply_with_error (connection,
   2037                                          MHD_HTTP_BAD_REQUEST,
   2038                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
   2039                                          "allow_refunded_for_repurchase");
   2040     TALER_MHD_parse_request_timeout (connection,
   2041                                      &gorc->sc.long_poll_timeout);
   2042     TALER_MHD_parse_request_arg_auto (connection,
   2043                                       "lp_not_etag",
   2044                                       &gorc->lp_not_etag,
   2045                                       gorc->have_lp_not_etag);
   2046     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   2047                 "Starting GET /private/orders/%s processing with timeout %s\n",
   2048                 hc->infix,
   2049                 GNUNET_STRINGS_absolute_time_to_string (
   2050                   gorc->sc.long_poll_timeout));
   2051   }
   2052   if (GNUNET_SYSERR == gorc->suspended)
   2053     return MHD_NO; /* we are in shutdown */
   2054   while (1)
   2055   {
   2056     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2057                 "Processing order %s in phase %d\n",
   2058                 hc->infix,
   2059                 (int) gorc->phase);
   2060     switch (gorc->phase)
   2061     {
   2062     case GOP_INIT:
   2063       phase_init (gorc);
   2064       break;
   2065     case GOP_FETCH_CONTRACT:
   2066       phase_fetch_contract (gorc);
   2067       break;
   2068     case GOP_PARSE_CONTRACT:
   2069       phase_parse_contract (gorc);
   2070       break;
   2071     case GOP_CHECK_PAID:
   2072       phase_check_paid (gorc);
   2073       break;
   2074     case GOP_CHECK_REPURCHASE:
   2075       phase_check_repurchase (gorc);
   2076       break;
   2077     case GOP_UNPAID_FINISH:
   2078       phase_unpaid_finish (gorc);
   2079       break;
   2080     case GOP_CHECK_DEPOSITS:
   2081       phase_check_deposits (gorc);
   2082       break;
   2083     case GOP_CHECK_REFUNDS:
   2084       phase_check_refunds (gorc);
   2085       break;
   2086     case GOP_CHECK_LOCAL_TRANSFERS:
   2087       phase_check_local_transfers (gorc);
   2088       break;
   2089     case GOP_REPLY_RESULT:
   2090       phase_reply_result (gorc);
   2091       break;
   2092     case GOP_ERROR:
   2093       phase_error (gorc);
   2094       break;
   2095     case GOP_SUSPENDED_ON_UNPAID:
   2096       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2097                   "Suspending order request awaiting payment\n");
   2098       return MHD_YES;
   2099     case GOP_END_YES:
   2100       return MHD_YES;
   2101     case GOP_END_NO:
   2102       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2103                   "Closing connection, no response generated\n");
   2104       return MHD_NO;
   2105     }
   2106   } /* end first-time per-request initialization */
   2107 }