merchant

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

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


      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_break (gorc->order_only);
    920       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    921                   "Choice index %i is invalid",
    922                   gorc->choice_index);
    923     }
    924     break;
    925   default:
    926     {
    927       GNUNET_break (0);
    928       phase_end (gorc,
    929                  TALER_MHD_reply_with_error (
    930                    gorc->sc.con,
    931                    MHD_HTTP_INTERNAL_SERVER_ERROR,
    932                    TALER_EC_MERCHANT_GET_ORDERS_ID_INVALID_CONTRACT_VERSION,
    933                    NULL));
    934       return;
    935     }
    936   }
    937 
    938   if ( (NULL != gorc->contract_terms) &&
    939        (GNUNET_OK !=
    940         TALER_JSON_contract_hash (gorc->contract_terms_json,
    941                                   &gorc->h_contract_terms)) )
    942   {
    943     GNUNET_break (0);
    944     phase_end (gorc,
    945                TALER_MHD_reply_with_error (gorc->sc.con,
    946                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
    947                                            TALER_EC_GENERIC_FAILED_COMPUTE_JSON_HASH,
    948                                            NULL));
    949     return;
    950   }
    951   GNUNET_assert ( (NULL != gorc->contract_terms_json) ||
    952                   (NULL != gorc->order_json) );
    953   GNUNET_assert ( (NULL != gorc->pc) ||
    954                   (NULL != gorc->order) );
    955   gorc->phase++;
    956 }
    957 
    958 
    959 /**
    960  * Check payment status of the order.
    961  *
    962  * @param[in,out] gorc order context to update
    963  */
    964 static void
    965 phase_check_paid (struct GetOrderRequestContext *gorc)
    966 {
    967   struct TMH_HandlerContext *hc = gorc->hc;
    968 
    969   if (gorc->order_only)
    970   {
    971     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    972                 "Order %s unclaimed, no need to lookup payment status\n",
    973                 hc->infix);
    974     GNUNET_assert (! gorc->paid);
    975     GNUNET_assert (! gorc->wired);
    976     gorc->phase++;
    977     return;
    978   }
    979   if (NULL == gorc->session_id)
    980   {
    981     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    982                 "No session ID, do not need to lookup session-ID specific payment status (%s/%s)\n",
    983                 gorc->paid ? "paid" : "unpaid",
    984                 gorc->wired ? "wired" : "unwired");
    985     gorc->phase++;
    986     return;
    987   }
    988   if (! gorc->paid_session_matches)
    989   {
    990     gorc->paid = false;
    991     gorc->wired = false;
    992   }
    993   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    994               "Order %s %s for session %s (%s)\n",
    995               hc->infix,
    996               gorc->paid ? "paid" : "unpaid",
    997               gorc->session_id,
    998               gorc->wired ? "wired" : "unwired");
    999   gorc->phase++;
   1000 }
   1001 
   1002 
   1003 /**
   1004  * Check if the @a reply satisfies the long-poll not_etag
   1005  * constraint. If so, return it as a response for @a gorc,
   1006  * otherwise suspend and wait for a change.
   1007  *
   1008  * @param[in,out] gorc request to handle
   1009  * @param reply body for JSON response (#MHD_HTTP_OK)
   1010  */
   1011 static void
   1012 check_reply (struct GetOrderRequestContext *gorc,
   1013              const json_t *reply)
   1014 {
   1015   struct GNUNET_ShortHashCode sh;
   1016   unsigned int http_response_code;
   1017   bool not_modified;
   1018   struct MHD_Response *response;
   1019   char *can;
   1020 
   1021   can = TALER_JSON_canonicalize (reply);
   1022   GNUNET_assert (GNUNET_YES ==
   1023                  GNUNET_CRYPTO_hkdf_gnunet (&sh,
   1024                                             sizeof (sh),
   1025                                             "GOR-SALT",
   1026                                             strlen ("GOR-SALT"),
   1027                                             can,
   1028                                             strlen (can)));
   1029   not_modified = gorc->have_lp_not_etag &&
   1030                  (0 == GNUNET_memcmp (&sh,
   1031                                       &gorc->lp_not_etag));
   1032 
   1033   if (not_modified &&
   1034       (! GNUNET_TIME_absolute_is_past (gorc->sc.long_poll_timeout)) )
   1035   {
   1036     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1037                 "Status unchanged, not returning response yet\n");
   1038     GNUNET_assert (GNUNET_NO == gorc->suspended);
   1039     if (gorc->instant_retry)
   1040     {
   1041       gorc->instant_retry = false;
   1042       gorc->phase = GOP_FETCH_CONTRACT;
   1043       GNUNET_free (can);
   1044       return;
   1045     }
   1046     /* note: not necessarily actually unpaid ... */
   1047     GNUNET_CONTAINER_DLL_insert (gorc_head,
   1048                                  gorc_tail,
   1049                                  gorc);
   1050     gorc->phase = GOP_SUSPENDED_ON_UNPAID;
   1051     gorc->suspended = GNUNET_YES;
   1052     MHD_suspend_connection (gorc->sc.con);
   1053     GNUNET_free (can);
   1054     return;
   1055   }
   1056   {
   1057     const char *inm;
   1058 
   1059     inm = MHD_lookup_connection_value (gorc->sc.con,
   1060                                        MHD_HEADER_KIND,
   1061                                        MHD_HTTP_HEADER_IF_NONE_MATCH);
   1062     if ( (NULL == inm) ||
   1063          ('"' != inm[0]) ||
   1064          ('"' != inm[strlen (inm) - 1]) ||
   1065          (0 != strncmp (inm + 1,
   1066                         can,
   1067                         strlen (can))) )
   1068       not_modified = false; /* must return full response */
   1069   }
   1070   GNUNET_free (can);
   1071   http_response_code = not_modified
   1072     ? MHD_HTTP_NOT_MODIFIED
   1073     : MHD_HTTP_OK;
   1074   response = TALER_MHD_make_json (reply);
   1075   {
   1076     char *etag;
   1077     char *qetag;
   1078 
   1079     etag = GNUNET_STRINGS_data_to_string_alloc (&sh,
   1080                                                 sizeof (sh));
   1081     GNUNET_asprintf (&qetag,
   1082                      "\"%s\"",
   1083                      etag);
   1084     GNUNET_break (MHD_YES ==
   1085                   MHD_add_response_header (response,
   1086                                            MHD_HTTP_HEADER_ETAG,
   1087                                            qetag));
   1088     GNUNET_free (qetag);
   1089     GNUNET_free (etag);
   1090   }
   1091 
   1092   {
   1093     enum MHD_Result ret;
   1094 
   1095     ret = MHD_queue_response (gorc->sc.con,
   1096                               http_response_code,
   1097                               response);
   1098     MHD_destroy_response (response);
   1099     phase_end (gorc,
   1100                ret);
   1101   }
   1102 }
   1103 
   1104 
   1105 /**
   1106  * Check if re-purchase detection applies to the order.
   1107  *
   1108  * @param[in,out] gorc order context to update
   1109  */
   1110 static void
   1111 phase_check_repurchase (struct GetOrderRequestContext *gorc)
   1112 {
   1113   struct TMH_HandlerContext *hc = gorc->hc;
   1114   char *already_paid_order_id = NULL;
   1115   enum GNUNET_DB_QueryStatus qs;
   1116   char *taler_pay_uri;
   1117   char *order_status_url;
   1118   json_t *reply;
   1119 
   1120   if ( (gorc->paid) ||
   1121        (NULL == gorc->ct->fulfillment_url) ||
   1122        (NULL == gorc->session_id) )
   1123   {
   1124     /* Repurchase cannot apply */
   1125     gorc->phase++;
   1126     return;
   1127   }
   1128   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1129               "Running re-purchase detection for %s/%s\n",
   1130               gorc->session_id,
   1131               gorc->ct->fulfillment_url);
   1132   qs = TALER_MERCHANTDB_get_order_by_fulfillment (
   1133     TMH_db,
   1134     hc->instance->settings.id,
   1135     gorc->ct->fulfillment_url,
   1136     gorc->session_id,
   1137     TALER_EXCHANGE_YNA_NO !=
   1138     gorc->allow_refunded_for_repurchase,
   1139     &already_paid_order_id);
   1140   if (0 > qs)
   1141   {
   1142     /* single, read-only SQL statements should never cause
   1143        serialization problems, and the entry should exist as per above */
   1144     GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs);
   1145     phase_end (gorc,
   1146                TALER_MHD_reply_with_error (gorc->sc.con,
   1147                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1148                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1149                                            "order by fulfillment"));
   1150     return;
   1151   }
   1152   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1153   {
   1154     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1155                 "No already paid order for %s/%s\n",
   1156                 gorc->session_id,
   1157                 gorc->ct->fulfillment_url);
   1158     gorc->phase++;
   1159     return;
   1160   }
   1161 
   1162   /* User did pay for this order, but under a different session; ask wallet to
   1163      switch order ID */
   1164   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1165               "Found already paid order %s\n",
   1166               already_paid_order_id);
   1167   taler_pay_uri = TMH_make_taler_pay_uri (gorc->sc.con,
   1168                                           hc->infix,
   1169                                           gorc->session_id,
   1170                                           hc->instance->settings.id,
   1171                                           &gorc->claim_token);
   1172   order_status_url = TMH_make_order_status_url (gorc->sc.con,
   1173                                                 hc->infix,
   1174                                                 gorc->session_id,
   1175                                                 hc->instance->settings.id,
   1176                                                 &gorc->claim_token,
   1177                                                 NULL);
   1178   if ( (NULL == taler_pay_uri) ||
   1179        (NULL == order_status_url) )
   1180   {
   1181     GNUNET_break_op (0);
   1182     GNUNET_free (taler_pay_uri);
   1183     GNUNET_free (order_status_url);
   1184     phase_end (gorc,
   1185                TALER_MHD_reply_with_error (gorc->sc.con,
   1186                                            MHD_HTTP_BAD_REQUEST,
   1187                                            TALER_EC_GENERIC_HTTP_HEADERS_MALFORMED,
   1188                                            "host"));
   1189     return;
   1190   }
   1191   reply = GNUNET_JSON_PACK (
   1192     GNUNET_JSON_pack_string ("taler_pay_uri",
   1193                              taler_pay_uri),
   1194     GNUNET_JSON_pack_string ("order_status_url",
   1195                              order_status_url),
   1196     GNUNET_JSON_pack_string ("order_status",
   1197                              "unpaid"),
   1198     GNUNET_JSON_pack_string ("already_paid_order_id",
   1199                              already_paid_order_id),
   1200     GNUNET_JSON_pack_string ("already_paid_fulfillment_url",
   1201                              gorc->ct->fulfillment_url),
   1202     /* undefined for unpaid v1 contracts */
   1203     GNUNET_JSON_pack_allow_null (
   1204       TALER_JSON_pack_amount ("total_amount",
   1205                               TALER_amount_is_valid (&gorc->contract_amount)
   1206                               ? &gorc->contract_amount
   1207                               : NULL)),
   1208     GNUNET_JSON_pack_object_incref ("proto_contract_terms",
   1209                                     gorc->contract_terms_json),
   1210     GNUNET_JSON_pack_string ("summary",
   1211                              gorc->ct->summary),
   1212     GNUNET_JSON_pack_timestamp ("pay_deadline",
   1213                                 NULL != gorc->pc
   1214                                 ? gorc->pc->pay_deadline
   1215                                 : gorc->order->pay_deadline),
   1216     GNUNET_JSON_pack_timestamp ("creation_time",
   1217                                 gorc->timestamp));
   1218 
   1219   GNUNET_free (order_status_url);
   1220   GNUNET_free (taler_pay_uri);
   1221   GNUNET_free (already_paid_order_id);
   1222   check_reply (gorc,
   1223                reply);
   1224   json_decref (reply);
   1225 }
   1226 
   1227 
   1228 /**
   1229  * Check if we should suspend until the order is paid.
   1230  *
   1231  * @param[in,out] gorc order context to update
   1232  */
   1233 static void
   1234 phase_unpaid_finish (struct GetOrderRequestContext *gorc)
   1235 {
   1236   struct TMH_HandlerContext *hc = gorc->hc;
   1237   char *order_status_url;
   1238 
   1239   if (gorc->paid)
   1240   {
   1241     gorc->phase++;
   1242     return;
   1243   }
   1244   /* User never paid for this order, suspend waiting
   1245      on payment or return details. */
   1246   if (GNUNET_TIME_absolute_is_future (gorc->sc.long_poll_timeout) &&
   1247       (! gorc->have_lp_not_etag) )
   1248   {
   1249     if (gorc->instant_retry)
   1250     {
   1251       gorc->instant_retry = false;
   1252       gorc->phase = GOP_FETCH_CONTRACT;
   1253       return;
   1254     }
   1255     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1256                 "Suspending GET /private/orders/%s\n",
   1257                 hc->infix);
   1258     GNUNET_CONTAINER_DLL_insert (gorc_head,
   1259                                  gorc_tail,
   1260                                  gorc);
   1261     gorc->phase = GOP_SUSPENDED_ON_UNPAID;
   1262     gorc->suspended = GNUNET_YES;
   1263     MHD_suspend_connection (gorc->sc.con);
   1264     return;
   1265   }
   1266   order_status_url = TMH_make_order_status_url (gorc->sc.con,
   1267                                                 hc->infix,
   1268                                                 gorc->session_id,
   1269                                                 hc->instance->settings.id,
   1270                                                 &gorc->claim_token,
   1271                                                 NULL);
   1272   if (! gorc->order_only)
   1273   {
   1274     json_t *reply;
   1275 
   1276     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1277                 "Order %s claimed but not paid yet\n",
   1278                 hc->infix);
   1279     reply = GNUNET_JSON_PACK (
   1280       GNUNET_JSON_pack_string ("order_status_url",
   1281                                order_status_url),
   1282       GNUNET_JSON_pack_object_incref ("contract_terms",
   1283                                       gorc->contract_terms_json),
   1284       GNUNET_JSON_pack_string ("order_status",
   1285                                "claimed"));
   1286     GNUNET_free (order_status_url);
   1287     check_reply (gorc,
   1288                  reply);
   1289     json_decref (reply);
   1290     return;
   1291   }
   1292   {
   1293     char *taler_pay_uri;
   1294     json_t *reply;
   1295 
   1296     taler_pay_uri = TMH_make_taler_pay_uri (gorc->sc.con,
   1297                                             hc->infix,
   1298                                             gorc->session_id,
   1299                                             hc->instance->settings.id,
   1300                                             &gorc->claim_token);
   1301     reply = GNUNET_JSON_PACK (
   1302       GNUNET_JSON_pack_string ("taler_pay_uri",
   1303                                taler_pay_uri),
   1304       GNUNET_JSON_pack_string ("order_status_url",
   1305                                order_status_url),
   1306       GNUNET_JSON_pack_string ("order_status",
   1307                                "unpaid"),
   1308       GNUNET_JSON_pack_object_incref ("proto_contract_terms",
   1309                                       gorc->contract_terms_json),
   1310       /* undefined for unpaid v1 contracts */
   1311       GNUNET_JSON_pack_allow_null (
   1312         TALER_JSON_pack_amount ("total_amount",
   1313                                 &gorc->contract_amount)),
   1314       GNUNET_JSON_pack_string ("summary",
   1315                                gorc->ct->summary),
   1316       GNUNET_JSON_pack_timestamp ("creation_time",
   1317                                   gorc->timestamp));
   1318     check_reply (gorc,
   1319                  reply);
   1320     json_decref (reply);
   1321     GNUNET_free (taler_pay_uri);
   1322   }
   1323   GNUNET_free (order_status_url);
   1324 }
   1325 
   1326 
   1327 /**
   1328  * Function called with each @a coin_pub that was deposited into the
   1329  * @a h_wire account of the merchant for the @a deposit_serial as part
   1330  * of the payment for the order identified by @a cls.
   1331  *
   1332  * Queries the exchange for the payment status associated with the
   1333  * given coin.
   1334  *
   1335  * @param cls a `struct GetOrderRequestContext`
   1336  * @param deposit_serial identifies the deposit operation
   1337  * @param exchange_url URL of the exchange that issued @a coin_pub
   1338  * @param h_wire hash of the merchant's wire account into which the deposit was made
   1339  * @param deposit_timestamp when was the deposit made
   1340  * @param amount_with_fee amount the exchange will deposit for this coin
   1341  * @param deposit_fee fee the exchange will charge for this coin
   1342  * @param coin_pub public key of the deposited coin
   1343  */
   1344 static void
   1345 deposit_cb (
   1346   void *cls,
   1347   uint64_t deposit_serial,
   1348   const char *exchange_url,
   1349   const struct TALER_MerchantWireHashP *h_wire,
   1350   struct GNUNET_TIME_Timestamp deposit_timestamp,
   1351   const struct TALER_Amount *amount_with_fee,
   1352   const struct TALER_Amount *deposit_fee,
   1353   const struct TALER_CoinSpendPublicKeyP *coin_pub)
   1354 {
   1355   struct GetOrderRequestContext *gorc = cls;
   1356   struct TransferQuery *tq;
   1357 
   1358   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1359               "Checking deposit status for coin %s (over %s)\n",
   1360               TALER_B2S (coin_pub),
   1361               TALER_amount2s (amount_with_fee));
   1362   gorc->last_payment
   1363     = GNUNET_TIME_timestamp_max (gorc->last_payment,
   1364                                  deposit_timestamp);
   1365   tq = GNUNET_new (struct TransferQuery);
   1366   tq->gorc = gorc;
   1367   tq->exchange_url = GNUNET_strdup (exchange_url);
   1368   tq->deposit_serial = deposit_serial;
   1369   GNUNET_CONTAINER_DLL_insert (gorc->tq_head,
   1370                                gorc->tq_tail,
   1371                                tq);
   1372   tq->coin_pub = *coin_pub;
   1373   tq->h_wire = *h_wire;
   1374   tq->amount_with_fee = *amount_with_fee;
   1375   tq->deposit_fee = *deposit_fee;
   1376 }
   1377 
   1378 
   1379 /**
   1380  * Check wire transfer status for the order at the exchange.
   1381  *
   1382  * @param[in,out] gorc order context to update
   1383  */
   1384 static void
   1385 phase_check_deposits (struct GetOrderRequestContext *gorc)
   1386 {
   1387   GNUNET_assert (! gorc->order_only);
   1388   GNUNET_assert (gorc->paid);
   1389 
   1390   /* amount must be always valid for paid orders */
   1391   GNUNET_assert (GNUNET_OK ==
   1392                  TALER_amount_is_valid (&gorc->contract_amount));
   1393 
   1394   GNUNET_assert (GNUNET_OK ==
   1395                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1396                                         &gorc->deposits_total));
   1397   GNUNET_assert (GNUNET_OK ==
   1398                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1399                                         &gorc->deposit_fees_total));
   1400   GNUNET_assert (GNUNET_OK ==
   1401                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1402                                         &gorc->deposit_fees_refunded_total));
   1403   TALER_MERCHANTDB_iterate_deposits_by_order (TMH_db,
   1404                                               gorc->order_serial,
   1405                                               &deposit_cb,
   1406                                               gorc);
   1407   gorc->phase++;
   1408 }
   1409 
   1410 
   1411 /**
   1412  * Function called with information about a refund.
   1413  * It is responsible for summing up the refund amount.
   1414  *
   1415  * @param cls closure
   1416  * @param refund_serial unique serial number of the refund
   1417  * @param timestamp time of the refund (for grouping of refunds in the wallet UI)
   1418  * @param coin_pub public coin from which the refund comes from
   1419  * @param exchange_url URL of the exchange that issued @a coin_pub
   1420  * @param rtransaction_id identificator of the refund
   1421  * @param reason human-readable explanation of the refund
   1422  * @param refund_amount refund amount which is being taken from @a coin_pub
   1423  * @param pending true if the this refund was not yet processed by the wallet/exchange
   1424  */
   1425 static void
   1426 process_refunds_cb (
   1427   void *cls,
   1428   uint64_t refund_serial,
   1429   struct GNUNET_TIME_Timestamp timestamp,
   1430   const struct TALER_CoinSpendPublicKeyP *coin_pub,
   1431   const char *exchange_url,
   1432   uint64_t rtransaction_id,
   1433   const char *reason,
   1434   const struct TALER_Amount *refund_amount,
   1435   bool pending)
   1436 {
   1437   struct GetOrderRequestContext *gorc = cls;
   1438 
   1439   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1440               "Found refund %llu over %s for reason %s\n",
   1441               (unsigned long long) rtransaction_id,
   1442               TALER_amount2s (refund_amount),
   1443               reason);
   1444   GNUNET_assert (
   1445     0 ==
   1446     json_array_append_new (
   1447       gorc->refund_details,
   1448       GNUNET_JSON_PACK (
   1449         TALER_JSON_pack_amount ("amount",
   1450                                 refund_amount),
   1451         GNUNET_JSON_pack_bool ("pending",
   1452                                pending),
   1453         GNUNET_JSON_pack_timestamp ("timestamp",
   1454                                     timestamp),
   1455         GNUNET_JSON_pack_string ("reason",
   1456                                  reason))));
   1457   /* For refunded coins, we are not charged deposit fees, so subtract those
   1458      again */
   1459   for (struct TransferQuery *tq = gorc->tq_head;
   1460        NULL != tq;
   1461        tq = tq->next)
   1462   {
   1463     if (0 !=
   1464         strcmp (exchange_url,
   1465                 tq->exchange_url))
   1466       continue;
   1467     if (0 !=
   1468         GNUNET_memcmp (&tq->coin_pub,
   1469                        coin_pub))
   1470       continue;
   1471     if (GNUNET_OK !=
   1472         TALER_amount_cmp_currency (
   1473           &gorc->deposit_fees_total,
   1474           &tq->deposit_fee))
   1475     {
   1476       gorc->refund_currency_mismatch = true;
   1477       return;
   1478     }
   1479     GNUNET_assert (
   1480       0 <=
   1481       TALER_amount_add (&gorc->deposit_fees_refunded_total,
   1482                         &gorc->deposit_fees_refunded_total,
   1483                         &tq->deposit_fee));
   1484   }
   1485   if (GNUNET_OK !=
   1486       TALER_amount_cmp_currency (
   1487         &gorc->refund_amount,
   1488         refund_amount))
   1489   {
   1490     gorc->refund_currency_mismatch = true;
   1491     return;
   1492   }
   1493   GNUNET_assert (0 <=
   1494                  TALER_amount_add (&gorc->refund_amount,
   1495                                    &gorc->refund_amount,
   1496                                    refund_amount));
   1497   gorc->refunded = true;
   1498   gorc->refund_pending |= pending;
   1499 }
   1500 
   1501 
   1502 /**
   1503  * Function called with information about an external refund.
   1504  * Appends the refund entry to the "refunds_external" array.
   1505  *
   1506  * @param cls a `struct GetOrderRequestContext`
   1507  * @param refund_id identifier of the refund within the order
   1508  * @param refund_timestamp when was the refund recorded
   1509  * @param method external payment method used for the refund
   1510  * @param payment_id id of the original external payment entry
   1511  * @param amount amount returned to the customer
   1512  * @param reason human-readable refund justification
   1513  */
   1514 static void
   1515 process_external_refunds_cb (void *cls,
   1516                              const char *refund_id,
   1517                              struct GNUNET_TIME_Timestamp refund_timestamp,
   1518                              const char *method,
   1519                              const char *payment_id,
   1520                              const struct TALER_Amount *amount,
   1521                              const char *reason)
   1522 {
   1523   struct GetOrderRequestContext *gorc = cls;
   1524 
   1525   GNUNET_assert (
   1526     0 ==
   1527     json_array_append_new (
   1528       gorc->refunds_external,
   1529       GNUNET_JSON_PACK (
   1530         GNUNET_JSON_pack_string ("id",
   1531                                  refund_id),
   1532         GNUNET_JSON_pack_string ("method",
   1533                                  method),
   1534         GNUNET_JSON_pack_allow_null (
   1535           GNUNET_JSON_pack_string ("payment_id",
   1536                                    payment_id)),
   1537         TALER_JSON_pack_amount ("amount",
   1538                                 amount),
   1539         GNUNET_JSON_pack_string ("reason",
   1540                                  reason),
   1541         GNUNET_JSON_pack_timestamp ("timestamp",
   1542                                     refund_timestamp))));
   1543 }
   1544 
   1545 
   1546 /**
   1547  * Check refund status for the order.
   1548  *
   1549  * @param[in,out] gorc order context to update
   1550  */
   1551 static void
   1552 phase_check_refunds (struct GetOrderRequestContext *gorc)
   1553 {
   1554   struct TMH_HandlerContext *hc = gorc->hc;
   1555   enum GNUNET_DB_QueryStatus qs;
   1556 
   1557   GNUNET_assert (! gorc->order_only);
   1558   GNUNET_assert (gorc->paid);
   1559 
   1560   /* Accumulate refunds, if any. */
   1561   GNUNET_assert (GNUNET_OK ==
   1562                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1563                                         &gorc->refund_amount));
   1564   json_array_clear (gorc->refund_details);
   1565   qs = TALER_MERCHANTDB_iterate_refunds_detailed (
   1566     TMH_db,
   1567     hc->instance->settings.id,
   1568     &gorc->h_contract_terms,
   1569     &process_refunds_cb,
   1570     gorc);
   1571   if (0 > qs)
   1572   {
   1573     GNUNET_break (0);
   1574     phase_end (gorc,
   1575                TALER_MHD_reply_with_error (
   1576                  gorc->sc.con,
   1577                  MHD_HTTP_INTERNAL_SERVER_ERROR,
   1578                  TALER_EC_GENERIC_DB_FETCH_FAILED,
   1579                  "detailed refunds"));
   1580     return;
   1581   }
   1582   if (gorc->refund_currency_mismatch)
   1583   {
   1584     GNUNET_break (0);
   1585     phase_end (gorc,
   1586                TALER_MHD_reply_with_error (
   1587                  gorc->sc.con,
   1588                  MHD_HTTP_INTERNAL_SERVER_ERROR,
   1589                  TALER_EC_GENERIC_DB_FETCH_FAILED,
   1590                  "refunds in different currency than original order price"));
   1591     return;
   1592   }
   1593   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1594               "Total refunds are %s\n",
   1595               TALER_amount2s (&gorc->refund_amount));
   1596   json_array_clear (gorc->refunds_external);
   1597   qs = TALER_MERCHANTDB_iterate_external_refunds (
   1598     TMH_db,
   1599     hc->instance->settings.id,
   1600     hc->infix,
   1601     &process_external_refunds_cb,
   1602     gorc);
   1603   if (0 > qs)
   1604   {
   1605     GNUNET_break (0);
   1606     phase_end (gorc,
   1607                TALER_MHD_reply_with_error (
   1608                  gorc->sc.con,
   1609                  MHD_HTTP_INTERNAL_SERVER_ERROR,
   1610                  TALER_EC_GENERIC_DB_FETCH_FAILED,
   1611                  "external refunds"));
   1612     return;
   1613   }
   1614   gorc->phase++;
   1615 }
   1616 
   1617 
   1618 /**
   1619  * Function called with available wire details, to be added to
   1620  * the response.
   1621  *
   1622  * @param cls a `struct GetOrderRequestContext`
   1623  * @param wtid wire transfer subject of the wire transfer for the coin
   1624  * @param exchange_url base URL of the exchange that made the payment
   1625  * @param execution_time when was the payment made
   1626  * @param deposit_value contribution of the coin to the total wire transfer value
   1627  * @param deposit_fee deposit fee charged by the exchange for the coin
   1628  * @param transfer_confirmed did the merchant confirm that a wire transfer with
   1629  *        @a wtid over the total amount happened?
   1630  * @param expected_credit_serial row for the expected wire transfer this
   1631  *   entry references
   1632  */
   1633 static void
   1634 process_transfer_details (
   1635   void *cls,
   1636   const struct TALER_WireTransferIdentifierRawP *wtid,
   1637   const char *exchange_url,
   1638   struct GNUNET_TIME_Timestamp execution_time,
   1639   const struct TALER_Amount *deposit_value,
   1640   const struct TALER_Amount *deposit_fee,
   1641   bool transfer_confirmed,
   1642   uint64_t expected_credit_serial)
   1643 {
   1644   struct GetOrderRequestContext *gorc = cls;
   1645   json_t *wire_details = gorc->wire_details;
   1646   struct TALER_Amount wired;
   1647 
   1648   if ( (GNUNET_OK !=
   1649         TALER_amount_cmp_currency (&gorc->deposits_total,
   1650                                    deposit_value)) ||
   1651        (GNUNET_OK !=
   1652         TALER_amount_cmp_currency (&gorc->deposit_fees_total,
   1653                                    deposit_fee)) )
   1654   {
   1655     GNUNET_break (0);
   1656     gorc->deposit_currency_mismatch = true;
   1657     return;
   1658   }
   1659 
   1660   /* Compute total amount *wired* */
   1661   GNUNET_assert (0 <=
   1662                  TALER_amount_add (&gorc->deposits_total,
   1663                                    &gorc->deposits_total,
   1664                                    deposit_value));
   1665   GNUNET_assert (0 <=
   1666                  TALER_amount_add (&gorc->deposit_fees_total,
   1667                                    &gorc->deposit_fees_total,
   1668                                    deposit_fee));
   1669   GNUNET_assert (0 <= TALER_amount_subtract (&wired,
   1670                                              deposit_value,
   1671                                              deposit_fee));
   1672   GNUNET_assert (0 ==
   1673                  json_array_append_new (
   1674                    wire_details,
   1675                    GNUNET_JSON_PACK (
   1676                      GNUNET_JSON_pack_data_auto ("wtid",
   1677                                                  wtid),
   1678                      GNUNET_JSON_pack_string ("exchange_url",
   1679                                               exchange_url),
   1680                      TALER_JSON_pack_amount ("amount",
   1681                                              &wired),
   1682                      TALER_JSON_pack_amount ("deposit_fee",
   1683                                              deposit_fee),
   1684                      GNUNET_JSON_pack_timestamp ("execution_time",
   1685                                                  execution_time),
   1686                      GNUNET_JSON_pack_bool ("confirmed",
   1687                                             transfer_confirmed),
   1688                      GNUNET_JSON_pack_uint64 ("expected_transfer_serial_id",
   1689                                               expected_credit_serial))));
   1690 }
   1691 
   1692 
   1693 /**
   1694  * Check transfer status in local database.
   1695  *
   1696  * @param[in,out] gorc order context to update
   1697  */
   1698 static void
   1699 phase_check_local_transfers (struct GetOrderRequestContext *gorc)
   1700 {
   1701   struct TMH_HandlerContext *hc = gorc->hc;
   1702   enum GNUNET_DB_QueryStatus qs;
   1703 
   1704   GNUNET_assert (gorc->paid);
   1705   GNUNET_assert (! gorc->order_only);
   1706 
   1707   GNUNET_assert (GNUNET_OK ==
   1708                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1709                                         &gorc->deposits_total));
   1710   GNUNET_assert (GNUNET_OK ==
   1711                  TALER_amount_set_zero (gorc->contract_amount.currency,
   1712                                         &gorc->deposit_fees_total));
   1713   GNUNET_assert (NULL != gorc->wire_details);
   1714   /* We may be running again due to long-polling, clear state first */
   1715   json_array_clear (gorc->wire_details);
   1716   qs = TALER_MERCHANTDB_iterate_transfer_details_by_order (TMH_db,
   1717                                                            gorc->order_serial,
   1718                                                            &process_transfer_details,
   1719                                                            gorc);
   1720   if (0 > qs)
   1721   {
   1722     GNUNET_break (0);
   1723     phase_end (gorc,
   1724                TALER_MHD_reply_with_error (gorc->sc.con,
   1725                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1726                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1727                                            "transfer details"));
   1728     return;
   1729   }
   1730   if (gorc->deposit_currency_mismatch)
   1731   {
   1732     GNUNET_break (0);
   1733     phase_end (gorc,
   1734                TALER_MHD_reply_with_error (gorc->sc.con,
   1735                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1736                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1737                                            "deposits in different currency than original order price"));
   1738     return;
   1739   }
   1740 
   1741   if (! gorc->wired)
   1742   {
   1743     /* we believe(d) the wire transfer did not happen yet, check if maybe
   1744        in light of new evidence it did */
   1745     struct TALER_Amount expect_total;
   1746 
   1747     if (0 >
   1748         TALER_amount_subtract (&expect_total,
   1749                                &gorc->contract_amount,
   1750                                &gorc->refund_amount))
   1751     {
   1752       GNUNET_break (0);
   1753       phase_end (gorc,
   1754                  TALER_MHD_reply_with_error (
   1755                    gorc->sc.con,
   1756                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1757                    TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
   1758                    "refund exceeds contract value"));
   1759       return;
   1760     }
   1761     GNUNET_assert (
   1762       0 <=
   1763       TALER_amount_add (&expect_total,
   1764                         &expect_total,
   1765                         &gorc->deposit_fees_refunded_total));
   1766 
   1767     if (0 >
   1768         TALER_amount_subtract (&expect_total,
   1769                                &expect_total,
   1770                                &gorc->deposit_fees_total))
   1771     {
   1772       GNUNET_break (0);
   1773       phase_end (gorc,
   1774                  TALER_MHD_reply_with_error (
   1775                    gorc->sc.con,
   1776                    MHD_HTTP_INTERNAL_SERVER_ERROR,
   1777                    TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
   1778                    "deposit fees exceed total minus refunds"));
   1779       return;
   1780     }
   1781     if (0 >=
   1782         TALER_amount_cmp (&expect_total,
   1783                           &gorc->deposits_total))
   1784     {
   1785       /* expect_total <= gorc->deposits_total: good: we got the wire transfer */
   1786       gorc->wired = true;
   1787       qs = TALER_MERCHANTDB_update_to_contract_terms_wired (TMH_db,
   1788                                                             gorc->order_serial);
   1789       GNUNET_break (qs >= 0);   /* just warn if transaction failed */
   1790       TMH_notify_order_change (hc->instance,
   1791                                TMH_OSF_PAID
   1792                                | TMH_OSF_WIRED,
   1793                                gorc->timestamp,
   1794                                gorc->order_serial);
   1795     }
   1796   }
   1797   gorc->phase++;
   1798 }
   1799 
   1800 
   1801 /**
   1802  * Generate final result for the status request.
   1803  *
   1804  * @param[in,out] gorc order context to update
   1805  */
   1806 static void
   1807 phase_reply_result (struct GetOrderRequestContext *gorc)
   1808 {
   1809   struct TMH_HandlerContext *hc = gorc->hc;
   1810   char *order_status_url;
   1811 
   1812   GNUNET_assert (gorc->paid);
   1813   GNUNET_assert (! gorc->order_only);
   1814 
   1815   {
   1816     struct TALER_PrivateContractHashP *h_contract = NULL;
   1817 
   1818     /* In a session-bound payment, allow the browser to check the order
   1819      * status page (e.g. to get a refund).
   1820      *
   1821      * Note that we don't allow this outside of session-based payment, as
   1822      * otherwise this becomes an oracle to convert order_id to h_contract.
   1823      */
   1824     if (NULL != gorc->session_id)
   1825       h_contract = &gorc->h_contract_terms;
   1826 
   1827     order_status_url =
   1828       TMH_make_order_status_url (gorc->sc.con,
   1829                                  hc->infix,
   1830                                  gorc->session_id,
   1831                                  hc->instance->settings.id,
   1832                                  &gorc->claim_token,
   1833                                  h_contract);
   1834   }
   1835   if (GNUNET_TIME_absolute_is_zero (gorc->last_payment.abs_time))
   1836   {
   1837     GNUNET_break (GNUNET_YES ==
   1838                   TALER_amount_is_zero (&gorc->contract_amount));
   1839     gorc->last_payment = gorc->timestamp;
   1840   }
   1841   {
   1842     json_t *reply;
   1843 
   1844     reply = GNUNET_JSON_PACK (
   1845       // Deprecated in protocol v6!
   1846       GNUNET_JSON_pack_array_steal ("wire_reports",
   1847                                     json_array ()),
   1848       GNUNET_JSON_pack_uint64 ("exchange_code",
   1849                                gorc->exchange_ec),
   1850       GNUNET_JSON_pack_uint64 ("exchange_http_status",
   1851                                gorc->exchange_hc),
   1852       /* legacy: */
   1853       GNUNET_JSON_pack_uint64 ("exchange_ec",
   1854                                gorc->exchange_ec),
   1855       /* legacy: */
   1856       GNUNET_JSON_pack_uint64 ("exchange_hc",
   1857                                gorc->exchange_hc),
   1858       TALER_JSON_pack_amount ("deposit_total",
   1859                               &gorc->deposits_total),
   1860       GNUNET_JSON_pack_object_incref ("contract_terms",
   1861                                       gorc->contract_terms_json),
   1862       GNUNET_JSON_pack_string ("order_status",
   1863                                "paid"),
   1864       GNUNET_JSON_pack_timestamp ("last_payment",
   1865                                   gorc->last_payment),
   1866       GNUNET_JSON_pack_bool ("refunded",
   1867                              gorc->refunded),
   1868       GNUNET_JSON_pack_bool ("wired",
   1869                              gorc->wired),
   1870       GNUNET_JSON_pack_bool ("refund_pending",
   1871                              gorc->refund_pending),
   1872       GNUNET_JSON_pack_allow_null (
   1873         TALER_JSON_pack_amount ("refund_amount",
   1874                                 &gorc->refund_amount)),
   1875       GNUNET_JSON_pack_array_incref ("wire_details",
   1876                                      gorc->wire_details),
   1877       GNUNET_JSON_pack_array_incref ("refund_details",
   1878                                      gorc->refund_details),
   1879       GNUNET_JSON_pack_array_incref ("refunds_external",
   1880                                      gorc->refunds_external),
   1881       GNUNET_JSON_pack_string ("order_status_url",
   1882                                order_status_url),
   1883       (gorc->choice_index >= 0)
   1884       ? GNUNET_JSON_pack_int64 ("choice_index",
   1885                                 gorc->choice_index)
   1886       : GNUNET_JSON_pack_end_ ());
   1887     check_reply (gorc,
   1888                  reply);
   1889     json_decref (reply);
   1890   }
   1891   GNUNET_free (order_status_url);
   1892 }
   1893 
   1894 
   1895 /**
   1896  * End with error status in wire_hc and wire_ec.
   1897  *
   1898  * @param[in,out] gorc order context to update
   1899  */
   1900 static void
   1901 phase_error (struct GetOrderRequestContext *gorc)
   1902 {
   1903   GNUNET_assert (TALER_EC_NONE != gorc->wire_ec);
   1904   phase_end (gorc,
   1905              TALER_MHD_reply_with_error (gorc->sc.con,
   1906                                          gorc->wire_hc,
   1907                                          gorc->wire_ec,
   1908                                          NULL));
   1909 }
   1910 
   1911 
   1912 enum MHD_Result
   1913 TMH_private_get_orders_ID (
   1914   const struct TMH_RequestHandler *rh,
   1915   struct MHD_Connection *connection,
   1916   struct TMH_HandlerContext *hc)
   1917 {
   1918   struct GetOrderRequestContext *gorc = hc->ctx;
   1919 
   1920   if (NULL == gorc)
   1921   {
   1922     /* First time here, parse request and check order is known */
   1923     GNUNET_assert (NULL != hc->infix);
   1924     gorc = GNUNET_new (struct GetOrderRequestContext);
   1925     hc->cc = &gorc_cleanup;
   1926     hc->ctx = gorc;
   1927     gorc->sc.con = connection;
   1928     gorc->hc = hc;
   1929     gorc->wire_details = json_array ();
   1930     GNUNET_assert (NULL != gorc->wire_details);
   1931     gorc->refund_details = json_array ();
   1932     GNUNET_assert (NULL != gorc->refund_details);
   1933     gorc->refunds_external = json_array ();
   1934     GNUNET_assert (NULL != gorc->refunds_external);
   1935     gorc->session_id = MHD_lookup_connection_value (connection,
   1936                                                     MHD_GET_ARGUMENT_KIND,
   1937                                                     "session_id");
   1938     if (! (TALER_MHD_arg_to_yna (connection,
   1939                                  "allow_refunded_for_repurchase",
   1940                                  TALER_EXCHANGE_YNA_NO,
   1941                                  &gorc->allow_refunded_for_repurchase)) )
   1942       return TALER_MHD_reply_with_error (connection,
   1943                                          MHD_HTTP_BAD_REQUEST,
   1944                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
   1945                                          "allow_refunded_for_repurchase");
   1946     TALER_MHD_parse_request_timeout (connection,
   1947                                      &gorc->sc.long_poll_timeout);
   1948     TALER_MHD_parse_request_arg_auto (connection,
   1949                                       "lp_not_etag",
   1950                                       &gorc->lp_not_etag,
   1951                                       gorc->have_lp_not_etag);
   1952     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
   1953                 "Starting GET /private/orders/%s processing with timeout %s\n",
   1954                 hc->infix,
   1955                 GNUNET_STRINGS_absolute_time_to_string (
   1956                   gorc->sc.long_poll_timeout));
   1957   }
   1958   if (GNUNET_SYSERR == gorc->suspended)
   1959     return MHD_NO; /* we are in shutdown */
   1960   while (1)
   1961   {
   1962     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1963                 "Processing order %s in phase %d\n",
   1964                 hc->infix,
   1965                 (int) gorc->phase);
   1966     switch (gorc->phase)
   1967     {
   1968     case GOP_INIT:
   1969       phase_init (gorc);
   1970       break;
   1971     case GOP_FETCH_CONTRACT:
   1972       phase_fetch_contract (gorc);
   1973       break;
   1974     case GOP_PARSE_CONTRACT:
   1975       phase_parse_contract (gorc);
   1976       break;
   1977     case GOP_CHECK_PAID:
   1978       phase_check_paid (gorc);
   1979       break;
   1980     case GOP_CHECK_REPURCHASE:
   1981       phase_check_repurchase (gorc);
   1982       break;
   1983     case GOP_UNPAID_FINISH:
   1984       phase_unpaid_finish (gorc);
   1985       break;
   1986     case GOP_CHECK_DEPOSITS:
   1987       phase_check_deposits (gorc);
   1988       break;
   1989     case GOP_CHECK_REFUNDS:
   1990       phase_check_refunds (gorc);
   1991       break;
   1992     case GOP_CHECK_LOCAL_TRANSFERS:
   1993       phase_check_local_transfers (gorc);
   1994       break;
   1995     case GOP_REPLY_RESULT:
   1996       phase_reply_result (gorc);
   1997       break;
   1998     case GOP_ERROR:
   1999       phase_error (gorc);
   2000       break;
   2001     case GOP_SUSPENDED_ON_UNPAID:
   2002       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   2003                   "Suspending order request awaiting payment\n");
   2004       return MHD_YES;
   2005     case GOP_END_YES:
   2006       return MHD_YES;
   2007     case GOP_END_NO:
   2008       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   2009                   "Closing connection, no response generated\n");
   2010       return MHD_NO;
   2011     }
   2012   } /* end first-time per-request initialization */
   2013 }