merchant

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

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


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