merchant

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

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


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