cash2ecash

cash2ecash: cash acceptor that issues digital cash (experimental)
Log | Files | Refs | README | LICENSE

bank_api_get_withdrawals.c (8807B)


      1 /*
      2   This file is part of TALER cash2ecash
      3   Copyright (C) 2026 GNUnet e.V.
      4 
      5   This program is free software: you can redistribute it and/or modify
      6   it under the terms of the GNU Affero General Public License as
      7   published by the Free Software Foundation, either version 3 of the
      8   License, or (at your option) any later version.
      9 
     10   This program is distributed in the hope that it will be useful,
     11   but WITHOUT ANY WARRANTY; without even the implied warranty of
     12   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14   GNU Affero General Public License for more details.
     15 
     16   You should have received a copy of the GNU Affero General Public License
     17   along with this program.  If not, see <https://www.gnu.org/licenses/>.
     18 */
     19 /**
     20  * @file bank-lib/bank_api_get_withdrawals.c
     21  * @brief implements the Taler Bank API "GET /withdrawals/$WITHDRAWAL_ID" handler
     22  * @author Reto Tellenbach
     23  */
     24  
     25 #include <microhttpd.h>
     26 #include "taler/taler_json_lib.h"
     27 #include "taler/taler_bank_service.h"
     28 #include "bank_api_get_withdrawals.h"
     29 #include "bank_api_curl_defaults.h"
     30 
     31 /**
     32  * Log error related to CURL operations.
     33  *
     34  * @param type log level
     35  * @param function which function failed to run
     36  * @param code what was the curl error code
     37  */
     38 #define CURL_STRERROR(type, function, code)      \
     39         GNUNET_log (type, \
     40                     "Curl function `%s' has failed at `%s:%d' with error: %s", \
     41                     function, __FILE__, __LINE__, curl_easy_strerror (code));
     42 
     43 /**
     44  * Handle for the accounts request.
     45  */
     46 struct TALER_BANK_GetWithdrawalHandle
     47 {
     48       /**
     49    * The context of this handle
     50    */
     51   struct GNUNET_CURL_Context *ctx;
     52 
     53   /**
     54    * Function to call with the ,
     55    * NULL if this has already been done.
     56    */
     57   TALER_BANK_WithdrawalCallback withdrawals_cb;
     58 
     59   /**
     60    * Closure to pass to
     61    */
     62   void *withdrawals_cb_cls;
     63 
     64   /**
     65    * Data for the request to get the /withdrawals/$WITHDRAWAL_ID of a bank,
     66    * NULL once we are past stage #MHS_INIT.
     67    */
     68   struct GNUNET_CURL_Job *job;
     69 
     70   /**
     71    * The whole request line
     72    */
     73   char *job_url;
     74 };
     75 
     76 
     77 /**
     78  * Decode the JSON in @a resp_obj from the /withdrawals/$WITHDRAWAL_ID response
     79  *
     80  * @param[in] resp_obj JSON object to parse
     81  * @param[in,out] vi where to store the results we decoded
     82  * @param[out] vc where to store account info data
     83  * @return #TALER_EC_NONE on success
     84  */
     85 static enum TALER_ErrorCode
     86 decode_withdrawals_json (const json_t *resp_obj,
     87                          struct TALER_BANK_WithdrawalInfo *vi)
     88 {
     89   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     90               "Received body\n`%s'\n",
     91               json_dumps(resp_obj, 0));
     92   
     93 
     94   struct GNUNET_JSON_Specification spec[] = {
     95     GNUNET_JSON_spec_mark_optional (
     96     GNUNET_JSON_spec_string ("status",
     97                               &vi->status),
     98                               NULL),
     99     GNUNET_JSON_spec_mark_optional (
    100     TALER_JSON_spec_amount_any ("amount",
    101                                 &vi->amount),NULL),
    102     GNUNET_JSON_spec_mark_optional (
    103     TALER_JSON_spec_amount_any ("suggested_amount",
    104                                 &vi->suggested_amount),NULL),
    105     GNUNET_JSON_spec_mark_optional (
    106     GNUNET_JSON_spec_bool ("no_amount_to_wallet",
    107                             &vi->no_amount_to_wallet),NULL),
    108     GNUNET_JSON_spec_string ("username",
    109                               &vi->username),
    110     GNUNET_JSON_spec_mark_optional (
    111     GNUNET_JSON_spec_string ("selected_reserve_pub",
    112                               &vi->selected_reserve_pub),NULL),
    113     GNUNET_JSON_spec_mark_optional (
    114     GNUNET_JSON_spec_string ("selected_exchange_account",
    115                               &vi->selected_exchange_account),NULL),
    116     GNUNET_JSON_spec_end ()
    117   };
    118 
    119   if (JSON_OBJECT != json_typeof (resp_obj))
    120   {
    121     GNUNET_break_op (0);
    122     return TALER_EC_GENERIC_JSON_INVALID;
    123   }
    124   if (GNUNET_OK !=
    125       GNUNET_JSON_parse (resp_obj,
    126                          spec,
    127                          NULL, NULL))
    128   {
    129     GNUNET_break_op (0);
    130     return TALER_EC_GENERIC_JSON_INVALID;
    131   }
    132 
    133   return TALER_EC_NONE;
    134 }
    135 
    136 
    137 /**
    138  * Callback used when http reply arived to a /withdrawals/$WITHDRAWAL_ID request.
    139  *
    140  * @param cls the `struct TALER_BANK_GetWithdrawalHandle`
    141  * @param response_code HTTP response code or 0 on error
    142  * @param  gresp_obj JSON result, NULL on error, must be a `const json_t *`
    143  */
    144 static void
    145 response_cb(void *cls,
    146         long response_code,
    147         const void *gresp_obj)
    148 {
    149     struct TALER_BANK_GetWithdrawalHandle *withdrawal = cls;
    150     const json_t *resp_obj = gresp_obj;
    151     
    152     struct TALER_BANK_WithdrawalResponse wr = {
    153         .hr.response = resp_obj,
    154         .hr.http_status = (unsigned int)response_code
    155     };
    156     
    157     withdrawal->job = NULL; //job was successfull, curl job cancel not needed anymore in cleanup
    158     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    159                 "Received withdrawal info from URL `%s' with status %ld.\n",
    160                 withdrawal->job_url,
    161                 response_code);
    162     
    163     switch (response_code)
    164   {
    165   case 0:
    166     GNUNET_break_op (0);
    167     wr.hr.ec = TALER_EC_INVALID;
    168     break;
    169   case MHD_HTTP_OK:
    170     if (NULL == resp_obj)
    171     {
    172       GNUNET_break_op (0);
    173       wr.hr.http_status = 0;
    174       wr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    175       break;
    176     }
    177     wr.hr.ec = decode_withdrawals_json (resp_obj,
    178                                         &wr.details.ok.acc);
    179     if (TALER_EC_NONE != wr.hr.ec)
    180     {
    181       GNUNET_break_op (0);
    182       wr.hr.http_status = 0;
    183       break;
    184     }
    185     break;
    186   case MHD_HTTP_NOT_FOUND:
    187     wr.hr.ec = TALER_JSON_get_error_code (resp_obj);
    188     wr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
    189     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    190                 "The operation was not found %u/%d\n",
    191                 (unsigned int) response_code,
    192                 (int) wr.hr.ec);
    193     break;
    194   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    195     wr.hr.ec = TALER_JSON_get_error_code (resp_obj);
    196     wr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
    197     break;
    198   default:
    199     wr.hr.ec = TALER_JSON_get_error_code (resp_obj);
    200     wr.hr.hint = TALER_JSON_get_error_hint (resp_obj);
    201     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    202                 "Unexpected response code %u/%d\n",
    203                 (unsigned int) response_code,
    204                 (int) wr.hr.ec);
    205     break;
    206   }
    207 
    208     withdrawal->withdrawals_cb (withdrawal->withdrawals_cb_cls, &wr);
    209     TALER_BANK_get_withdrawal_cancel(withdrawal);
    210 }
    211 
    212 
    213 struct TALER_BANK_GetWithdrawalHandle *
    214 TALER_BANK_get_withdrawal ( struct GNUNET_CURL_Context *ctx,
    215                             const char *base_url,
    216                             const char *wopid,
    217                             TALER_BANK_WithdrawalCallback withdrawals_cb,
    218                             void *withdrawals_cb_cls,
    219                             const char *timeout_ms)
    220 {
    221     struct TALER_BANK_GetWithdrawalHandle *withdrawal;
    222     char *url;
    223     CURL *eh;
    224 
    225     withdrawal = GNUNET_new(struct TALER_BANK_GetWithdrawalHandle);
    226     withdrawal->withdrawals_cb = withdrawals_cb;
    227     withdrawal->withdrawals_cb_cls = withdrawals_cb_cls;
    228     withdrawal->ctx = ctx;
    229     GNUNET_asprintf(&url,
    230                     "withdrawals/%s",
    231                     wopid);
    232     if (NULL != timeout_ms)
    233     {
    234       withdrawal->job_url = TALER_url_join(base_url,
    235                                           url,
    236                                           "timeout_ms",
    237                                           timeout_ms,
    238                                           NULL);
    239     }
    240     else
    241     {
    242       withdrawal->job_url = TALER_url_join(base_url,
    243                                            url,
    244                                            NULL);
    245     }
    246     if(NULL == withdrawal->job_url)
    247     {
    248         GNUNET_break(0);
    249         GNUNET_free(withdrawal);
    250         return NULL;
    251     }
    252     GNUNET_log( GNUNET_ERROR_TYPE_INFO,
    253                 "Requesting bank account information with URL `%s'.\n",
    254                 withdrawal->job_url);
    255     eh = TALER_BANK_curl_easy_get_(withdrawal->job_url);
    256     if(NULL == eh)
    257     {
    258         GNUNET_break(0);
    259         TALER_BANK_get_withdrawal_cancel(withdrawal);
    260         return NULL;
    261     }
    262     withdrawal->job =
    263     GNUNET_CURL_job_add(withdrawal->ctx,
    264                         eh,
    265                         &response_cb,
    266                         withdrawal);
    267     if(NULL == withdrawal->job)
    268     {
    269         GNUNET_break(0);
    270         TALER_BANK_get_withdrawal_cancel(withdrawal);
    271         return NULL;
    272     }
    273             
    274     return withdrawal;
    275 }
    276 
    277 
    278 
    279 void
    280 TALER_BANK_get_withdrawal_cancel ( struct TALER_BANK_GetWithdrawalHandle *withdrawal)
    281 {
    282     if(NULL != withdrawal->job)
    283     {
    284         GNUNET_CURL_job_cancel(withdrawal->job);
    285         withdrawal->job = NULL;
    286     }
    287     GNUNET_free(withdrawal->job_url);
    288     GNUNET_free(withdrawal);
    289 }