donau_api_donation_statement_get.c (7347B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it 6 under the terms of the GNU General Public License as published 7 by the Free Software Foundation; either version 3, or (at your 8 option) any later version. 9 10 TALER is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public 16 License along with TALER; see the file COPYING. If not, see 17 <http://www.gnu.org/licenses/> 18 */ 19 20 /** 21 * @file lib/donau_api_donation_statement_get.c 22 * @brief Implementation of the "handle" component of the donau's HTTP API 23 * @author Lukas Matyja 24 */ 25 #include <gnunet/gnunet_curl_lib.h> 26 #include <taler/taler_json_lib.h> 27 #include "donau_service.h" 28 #include "donau_api_curl_defaults.h" 29 #include "donau_json_lib.h" 30 31 32 /** 33 * Handle for a GET /donation-statement/$YEAR/$HASH_DONOR_ID request. 34 */ 35 struct DONAU_DonationStatementGetHandle 36 { 37 /** 38 * The url for the /donation-statement/$YEAR/$HASH_DONOR_ID request. 39 */ 40 char *url; 41 42 /** 43 * Entry for this request with the `struct GNUNET_CURL_Context`. 44 */ 45 struct GNUNET_CURL_Job *job; 46 47 /** 48 * Function to call with the result. 49 */ 50 DONAU_GetDonationStatmentResponseCallback cb; 51 52 /** 53 * Salted and hashed donor id 54 */ 55 struct DONAU_HashDonorTaxId h_donor_tax_id; 56 57 /** 58 * year 59 */ 60 uint64_t year; 61 62 /** 63 * Closure to pass to @e cb. 64 */ 65 void *cb_cls; 66 67 }; 68 69 70 /** 71 * Callback used when downloading the reply to a /donation-statement/$YEAR/$HASH_DONOR_ID request 72 * is complete. 73 * 74 * @param cls the `struct KeysRequest` 75 * @param response_code HTTP response code, 0 on error 76 * @param resp_obj parsed JSON result, NULL on error 77 */ 78 static void 79 handle_donation_statement_get_finished (void *cls, 80 long response_code, 81 const void *resp_obj) 82 { 83 struct DONAU_DonationStatementGetHandle *dsgh = cls; 84 const json_t *j = resp_obj; 85 struct DONAU_DonationStatementResponse dsresp = { 86 .hr.reply = j, 87 .hr.http_status = (unsigned int) response_code 88 }; 89 90 dsgh->job = NULL; 91 switch (response_code) 92 { 93 case 0: 94 dsresp.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 95 break; 96 case MHD_HTTP_OK: 97 { 98 struct GNUNET_JSON_Specification spec[] = { 99 GNUNET_JSON_spec_fixed_auto ( 100 "donation_statement_sig", 101 &dsresp.details.ok.donation_statement_sig), 102 TALER_JSON_spec_amount_any ("total", 103 &dsresp.details.ok.total_amount), 104 GNUNET_JSON_spec_fixed_auto ("donau_pub", 105 &dsresp.details.ok.donau_pub), 106 GNUNET_JSON_spec_end () 107 }; 108 109 if (GNUNET_OK != 110 GNUNET_JSON_parse (j, 111 spec, 112 NULL, 113 NULL)) 114 { 115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 116 "Could not parse response from donation-statement GET\n"); 117 GNUNET_break_op (0); 118 dsresp.hr.http_status = 0; 119 dsresp.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 120 } 121 dsgh->cb (dsgh->cb_cls, 122 &dsresp); 123 dsgh->cb = NULL; 124 break; 125 } 126 case MHD_HTTP_BAD_REQUEST: 127 /* This should never happen, either us or the donau is buggy 128 (or API version conflict); just pass JSON reply to the application */ 129 dsresp.hr.ec = TALER_JSON_get_error_code (j); 130 dsresp.hr.hint = TALER_JSON_get_error_hint (j); 131 break; 132 case MHD_HTTP_NOT_FOUND: 133 /* Nothing really to verify, this should never 134 happen, we should pass the JSON reply to the application */ 135 dsresp.hr.ec = TALER_JSON_get_error_code (j); 136 dsresp.hr.hint = TALER_JSON_get_error_hint (j); 137 break; 138 case MHD_HTTP_INTERNAL_SERVER_ERROR: 139 /* Server had an internal issue; we should retry, but this API 140 leaves this to the application */ 141 dsresp.hr.ec = TALER_JSON_get_error_code (j); 142 dsresp.hr.hint = TALER_JSON_get_error_hint (j); 143 break; 144 default: 145 /* unexpected response code */ 146 GNUNET_break_op (0); 147 dsresp.hr.ec = TALER_JSON_get_error_code (j); 148 dsresp.hr.hint = TALER_JSON_get_error_hint (j); 149 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 150 "Unexpected response code %u/%d for GET %s\n", 151 (unsigned int) response_code, 152 (int) dsresp.hr.ec, 153 dsgh->url); 154 break; 155 } 156 if (NULL != dsgh->cb) 157 { 158 dsgh->cb (dsgh->cb_cls, 159 &dsresp); 160 dsgh->cb = NULL; 161 } 162 DONAU_donation_statement_get_cancel (dsgh); 163 } 164 165 166 /** 167 * Prepares the request URL for the age-withdraw request 168 * 169 * @param awbh The handler 170 * @param donau_url The base-URL to the donau 171 */ 172 static 173 enum GNUNET_GenericReturnValue 174 prepare_url ( 175 struct DONAU_DonationStatementGetHandle *dsgh, 176 const char *donau_url) 177 { 178 char arg_str[sizeof (struct DONAU_HashDonorTaxId) * 2 + 32]; 179 char donor_id_hash_str[sizeof (struct DONAU_HashDonorTaxId) * 2]; 180 char *end; 181 182 end = GNUNET_STRINGS_data_to_string ( 183 &dsgh->h_donor_tax_id, 184 sizeof (struct DONAU_HashDonorTaxId), 185 donor_id_hash_str, 186 sizeof (donor_id_hash_str)); 187 *end = '\0'; 188 GNUNET_snprintf (arg_str, 189 sizeof (arg_str), 190 "donation-statement/%lu/%s", 191 dsgh->year, 192 donor_id_hash_str); 193 194 dsgh->url = TALER_url_join (donau_url, 195 arg_str, 196 NULL); 197 if (NULL == dsgh->url) 198 { 199 GNUNET_break (0); 200 DONAU_donation_statement_get_cancel (dsgh); 201 return GNUNET_SYSERR; 202 } 203 204 return GNUNET_OK; 205 } 206 207 208 struct DONAU_DonationStatementGetHandle * 209 DONAU_donation_statement_get ( 210 struct GNUNET_CURL_Context *ctx, 211 const char *url, 212 const uint64_t year, 213 const struct DONAU_HashDonorTaxId *h_donor_tax_id, 214 DONAU_GetDonationStatmentResponseCallback cb, 215 void *cb_cls) 216 { 217 struct DONAU_DonationStatementGetHandle *dsgh; 218 CURL *eh; 219 220 TALER_LOG_DEBUG ("Connecting to the donau (%s)\n", 221 url); 222 223 dsgh = GNUNET_new (struct DONAU_DonationStatementGetHandle); 224 dsgh->cb = cb; 225 dsgh->cb_cls = cb_cls; 226 dsgh->year = year; 227 dsgh->h_donor_tax_id = *h_donor_tax_id; 228 if (GNUNET_OK != prepare_url (dsgh, 229 url)) 230 return NULL; 231 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 232 "Requesting a charity with URL `%s'.\n", 233 dsgh->url); 234 eh = DONAU_curl_easy_get_ (dsgh->url); 235 if (NULL == eh) 236 { 237 GNUNET_break (0); 238 GNUNET_free (dsgh->url); 239 GNUNET_free (dsgh); 240 return NULL; 241 } 242 dsgh->job = GNUNET_CURL_job_add_with_ct_json (ctx, 243 eh, 244 & 245 handle_donation_statement_get_finished, 246 dsgh); 247 return dsgh; 248 } 249 250 251 void 252 DONAU_donation_statement_get_cancel ( 253 struct DONAU_DonationStatementGetHandle *dsgh) 254 { 255 if (NULL != dsgh->job) 256 { 257 GNUNET_CURL_job_cancel (dsgh->job); 258 dsgh->job = NULL; 259 } 260 GNUNET_free (dsgh->url); 261 GNUNET_free (dsgh); 262 }