exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

pq_result_helper.c (44788B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2014-2023 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 pq/pq_result_helper.c
     18  * @brief functions to initialize parameter arrays
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/platform.h"
     22 #include <gnunet/gnunet_util_lib.h>
     23 #include "pq_common.h"
     24 #include "taler/taler_pq_lib.h"
     25 
     26 
     27 /**
     28  * Extract an amount from a tuple including the currency from a Postgres
     29  * database @a result at row @a row.
     30  *
     31  * @param cls closure; not used
     32  * @param result where to extract data from
     33  * @param row row to extract data from
     34  * @param fname name (or prefix) of the fields to extract from
     35  * @param[in,out] dst_size where to store size of result, may be NULL
     36  * @param[out] dst where to store the result
     37  * @return
     38  *   #GNUNET_YES if all results could be extracted
     39  *   #GNUNET_NO if at least one result was NULL
     40  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
     41  */
     42 static enum GNUNET_GenericReturnValue
     43 extract_amount_currency_tuple (void *cls,
     44                                PGresult *result,
     45                                int row,
     46                                const char *fname,
     47                                size_t *dst_size,
     48                                void *dst)
     49 {
     50   struct TALER_Amount *r_amount = dst;
     51   int col;
     52 
     53   (void) cls;
     54   if (sizeof (struct TALER_Amount) != *dst_size)
     55   {
     56     GNUNET_break (0);
     57     return GNUNET_SYSERR;
     58   }
     59 
     60   /* Set return value to invalid in case we don't finish */
     61   memset (r_amount,
     62           0,
     63           sizeof (struct TALER_Amount));
     64   col = PQfnumber (result,
     65                    fname);
     66   if (col < 0)
     67   {
     68     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     69                 "Field `%s' does not exist in result\n",
     70                 fname);
     71     return GNUNET_SYSERR;
     72   }
     73   if (PQgetisnull (result,
     74                    row,
     75                    col))
     76   {
     77     return GNUNET_NO;
     78   }
     79 
     80   /* Parse the tuple */
     81   {
     82     struct TALER_PQ_AmountCurrencyP ap;
     83     const char *in;
     84     size_t size;
     85 
     86     size = PQgetlength (result,
     87                         row,
     88                         col);
     89     if ( (size >= sizeof (ap)) ||
     90          (size <= sizeof (ap) - TALER_CURRENCY_LEN) )
     91     {
     92       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     93                   "Incorrect size of binary field `%s' (got %zu, expected (%zu-%zu))\n",
     94                   fname,
     95                   size,
     96                   sizeof (ap) - TALER_CURRENCY_LEN,
     97                   sizeof (ap));
     98       return GNUNET_SYSERR;
     99     }
    100 
    101     in = PQgetvalue (result,
    102                      row,
    103                      col);
    104     memset (&ap.c,
    105             0,
    106             TALER_CURRENCY_LEN);
    107     memcpy (&ap,
    108             in,
    109             size);
    110     if (3 != ntohl (ap.cnt))
    111     {
    112       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    113                   "Incorrect number of elements in tuple-field `%s'\n",
    114                   fname);
    115       return GNUNET_SYSERR;
    116     }
    117     /* FIXME[oec]: OID-checks? */
    118 
    119     r_amount->value = GNUNET_ntohll (ap.v);
    120     r_amount->fraction = ntohl (ap.f);
    121     memcpy (r_amount->currency,
    122             ap.c,
    123             TALER_CURRENCY_LEN);
    124     if ('\0' != r_amount->currency[TALER_CURRENCY_LEN - 1])
    125     {
    126       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    127                   "Invalid currency (not 0-terminated) in tuple field `%s'\n",
    128                   fname);
    129       /* be sure nobody uses this by accident */
    130       memset (r_amount,
    131               0,
    132               sizeof (struct TALER_Amount));
    133       return GNUNET_SYSERR;
    134     }
    135   }
    136 
    137   if (r_amount->value >= TALER_AMOUNT_MAX_VALUE)
    138   {
    139     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    140                 "Value in field `%s' exceeds legal range\n",
    141                 fname);
    142     return GNUNET_SYSERR;
    143   }
    144   if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE)
    145   {
    146     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    147                 "Fraction in field `%s' exceeds legal range\n",
    148                 fname);
    149     return GNUNET_SYSERR;
    150   }
    151   return GNUNET_OK;
    152 }
    153 
    154 
    155 struct GNUNET_PQ_ResultSpec
    156 TALER_PQ_result_spec_amount_with_currency (const char *name,
    157                                            struct TALER_Amount *amount)
    158 {
    159   struct GNUNET_PQ_ResultSpec res = {
    160     .conv = &extract_amount_currency_tuple,
    161     .dst = (void *) amount,
    162     .dst_size = sizeof (*amount),
    163     .fname = name
    164   };
    165 
    166   return res;
    167 }
    168 
    169 
    170 /**
    171  * Extract an amount from a tuple from a Postgres database @a result at row @a row.
    172  *
    173  * @param cls closure, a `const char *` giving the currency
    174  * @param result where to extract data from
    175  * @param row row to extract data from
    176  * @param fname name (or prefix) of the fields to extract from
    177  * @param[in,out] dst_size where to store size of result, may be NULL
    178  * @param[out] dst where to store the result
    179  * @return
    180  *   #GNUNET_YES if all results could be extracted
    181  *   #GNUNET_NO if at least one result was NULL
    182  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
    183  */
    184 static enum GNUNET_GenericReturnValue
    185 extract_amount_tuple (void *cls,
    186                       PGresult *result,
    187                       int row,
    188                       const char *fname,
    189                       size_t *dst_size,
    190                       void *dst)
    191 {
    192   struct TALER_Amount *r_amount = dst;
    193   const char *currency = cls;
    194   int col;
    195   size_t len;
    196 
    197   if (sizeof (struct TALER_Amount) != *dst_size)
    198   {
    199     GNUNET_break (0);
    200     return GNUNET_SYSERR;
    201   }
    202 
    203   /* Set return value to invalid in case we don't finish */
    204   memset (r_amount,
    205           0,
    206           sizeof (struct TALER_Amount));
    207   col = PQfnumber (result,
    208                    fname);
    209   if (col < 0)
    210   {
    211     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    212                 "Field `%s' does not exist in result\n",
    213                 fname);
    214     return GNUNET_SYSERR;
    215   }
    216   if (PQgetisnull (result,
    217                    row,
    218                    col))
    219   {
    220     return GNUNET_NO;
    221   }
    222 
    223   /* Parse the tuple */
    224   {
    225     struct TALER_PQ_AmountP ap;
    226     const char *in;
    227     size_t size;
    228 
    229     size = PQgetlength (result,
    230                         row,
    231                         col);
    232     in = PQgetvalue (result,
    233                      row,
    234                      col);
    235     if (sizeof(struct TALER_PQ_AmountNullP) == size)
    236     {
    237       struct TALER_PQ_AmountNullP apn;
    238 
    239       memcpy (&apn,
    240               in,
    241               size);
    242       if ( (2 == ntohl (apn.cnt)) &&
    243            (-1 == (int32_t) ntohl (apn.sz_v)) &&
    244            (-1 == (int32_t) ntohl (apn.sz_f)) )
    245       {
    246         /* is NULL! */
    247         return GNUNET_NO;
    248       }
    249       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    250                   "Incorrect size of binary field `%s' and not NULL (got %zu, expected %zu)\n",
    251                   fname,
    252                   size,
    253                   sizeof(ap));
    254       return GNUNET_SYSERR;
    255     }
    256     if (sizeof(ap) != size)
    257     {
    258       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    259                   "Incorrect size of binary field `%s' (got %zu, expected %zu)\n",
    260                   fname,
    261                   size,
    262                   sizeof(ap));
    263       return GNUNET_SYSERR;
    264     }
    265 
    266     memcpy (&ap,
    267             in,
    268             size);
    269     if (2 != ntohl (ap.cnt))
    270     {
    271       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    272                   "Incorrect number of elements in tuple-field `%s'\n",
    273                   fname);
    274       return GNUNET_SYSERR;
    275     }
    276     /* FIXME[oec]: OID-checks? */
    277 
    278     r_amount->value = GNUNET_ntohll (ap.v);
    279     r_amount->fraction = ntohl (ap.f);
    280   }
    281 
    282   if (r_amount->value >= TALER_AMOUNT_MAX_VALUE)
    283   {
    284     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    285                 "Value in field `%s' exceeds legal range\n",
    286                 fname);
    287     return GNUNET_SYSERR;
    288   }
    289   if (r_amount->fraction >= TALER_AMOUNT_FRAC_BASE)
    290   {
    291     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    292                 "Fraction in field `%s' exceeds legal range\n",
    293                 fname);
    294     return GNUNET_SYSERR;
    295   }
    296 
    297   len = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
    298                     strlen (currency));
    299 
    300   GNUNET_memcpy (r_amount->currency,
    301                  currency,
    302                  len);
    303   return GNUNET_OK;
    304 }
    305 
    306 
    307 struct GNUNET_PQ_ResultSpec
    308 TALER_PQ_result_spec_amount (const char *name,
    309                              const char *currency,
    310                              struct TALER_Amount *amount)
    311 {
    312   struct GNUNET_PQ_ResultSpec res = {
    313     .conv = &extract_amount_tuple,
    314     .cls = (void *) currency,
    315     .dst = (void *) amount,
    316     .dst_size = sizeof (*amount),
    317     .fname = name
    318   };
    319 
    320   return res;
    321 }
    322 
    323 
    324 /**
    325  * Extract data from a Postgres database @a result at row @a row.
    326  *
    327  * @param cls closure
    328  * @param result where to extract data from
    329  * @param row row to extract data from
    330  * @param fname name (or prefix) of the fields to extract from
    331  * @param[in,out] dst_size where to store size of result, may be NULL
    332  * @param[out] dst where to store the result
    333  * @return
    334  *   #GNUNET_YES if all results could be extracted
    335  *   #GNUNET_NO if at least one result was NULL
    336  *   #GNUNET_SYSERR if a result was invalid (non-existing field)
    337  */
    338 static enum GNUNET_GenericReturnValue
    339 extract_json (void *cls,
    340               PGresult *result,
    341               int row,
    342               const char *fname,
    343               size_t *dst_size,
    344               void *dst)
    345 {
    346   json_t **j_dst = dst;
    347   const char *res;
    348   int fnum;
    349   json_error_t json_error;
    350   size_t slen;
    351 
    352   (void) cls;
    353   (void) dst_size;
    354   fnum = PQfnumber (result,
    355                     fname);
    356   if (fnum < 0)
    357   {
    358     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    359                 "Field `%s' does not exist in result\n",
    360                 fname);
    361     return GNUNET_SYSERR;
    362   }
    363   if (PQgetisnull (result,
    364                    row,
    365                    fnum))
    366     return GNUNET_NO;
    367   slen = PQgetlength (result,
    368                       row,
    369                       fnum);
    370   res = (const char *) PQgetvalue (result,
    371                                    row,
    372                                    fnum);
    373   *j_dst = json_loadb (res,
    374                        slen,
    375                        JSON_REJECT_DUPLICATES,
    376                        &json_error);
    377   if (NULL == *j_dst)
    378   {
    379     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    380                 "Failed to parse JSON result for field `%s': %s (%s)\n",
    381                 fname,
    382                 json_error.text,
    383                 json_error.source);
    384     return GNUNET_SYSERR;
    385   }
    386   return GNUNET_OK;
    387 }
    388 
    389 
    390 /**
    391  * Function called to clean up memory allocated
    392  * by a #GNUNET_PQ_ResultConverter.
    393  *
    394  * @param cls closure
    395  * @param rd result data to clean up
    396  */
    397 static void
    398 clean_json (void *cls,
    399             void *rd)
    400 {
    401   json_t **dst = rd;
    402 
    403   (void) cls;
    404   if (NULL != *dst)
    405   {
    406     json_decref (*dst);
    407     *dst = NULL;
    408   }
    409 }
    410 
    411 
    412 struct GNUNET_PQ_ResultSpec
    413 TALER_PQ_result_spec_json (const char *name,
    414                            json_t **jp)
    415 {
    416   struct GNUNET_PQ_ResultSpec res = {
    417     .conv = &extract_json,
    418     .cleaner = &clean_json,
    419     .dst = (void *) jp,
    420     .fname  = name
    421   };
    422 
    423   return res;
    424 }
    425 
    426 
    427 /**
    428  * Extract data from a Postgres database @a result at row @a row.
    429  *
    430  * @param cls closure
    431  * @param result where to extract data from
    432  * @param row the row to extract data from
    433  * @param fname name (or prefix) of the fields to extract from
    434  * @param[in,out] dst_size where to store size of result, may be NULL
    435  * @param[out] dst where to store the result
    436  * @return
    437  *   #GNUNET_YES if all results could be extracted
    438  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
    439  */
    440 static enum GNUNET_GenericReturnValue
    441 extract_denom_pub (void *cls,
    442                    PGresult *result,
    443                    int row,
    444                    const char *fname,
    445                    size_t *dst_size,
    446                    void *dst)
    447 {
    448   struct TALER_DenominationPublicKey *pk = dst;
    449   struct GNUNET_CRYPTO_BlindSignPublicKey *bpk;
    450   size_t len;
    451   const char *res;
    452   int fnum;
    453   uint32_t be[2];
    454 
    455   (void) cls;
    456   (void) dst_size;
    457   fnum = PQfnumber (result,
    458                     fname);
    459   if (fnum < 0)
    460   {
    461     GNUNET_break (0);
    462     return GNUNET_SYSERR;
    463   }
    464   if (PQgetisnull (result,
    465                    row,
    466                    fnum))
    467     return GNUNET_NO;
    468 
    469   /* if a field is null, continue but
    470    * remember that we now return a different result */
    471   len = PQgetlength (result,
    472                      row,
    473                      fnum);
    474   res = PQgetvalue (result,
    475                     row,
    476                     fnum);
    477   if (len < sizeof (be))
    478   {
    479     GNUNET_break (0);
    480     return GNUNET_SYSERR;
    481   }
    482   GNUNET_memcpy (be,
    483                  res,
    484                  sizeof (be));
    485   res += sizeof (be);
    486   len -= sizeof (be);
    487   bpk = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
    488   bpk->cipher = ntohl (be[0]);
    489   bpk->rc = 1;
    490   pk->age_mask.bits = ntohl (be[1]);
    491   switch (bpk->cipher)
    492   {
    493   case GNUNET_CRYPTO_BSA_INVALID:
    494     break;
    495   case GNUNET_CRYPTO_BSA_RSA:
    496     bpk->details.rsa_public_key
    497       = GNUNET_CRYPTO_rsa_public_key_decode (res,
    498                                              len);
    499     if (NULL == bpk->details.rsa_public_key)
    500     {
    501       GNUNET_break (0);
    502       GNUNET_free (bpk);
    503       return GNUNET_SYSERR;
    504     }
    505     pk->bsign_pub_key = bpk;
    506     GNUNET_CRYPTO_hash (res,
    507                         len,
    508                         &bpk->pub_key_hash);
    509     return GNUNET_OK;
    510   case GNUNET_CRYPTO_BSA_CS:
    511     if (sizeof (bpk->details.cs_public_key) != len)
    512     {
    513       GNUNET_break (0);
    514       GNUNET_free (bpk);
    515       return GNUNET_SYSERR;
    516     }
    517     GNUNET_memcpy (&bpk->details.cs_public_key,
    518                    res,
    519                    len);
    520     pk->bsign_pub_key = bpk;
    521     GNUNET_CRYPTO_hash (res,
    522                         len,
    523                         &bpk->pub_key_hash);
    524     return GNUNET_OK;
    525   }
    526   GNUNET_break (0);
    527   GNUNET_free (bpk);
    528   return GNUNET_SYSERR;
    529 }
    530 
    531 
    532 /**
    533  * Function called to clean up memory allocated
    534  * by a #GNUNET_PQ_ResultConverter.
    535  *
    536  * @param cls closure
    537  * @param rd result data to clean up
    538  */
    539 static void
    540 clean_denom_pub (void *cls,
    541                  void *rd)
    542 {
    543   struct TALER_DenominationPublicKey *denom_pub = rd;
    544 
    545   (void) cls;
    546   TALER_denom_pub_free (denom_pub);
    547 }
    548 
    549 
    550 struct GNUNET_PQ_ResultSpec
    551 TALER_PQ_result_spec_denom_pub (const char *name,
    552                                 struct TALER_DenominationPublicKey *denom_pub)
    553 {
    554   struct GNUNET_PQ_ResultSpec res = {
    555     .conv = &extract_denom_pub,
    556     .cleaner = &clean_denom_pub,
    557     .dst = (void *) denom_pub,
    558     .fname = name
    559   };
    560 
    561   return res;
    562 }
    563 
    564 
    565 /**
    566  * Extract data from a Postgres database @a result at row @a row.
    567  *
    568  * @param cls closure
    569  * @param result where to extract data from
    570  * @param row the row to extract data from
    571  * @param fname name (or prefix) of the fields to extract from
    572  * @param[in,out] dst_size where to store size of result, may be NULL
    573  * @param[out] dst where to store the result
    574  * @return
    575  *   #GNUNET_YES if all results could be extracted
    576  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
    577  */
    578 static enum GNUNET_GenericReturnValue
    579 extract_denom_sig (void *cls,
    580                    PGresult *result,
    581                    int row,
    582                    const char *fname,
    583                    size_t *dst_size,
    584                    void *dst)
    585 {
    586   struct TALER_DenominationSignature *sig = dst;
    587   struct GNUNET_CRYPTO_UnblindedSignature *ubs;
    588   size_t len;
    589   const char *res;
    590   int fnum;
    591   uint32_t be[2];
    592 
    593   (void) cls;
    594   (void) dst_size;
    595   fnum = PQfnumber (result,
    596                     fname);
    597   if (fnum < 0)
    598   {
    599     GNUNET_break (0);
    600     return GNUNET_SYSERR;
    601   }
    602   if (PQgetisnull (result,
    603                    row,
    604                    fnum))
    605     return GNUNET_NO;
    606 
    607   /* if a field is null, continue but
    608    * remember that we now return a different result */
    609   len = PQgetlength (result,
    610                      row,
    611                      fnum);
    612   res = PQgetvalue (result,
    613                     row,
    614                     fnum);
    615   if (len < sizeof (be))
    616   {
    617     GNUNET_break (0);
    618     return GNUNET_SYSERR;
    619   }
    620   GNUNET_memcpy (&be,
    621                  res,
    622                  sizeof (be));
    623   if (0x00 != ntohl (be[1]))
    624   {
    625     GNUNET_break (0);
    626     return GNUNET_SYSERR;
    627   }
    628   res += sizeof (be);
    629   len -= sizeof (be);
    630   ubs = GNUNET_new (struct GNUNET_CRYPTO_UnblindedSignature);
    631   ubs->rc = 1;
    632   ubs->cipher = ntohl (be[0]);
    633   switch (ubs->cipher)
    634   {
    635   case GNUNET_CRYPTO_BSA_INVALID:
    636     break;
    637   case GNUNET_CRYPTO_BSA_RSA:
    638     ubs->details.rsa_signature
    639       = GNUNET_CRYPTO_rsa_signature_decode (res,
    640                                             len);
    641     if (NULL == ubs->details.rsa_signature)
    642     {
    643       GNUNET_break (0);
    644       GNUNET_free (ubs);
    645       return GNUNET_SYSERR;
    646     }
    647     sig->unblinded_sig = ubs;
    648     return GNUNET_OK;
    649   case GNUNET_CRYPTO_BSA_CS:
    650     if (sizeof (ubs->details.cs_signature) != len)
    651     {
    652       GNUNET_break (0);
    653       GNUNET_free (ubs);
    654       return GNUNET_SYSERR;
    655     }
    656     GNUNET_memcpy (&ubs->details.cs_signature,
    657                    res,
    658                    len);
    659     sig->unblinded_sig = ubs;
    660     return GNUNET_OK;
    661   }
    662   GNUNET_break (0);
    663   GNUNET_free (ubs);
    664   return GNUNET_SYSERR;
    665 }
    666 
    667 
    668 /**
    669  * Function called to clean up memory allocated
    670  * by a #GNUNET_PQ_ResultConverter.
    671  *
    672  * @param cls closure
    673  * @param rd result data to clean up
    674  */
    675 static void
    676 clean_denom_sig (void *cls,
    677                  void *rd)
    678 {
    679   struct TALER_DenominationSignature *denom_sig = rd;
    680 
    681   (void) cls;
    682   TALER_denom_sig_free (denom_sig);
    683 }
    684 
    685 
    686 struct GNUNET_PQ_ResultSpec
    687 TALER_PQ_result_spec_denom_sig (const char *name,
    688                                 struct TALER_DenominationSignature *denom_sig)
    689 {
    690   struct GNUNET_PQ_ResultSpec res = {
    691     .conv = &extract_denom_sig,
    692     .cleaner = &clean_denom_sig,
    693     .dst = (void *) denom_sig,
    694     .fname = name
    695   };
    696 
    697   return res;
    698 }
    699 
    700 
    701 /**
    702  * Extract data from a Postgres database @a result at row @a row.
    703  *
    704  * @param cls closure
    705  * @param result where to extract data from
    706  * @param row the row to extract data from
    707  * @param fname name (or prefix) of the fields to extract from
    708  * @param[in,out] dst_size where to store size of result, may be NULL
    709  * @param[out] dst where to store the result
    710  * @return
    711  *   #GNUNET_YES if all results could be extracted
    712  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
    713  */
    714 static enum GNUNET_GenericReturnValue
    715 extract_blinded_denom_sig (void *cls,
    716                            PGresult *result,
    717                            int row,
    718                            const char *fname,
    719                            size_t *dst_size,
    720                            void *dst)
    721 {
    722   struct TALER_BlindedDenominationSignature *sig = dst;
    723   struct GNUNET_CRYPTO_BlindedSignature *bs;
    724   size_t len;
    725   const char *res;
    726   int fnum;
    727   uint32_t be[2];
    728 
    729   (void) cls;
    730   (void) dst_size;
    731   fnum = PQfnumber (result,
    732                     fname);
    733   if (fnum < 0)
    734   {
    735     GNUNET_break (0);
    736     return GNUNET_SYSERR;
    737   }
    738   if (PQgetisnull (result,
    739                    row,
    740                    fnum))
    741     return GNUNET_NO;
    742 
    743   /* if a field is null, continue but
    744    * remember that we now return a different result */
    745   len = PQgetlength (result,
    746                      row,
    747                      fnum);
    748   res = PQgetvalue (result,
    749                     row,
    750                     fnum);
    751   if (len < sizeof (be))
    752   {
    753     GNUNET_break (0);
    754     return GNUNET_SYSERR;
    755   }
    756   GNUNET_memcpy (&be,
    757                  res,
    758                  sizeof (be));
    759   if (0x01 != ntohl (be[1])) /* magic marker: blinded */
    760   {
    761     GNUNET_break (0);
    762     return GNUNET_SYSERR;
    763   }
    764   res += sizeof (be);
    765   len -= sizeof (be);
    766   bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
    767   bs->rc = 1;
    768   bs->cipher = ntohl (be[0]);
    769   switch (bs->cipher)
    770   {
    771   case GNUNET_CRYPTO_BSA_INVALID:
    772     break;
    773   case GNUNET_CRYPTO_BSA_RSA:
    774     bs->details.blinded_rsa_signature
    775       = GNUNET_CRYPTO_rsa_signature_decode (res,
    776                                             len);
    777     if (NULL == bs->details.blinded_rsa_signature)
    778     {
    779       GNUNET_break (0);
    780       GNUNET_free (bs);
    781       return GNUNET_SYSERR;
    782     }
    783     sig->blinded_sig = bs;
    784     return GNUNET_OK;
    785   case GNUNET_CRYPTO_BSA_CS:
    786     if (sizeof (bs->details.blinded_cs_answer) != len)
    787     {
    788       GNUNET_break (0);
    789       GNUNET_free (bs);
    790       return GNUNET_SYSERR;
    791     }
    792     GNUNET_memcpy (&bs->details.blinded_cs_answer,
    793                    res,
    794                    len);
    795     sig->blinded_sig = bs;
    796     return GNUNET_OK;
    797   }
    798   GNUNET_break (0);
    799   GNUNET_free (bs);
    800   return GNUNET_SYSERR;
    801 }
    802 
    803 
    804 /**
    805  * Function called to clean up memory allocated
    806  * by a #GNUNET_PQ_ResultConverter.
    807  *
    808  * @param cls closure
    809  * @param rd result data to clean up
    810  */
    811 static void
    812 clean_blinded_denom_sig (void *cls,
    813                          void *rd)
    814 {
    815   struct TALER_BlindedDenominationSignature *denom_sig = rd;
    816 
    817   (void) cls;
    818   TALER_blinded_denom_sig_free (denom_sig);
    819 }
    820 
    821 
    822 struct GNUNET_PQ_ResultSpec
    823 TALER_PQ_result_spec_blinded_denom_sig (
    824   const char *name,
    825   struct TALER_BlindedDenominationSignature *denom_sig)
    826 {
    827   // FIXME: use GNUNET_PQ_result_spec_blinded_sig()
    828   struct GNUNET_PQ_ResultSpec res = {
    829     .conv = &extract_blinded_denom_sig,
    830     .cleaner = &clean_blinded_denom_sig,
    831     .dst = (void *) denom_sig,
    832     .fname = name
    833   };
    834 
    835   return res;
    836 }
    837 
    838 
    839 /**
    840  * Extract data from a Postgres database @a result at row @a row.
    841  *
    842  * @param cls closure
    843  * @param result where to extract data from
    844  * @param row the row to extract data from
    845  * @param fname name (or prefix) of the fields to extract from
    846  * @param[in,out] dst_size where to store size of result, may be NULL
    847  * @param[out] dst where to store the result
    848  * @return
    849  *   #GNUNET_YES if all results could be extracted
    850  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
    851  */
    852 static enum GNUNET_GenericReturnValue
    853 extract_blinded_planchet (void *cls,
    854                           PGresult *result,
    855                           int row,
    856                           const char *fname,
    857                           size_t *dst_size,
    858                           void *dst)
    859 {
    860   struct TALER_BlindedPlanchet *bp = dst;
    861   struct GNUNET_CRYPTO_BlindedMessage *bm;
    862   size_t len;
    863   const char *res;
    864   int fnum;
    865   uint32_t be[2];
    866 
    867   (void) cls;
    868   (void) dst_size;
    869   fnum = PQfnumber (result,
    870                     fname);
    871   if (fnum < 0)
    872   {
    873     GNUNET_break (0);
    874     return GNUNET_SYSERR;
    875   }
    876   if (PQgetisnull (result,
    877                    row,
    878                    fnum))
    879     return GNUNET_NO;
    880 
    881   /* if a field is null, continue but
    882    * remember that we now return a different result */
    883   len = PQgetlength (result,
    884                      row,
    885                      fnum);
    886   res = PQgetvalue (result,
    887                     row,
    888                     fnum);
    889   if (len < sizeof (be))
    890   {
    891     GNUNET_break (0);
    892     return GNUNET_SYSERR;
    893   }
    894   GNUNET_memcpy (&be,
    895                  res,
    896                  sizeof (be));
    897   if (0x0100 != ntohl (be[1])) /* magic marker: blinded */
    898   {
    899     GNUNET_break (0);
    900     return GNUNET_SYSERR;
    901   }
    902   res += sizeof (be);
    903   len -= sizeof (be);
    904   bm = GNUNET_new (struct GNUNET_CRYPTO_BlindedMessage);
    905   bm->rc = 1;
    906   bm->cipher = ntohl (be[0]);
    907   switch (bm->cipher)
    908   {
    909   case GNUNET_CRYPTO_BSA_INVALID:
    910     break;
    911   case GNUNET_CRYPTO_BSA_RSA:
    912     bm->details.rsa_blinded_message.blinded_msg_size
    913       = len;
    914     bm->details.rsa_blinded_message.blinded_msg
    915       = GNUNET_memdup (res,
    916                        len);
    917     bp->blinded_message = bm;
    918     return GNUNET_OK;
    919   case GNUNET_CRYPTO_BSA_CS:
    920     if (sizeof (bm->details.cs_blinded_message) != len)
    921     {
    922       GNUNET_break (0);
    923       GNUNET_free (bm);
    924       return GNUNET_SYSERR;
    925     }
    926     GNUNET_memcpy (&bm->details.cs_blinded_message,
    927                    res,
    928                    len);
    929     bp->blinded_message = bm;
    930     return GNUNET_OK;
    931   }
    932   GNUNET_break (0);
    933   GNUNET_free (bm);
    934   return GNUNET_SYSERR;
    935 }
    936 
    937 
    938 /**
    939  * Function called to clean up memory allocated
    940  * by a #GNUNET_PQ_ResultConverter.
    941  *
    942  * @param cls closure
    943  * @param rd result data to clean up
    944  */
    945 static void
    946 clean_blinded_planchet (void *cls,
    947                         void *rd)
    948 {
    949   struct TALER_BlindedPlanchet *bp = rd;
    950 
    951   (void) cls;
    952   TALER_blinded_planchet_free (bp);
    953 }
    954 
    955 
    956 struct GNUNET_PQ_ResultSpec
    957 TALER_PQ_result_spec_blinded_planchet (
    958   const char *name,
    959   struct TALER_BlindedPlanchet *bp)
    960 {
    961   struct GNUNET_PQ_ResultSpec res = {
    962     .conv = &extract_blinded_planchet,
    963     .cleaner = &clean_blinded_planchet,
    964     .dst = (void *) bp,
    965     .fname = name
    966   };
    967 
    968   return res;
    969 }
    970 
    971 
    972 /**
    973  * Extract data from a Postgres database @a result at row @a row.
    974  *
    975  * @param cls closure
    976  * @param result where to extract data from
    977  * @param row row to extract data from
    978  * @param fname name (or prefix) of the fields to extract from
    979  * @param[in,out] dst_size where to store size of result, may be NULL
    980  * @param[out] dst where to store the result
    981  * @return
    982  *   #GNUNET_YES if all results could be extracted
    983  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
    984  */
    985 static enum GNUNET_GenericReturnValue
    986 extract_exchange_withdraw_values (void *cls,
    987                                   PGresult *result,
    988                                   int row,
    989                                   const char *fname,
    990                                   size_t *dst_size,
    991                                   void *dst)
    992 {
    993   struct TALER_ExchangeBlindingValues *alg_values = dst;
    994   struct GNUNET_CRYPTO_BlindingInputValues *bi;
    995   size_t len;
    996   const char *res;
    997   int fnum;
    998   uint32_t be[2];
    999 
   1000   (void) cls;
   1001   (void) dst_size;
   1002   fnum = PQfnumber (result,
   1003                     fname);
   1004   if (fnum < 0)
   1005   {
   1006     GNUNET_break (0);
   1007     return GNUNET_SYSERR;
   1008   }
   1009   if (PQgetisnull (result,
   1010                    row,
   1011                    fnum))
   1012     return GNUNET_NO;
   1013 
   1014   /* if a field is null, continue but
   1015    * remember that we now return a different result */
   1016   len = PQgetlength (result,
   1017                      row,
   1018                      fnum);
   1019   res = PQgetvalue (result,
   1020                     row,
   1021                     fnum);
   1022   if (len < sizeof (be))
   1023   {
   1024     GNUNET_break (0);
   1025     return GNUNET_SYSERR;
   1026   }
   1027   GNUNET_memcpy (&be,
   1028                  res,
   1029                  sizeof (be));
   1030   if (0x010000 != ntohl (be[1])) /* magic marker: EWV */
   1031   {
   1032     GNUNET_break (0);
   1033     return GNUNET_SYSERR;
   1034   }
   1035   res += sizeof (be);
   1036   len -= sizeof (be);
   1037   bi = GNUNET_new (struct GNUNET_CRYPTO_BlindingInputValues);
   1038   bi->rc = 1;
   1039   bi->cipher = ntohl (be[0]);
   1040   switch (bi->cipher)
   1041   {
   1042   case GNUNET_CRYPTO_BSA_INVALID:
   1043     break;
   1044   case GNUNET_CRYPTO_BSA_RSA:
   1045     if (0 != len)
   1046     {
   1047       GNUNET_break (0);
   1048       GNUNET_free (bi);
   1049       return GNUNET_SYSERR;
   1050     }
   1051     alg_values->blinding_inputs = bi;
   1052     return GNUNET_OK;
   1053   case GNUNET_CRYPTO_BSA_CS:
   1054     if (sizeof (bi->details.cs_values) != len)
   1055     {
   1056       GNUNET_break (0);
   1057       GNUNET_free (bi);
   1058       return GNUNET_SYSERR;
   1059     }
   1060     GNUNET_memcpy (&bi->details.cs_values,
   1061                    res,
   1062                    len);
   1063     alg_values->blinding_inputs = bi;
   1064     return GNUNET_OK;
   1065   }
   1066   GNUNET_break (0);
   1067   GNUNET_free (bi);
   1068   return GNUNET_SYSERR;
   1069 }
   1070 
   1071 
   1072 struct GNUNET_PQ_ResultSpec
   1073 TALER_PQ_result_spec_exchange_withdraw_values (
   1074   const char *name,
   1075   struct TALER_ExchangeBlindingValues *ewv)
   1076 {
   1077   struct GNUNET_PQ_ResultSpec res = {
   1078     .conv = &extract_exchange_withdraw_values,
   1079     .dst = (void *) ewv,
   1080     .fname = name
   1081   };
   1082 
   1083   return res;
   1084 }
   1085 
   1086 
   1087 /**
   1088  * Closure for the array result specifications.  Contains type information
   1089  * for the generic parser extract_array_generic and out-pointers for the results.
   1090  */
   1091 struct ArrayResultCls
   1092 {
   1093   /**
   1094    * Oid of the expected type, must match the oid in the header of the PQResult struct
   1095    */
   1096   Oid oid;
   1097 
   1098   /**
   1099    * Target type
   1100    */
   1101   enum TALER_PQ_ArrayType typ;
   1102 
   1103   /**
   1104    * If not 0, defines the expected size of each entry
   1105    */
   1106   size_t same_size;
   1107 
   1108   /**
   1109    * Out-pointer to write the number of elements in the array
   1110    */
   1111   size_t *num;
   1112 
   1113   /**
   1114    * Out-pointer. If @a typ is TALER_PQ_array_of_byte and @a same_size is 0,
   1115    * allocate and put the array of @a num sizes here. NULL otherwise
   1116    */
   1117   size_t **sizes;
   1118 
   1119   /**
   1120    * DB_connection, needed for OID-lookup for composite types
   1121    */
   1122   const struct GNUNET_PQ_Context *db;
   1123 
   1124   /**
   1125    * Currency information for amount composites
   1126    */
   1127   char currency[TALER_CURRENCY_LEN];
   1128 };
   1129 
   1130 
   1131 /**
   1132  * Extract data from a Postgres database @a result as array of a specific type
   1133  * from row @a row.  The type information and optionally additional
   1134  * out-parameters are given in @a cls which is of type array_result_cls.
   1135  *
   1136  * @param cls closure of type array_result_cls
   1137  * @param result where to extract data from
   1138  * @param row row to extract data from
   1139  * @param fname name (or prefix) of the fields to extract from
   1140  * @param[in,out] dst_size where to store size of result, may be NULL
   1141  * @param[out] dst where to store the result
   1142  * @return
   1143  *   #GNUNET_YES if all results could be extracted
   1144  *   #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
   1145  */
   1146 static enum GNUNET_GenericReturnValue
   1147 extract_array_generic (
   1148   void *cls,
   1149   PGresult *result,
   1150   int row,
   1151   const char *fname,
   1152   size_t *dst_size,
   1153   void *dst)
   1154 {
   1155   const struct ArrayResultCls *info = cls;
   1156   int data_sz;
   1157   char *data;
   1158   void *out = NULL;
   1159   struct GNUNET_PQ_ArrayHeader_P header;
   1160   int col_num;
   1161 
   1162   GNUNET_assert (NULL != dst);
   1163   *((void **) dst) = NULL;
   1164 
   1165   #define FAIL_IF(cond) \
   1166   do { \
   1167     if ((cond)) \
   1168     { \
   1169       GNUNET_break (! (cond)); \
   1170       goto FAIL; \
   1171     } \
   1172   } while (0)
   1173 
   1174   col_num = PQfnumber (result, fname);
   1175   FAIL_IF (0 > col_num);
   1176 
   1177   if (PQgetisnull (result, row, col_num))
   1178   {
   1179     return GNUNET_NO;
   1180   }
   1181 
   1182   data_sz = PQgetlength (result, row, col_num);
   1183   FAIL_IF (0 > data_sz);
   1184   FAIL_IF (sizeof(header) > (size_t) data_sz);
   1185 
   1186   data = PQgetvalue (result, row, col_num);
   1187   FAIL_IF (NULL == data);
   1188 
   1189   {
   1190     struct GNUNET_PQ_ArrayHeader_P *h =
   1191       (struct GNUNET_PQ_ArrayHeader_P *) data;
   1192 
   1193     header.ndim = ntohl (h->ndim);
   1194     header.has_null = ntohl (h->has_null);
   1195     header.oid = ntohl (h->oid);
   1196     header.dim = ntohl (h->dim);
   1197     header.lbound = ntohl (h->lbound);
   1198 
   1199     FAIL_IF (1 != header.ndim);
   1200     FAIL_IF (INT_MAX <= header.dim);
   1201     FAIL_IF (0 != header.has_null);
   1202     FAIL_IF (1 != header.lbound);
   1203     FAIL_IF (info->oid != header.oid);
   1204   }
   1205 
   1206   if (NULL != info->num)
   1207     *info->num = header.dim;
   1208 
   1209   {
   1210     char *in = data + sizeof(header);
   1211 
   1212     switch (info->typ)
   1213     {
   1214     case TALER_PQ_array_of_amount:
   1215       {
   1216         struct TALER_Amount *amounts;
   1217         if (NULL != dst_size)
   1218           *dst_size = sizeof(struct TALER_Amount) * (header.dim);
   1219 
   1220         amounts = GNUNET_new_array (header.dim,
   1221                                     struct TALER_Amount);
   1222         *((void **) dst) = amounts;
   1223 
   1224         for (uint32_t i = 0; i < header.dim; i++)
   1225         {
   1226           struct TALER_PQ_AmountP ap;
   1227           struct TALER_Amount *amount = &amounts[i];
   1228           uint32_t val;
   1229           size_t sz;
   1230 
   1231           GNUNET_memcpy (&val,
   1232                          in,
   1233                          sizeof(val));
   1234           sz =  ntohl (val);
   1235           in += sizeof(val);
   1236 
   1237           /* total size for this array-entry */
   1238           FAIL_IF (sizeof(ap) != sz);
   1239 
   1240           GNUNET_memcpy (&ap,
   1241                          in,
   1242                          sz);
   1243           FAIL_IF (2 != ntohl (ap.cnt));
   1244 
   1245           amount->value = GNUNET_ntohll (ap.v);
   1246           amount->fraction = ntohl (ap.f);
   1247           GNUNET_memcpy (amount->currency,
   1248                          info->currency,
   1249                          TALER_CURRENCY_LEN);
   1250 
   1251           in += sizeof(struct TALER_PQ_AmountP);
   1252         }
   1253         return GNUNET_OK;
   1254       }
   1255     case TALER_PQ_array_of_amount_currency:
   1256       {
   1257         struct TALER_Amount *amounts;
   1258         if (NULL != dst_size)
   1259           *dst_size = sizeof(struct TALER_Amount) * (header.dim);
   1260 
   1261         amounts = GNUNET_new_array (header.dim,
   1262                                     struct TALER_Amount);
   1263         *((void **) dst) = amounts;
   1264 
   1265         for (uint32_t i = 0; i < header.dim; i++)
   1266         {
   1267           struct TALER_PQ_AmountCurrencyP ap;
   1268           struct TALER_Amount *amount = &amounts[i];
   1269           uint32_t val;
   1270           size_t sz;
   1271 
   1272           GNUNET_memcpy (&val,
   1273                          in,
   1274                          sizeof(val));
   1275           sz =  ntohl (val);
   1276           in += sizeof(val);
   1277 
   1278           FAIL_IF ( (sz >= sizeof(ap)) ||
   1279                     (sz <= sizeof(ap) - TALER_CURRENCY_LEN) );
   1280 
   1281           memset (&ap,
   1282                   0,
   1283                   sizeof(ap));
   1284           GNUNET_memcpy (&ap,
   1285                          in,
   1286                          sz);
   1287           FAIL_IF (3 != ntohl (ap.cnt));
   1288 
   1289           amount->value = GNUNET_ntohll (ap.v);
   1290           amount->fraction = ntohl (ap.f);
   1291           GNUNET_memcpy (amount->currency,
   1292                          ap.c,
   1293                          TALER_CURRENCY_LEN);
   1294 
   1295           FAIL_IF ('\0' != amount->currency[TALER_CURRENCY_LEN - 1]);
   1296           FAIL_IF (amount->value >= TALER_AMOUNT_MAX_VALUE);
   1297           FAIL_IF (amount->fraction >= TALER_AMOUNT_FRAC_BASE);
   1298 
   1299           in += sz;
   1300         }
   1301         return GNUNET_OK;
   1302       }
   1303     case TALER_PQ_array_of_denom_hash:
   1304       if (NULL != dst_size)
   1305         *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim);
   1306       out = GNUNET_new_array (header.dim,
   1307                               struct TALER_DenominationHashP);
   1308       *((void **) dst) = out;
   1309       for (uint32_t i = 0; i < header.dim; i++)
   1310       {
   1311         uint32_t val;
   1312         size_t sz;
   1313 
   1314         GNUNET_memcpy (&val,
   1315                        in,
   1316                        sizeof(val));
   1317         sz =  ntohl (val);
   1318         FAIL_IF (sz != sizeof(struct TALER_DenominationHashP));
   1319         in += sizeof(uint32_t);
   1320         *(struct TALER_DenominationHashP *) out =
   1321           *(struct TALER_DenominationHashP *) in;
   1322         in += sz;
   1323         out += sz;
   1324       }
   1325       return GNUNET_OK;
   1326 
   1327     case TALER_PQ_array_of_hash_code:
   1328       if (NULL != dst_size)
   1329         *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim);
   1330       out = GNUNET_new_array (header.dim,
   1331                               struct GNUNET_HashCode);
   1332       *((void **) dst) = out;
   1333       for (uint32_t i = 0; i < header.dim; i++)
   1334       {
   1335         uint32_t val;
   1336         size_t sz;
   1337 
   1338         GNUNET_memcpy (&val,
   1339                        in,
   1340                        sizeof(val));
   1341         sz =  ntohl (val);
   1342         FAIL_IF (sz != sizeof(struct GNUNET_HashCode));
   1343         in += sizeof(uint32_t);
   1344         *(struct GNUNET_HashCode *) out =
   1345           *(struct GNUNET_HashCode *) in;
   1346         in += sz;
   1347         out += sz;
   1348       }
   1349       return GNUNET_OK;
   1350 
   1351     case TALER_PQ_array_of_blinded_coin_hash:
   1352       if (NULL != dst_size)
   1353         *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim);
   1354       out = GNUNET_new_array (header.dim,
   1355                               struct TALER_BlindedCoinHashP);
   1356       *((void **) dst) = out;
   1357       for (uint32_t i = 0; i < header.dim; i++)
   1358       {
   1359         uint32_t val;
   1360         size_t sz;
   1361 
   1362         GNUNET_memcpy (&val,
   1363                        in,
   1364                        sizeof(val));
   1365         sz =  ntohl (val);
   1366         FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP));
   1367         in += sizeof(uint32_t);
   1368         *(struct TALER_BlindedCoinHashP *) out =
   1369           *(struct TALER_BlindedCoinHashP *) in;
   1370         in += sz;
   1371         out += sz;
   1372       }
   1373       return GNUNET_OK;
   1374 
   1375     case TALER_PQ_array_of_cs_r_pub:
   1376       if (NULL != dst_size)
   1377         *dst_size = sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * (header.dim);
   1378       out = GNUNET_new_array (header.dim,
   1379                               struct GNUNET_CRYPTO_CSPublicRPairP);
   1380       *((void **) dst) = out;
   1381       for (uint32_t i = 0; i < header.dim; i++)
   1382       {
   1383         uint32_t val;
   1384         size_t sz;
   1385 
   1386         GNUNET_memcpy (&val,
   1387                        in,
   1388                        sizeof(val));
   1389         sz =  ntohl (val);
   1390         FAIL_IF (sz != sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
   1391         in += sizeof(uint32_t);
   1392         *(struct GNUNET_CRYPTO_CSPublicRPairP *) out =
   1393           *(struct GNUNET_CRYPTO_CSPublicRPairP *) in;
   1394         in += sz;
   1395         out += sz;
   1396       }
   1397       return GNUNET_OK;
   1398 
   1399     case TALER_PQ_array_of_blinded_denom_sig:
   1400       {
   1401         struct TALER_BlindedDenominationSignature *denom_sigs;
   1402         if (0 == header.dim)
   1403         {
   1404           if (NULL != dst_size)
   1405             *dst_size = 0;
   1406           break;
   1407         }
   1408 
   1409         denom_sigs = GNUNET_new_array (header.dim,
   1410                                        struct TALER_BlindedDenominationSignature);
   1411         *((void **) dst) = denom_sigs;
   1412 
   1413         /* copy data */
   1414         for (uint32_t i = 0; i < header.dim; i++)
   1415         {
   1416           struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i];
   1417           struct GNUNET_CRYPTO_BlindedSignature *bs;
   1418           uint32_t be[2];
   1419           uint32_t val;
   1420           size_t sz;
   1421 
   1422           GNUNET_memcpy (&val,
   1423                          in,
   1424                          sizeof(val));
   1425           sz = ntohl (val);
   1426           FAIL_IF (sizeof(be) > sz);
   1427 
   1428           in += sizeof(val);
   1429           GNUNET_memcpy (&be,
   1430                          in,
   1431                          sizeof(be));
   1432           FAIL_IF (0x01 != ntohl (be[1]));  /* magic marker: blinded */
   1433 
   1434           in += sizeof(be);
   1435           sz -= sizeof(be);
   1436           bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
   1437           bs->cipher = ntohl (be[0]);
   1438           bs->rc = 1;
   1439           switch (bs->cipher)
   1440           {
   1441           case GNUNET_CRYPTO_BSA_RSA:
   1442             bs->details.blinded_rsa_signature
   1443               = GNUNET_CRYPTO_rsa_signature_decode (in,
   1444                                                     sz);
   1445             if (NULL == bs->details.blinded_rsa_signature)
   1446             {
   1447               GNUNET_free (bs);
   1448               FAIL_IF (true);
   1449             }
   1450             break;
   1451           case GNUNET_CRYPTO_BSA_CS:
   1452             if (sizeof(bs->details.blinded_cs_answer) != sz)
   1453             {
   1454               GNUNET_free (bs);
   1455               FAIL_IF (true);
   1456             }
   1457             GNUNET_memcpy (&bs->details.blinded_cs_answer,
   1458                            in,
   1459                            sz);
   1460             break;
   1461           default:
   1462             GNUNET_free (bs);
   1463             FAIL_IF (true);
   1464           }
   1465           denom_sig->blinded_sig = bs;
   1466           in += sz;
   1467         }
   1468         return GNUNET_OK;
   1469       }
   1470     default:
   1471       FAIL_IF (true);
   1472     }
   1473   }
   1474 FAIL:
   1475   GNUNET_free (*(void **) dst);
   1476   return GNUNET_SYSERR;
   1477 #undef FAIL_IF
   1478 }
   1479 
   1480 
   1481 /**
   1482  * Cleanup of the data and closure of an array spec.
   1483  */
   1484 static void
   1485 array_cleanup (void *cls,
   1486                void *rd)
   1487 {
   1488   struct ArrayResultCls *info = cls;
   1489   void **dst = rd;
   1490 
   1491   if ( (0 == info->same_size) &&
   1492        (NULL != info->sizes) )
   1493     GNUNET_free (*(info->sizes));
   1494 
   1495   /* Clean up signatures, if applicable */
   1496   if ((TALER_PQ_array_of_blinded_denom_sig == info->typ) &&
   1497       (NULL != *dst))
   1498   {
   1499     struct TALER_BlindedDenominationSignature *denom_sigs = *dst;
   1500 
   1501     GNUNET_assert (NULL != info->num);
   1502     for (size_t i = 0; i < *info->num; i++)
   1503       GNUNET_free (denom_sigs[i].blinded_sig);
   1504   }
   1505   GNUNET_free (info);
   1506   GNUNET_free (*dst);
   1507   *dst = NULL;
   1508 }
   1509 
   1510 
   1511 struct GNUNET_PQ_ResultSpec
   1512 TALER_PQ_result_spec_array_blinded_denom_sig (
   1513   struct GNUNET_PQ_Context *db,
   1514   const char *name,
   1515   size_t *num,
   1516   struct TALER_BlindedDenominationSignature **denom_sigs)
   1517 {
   1518   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1519 
   1520   info->num = num;
   1521   info->typ = TALER_PQ_array_of_blinded_denom_sig;
   1522   GNUNET_assert (GNUNET_OK ==
   1523                  GNUNET_PQ_get_oid_by_name (db,
   1524                                             "bytea",
   1525                                             &info->oid));
   1526   {
   1527     struct GNUNET_PQ_ResultSpec res = {
   1528       .conv = extract_array_generic,
   1529       .cleaner = &array_cleanup,
   1530       .dst = (void *) denom_sigs,
   1531       .fname = name,
   1532       .cls = info
   1533     };
   1534 
   1535     return res;
   1536   }
   1537 }
   1538 
   1539 
   1540 struct GNUNET_PQ_ResultSpec
   1541 TALER_PQ_result_spec_array_blinded_coin_hash (
   1542   struct GNUNET_PQ_Context *db,
   1543   const char *name,
   1544   size_t *num,
   1545   struct TALER_BlindedCoinHashP **h_coin_evs)
   1546 {
   1547   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1548 
   1549   info->num = num;
   1550   info->typ = TALER_PQ_array_of_blinded_coin_hash;
   1551   GNUNET_assert (GNUNET_OK ==
   1552                  GNUNET_PQ_get_oid_by_name (db,
   1553                                             "bytea",
   1554                                             &info->oid));
   1555   {
   1556     struct GNUNET_PQ_ResultSpec res = {
   1557       .conv = extract_array_generic,
   1558       .cleaner = &array_cleanup,
   1559       .dst = (void *) h_coin_evs,
   1560       .fname = name,
   1561       .cls = info
   1562     };
   1563 
   1564     return res;
   1565   }
   1566 }
   1567 
   1568 
   1569 struct GNUNET_PQ_ResultSpec
   1570 TALER_PQ_result_spec_array_denom_hash (
   1571   struct GNUNET_PQ_Context *db,
   1572   const char *name,
   1573   size_t *num,
   1574   struct TALER_DenominationHashP **denom_hs)
   1575 {
   1576   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1577 
   1578   info->num = num;
   1579   info->typ = TALER_PQ_array_of_denom_hash;
   1580   GNUNET_assert (GNUNET_OK ==
   1581                  GNUNET_PQ_get_oid_by_name (db,
   1582                                             "bytea",
   1583                                             &info->oid));
   1584   {
   1585     struct GNUNET_PQ_ResultSpec res = {
   1586       .conv = extract_array_generic,
   1587       .cleaner = &array_cleanup,
   1588       .dst = (void *) denom_hs,
   1589       .fname = name,
   1590       .cls = info
   1591     };
   1592 
   1593     return res;
   1594   }
   1595 }
   1596 
   1597 
   1598 struct GNUNET_PQ_ResultSpec
   1599 TALER_PQ_result_spec_array_amount (
   1600   struct GNUNET_PQ_Context *db,
   1601   const char *name,
   1602   const char *currency,
   1603   size_t *num,
   1604   struct TALER_Amount **amounts)
   1605 {
   1606   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1607 
   1608   info->num = num;
   1609   info->typ = TALER_PQ_array_of_amount;
   1610   info->db = db;
   1611   GNUNET_assert (GNUNET_OK ==
   1612                  GNUNET_PQ_get_oid_by_name (db,
   1613                                             "taler_amount",
   1614                                             &info->oid));
   1615 
   1616   {
   1617     size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
   1618                               strlen (currency));
   1619     GNUNET_memcpy (&info->currency,
   1620                    currency,
   1621                    clen);
   1622   }
   1623   {
   1624     struct GNUNET_PQ_ResultSpec res = {
   1625       .conv = extract_array_generic,
   1626       .cleaner = &array_cleanup,
   1627       .dst = (void *) amounts,
   1628       .fname = name,
   1629       .cls = info,
   1630     };
   1631 
   1632     return res;
   1633   }
   1634 }
   1635 
   1636 
   1637 struct GNUNET_PQ_ResultSpec
   1638 TALER_PQ_result_spec_array_amount_with_currency (
   1639   struct GNUNET_PQ_Context *db,
   1640   const char *name,
   1641   size_t *num,
   1642   struct TALER_Amount **amounts)
   1643 {
   1644   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1645 
   1646   info->num = num;
   1647   info->typ = TALER_PQ_array_of_amount_currency;
   1648   info->db = db;
   1649   GNUNET_assert (GNUNET_OK ==
   1650                  GNUNET_PQ_get_oid_by_name (db,
   1651                                             "taler_amount_currency",
   1652                                             &info->oid));
   1653 
   1654   {
   1655     struct GNUNET_PQ_ResultSpec res = {
   1656       .conv = extract_array_generic,
   1657       .cleaner = &array_cleanup,
   1658       .dst = (void *) amounts,
   1659       .fname = name,
   1660       .cls = info,
   1661     };
   1662 
   1663     return res;
   1664   }
   1665 }
   1666 
   1667 
   1668 struct GNUNET_PQ_ResultSpec
   1669 TALER_PQ_result_spec_array_hash_code (
   1670   struct GNUNET_PQ_Context *db,
   1671   const char *name,
   1672   size_t *num,
   1673   struct GNUNET_HashCode **hashes)
   1674 {
   1675   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1676 
   1677   info->num = num;
   1678   info->typ = TALER_PQ_array_of_hash_code;
   1679   info->db = db;
   1680   GNUNET_assert (GNUNET_OK ==
   1681                  GNUNET_PQ_get_oid_by_name (db,
   1682                                             "gnunet_hashcode",
   1683                                             &info->oid));
   1684   {
   1685     struct GNUNET_PQ_ResultSpec res = {
   1686       .conv = extract_array_generic,
   1687       .cleaner = &array_cleanup,
   1688       .dst = (void *) hashes,
   1689       .fname = name,
   1690       .cls = info,
   1691     };
   1692 
   1693     return res;
   1694   }
   1695 }
   1696 
   1697 
   1698 struct GNUNET_PQ_ResultSpec
   1699 TALER_PQ_result_spec_array_cs_r_pub (
   1700   struct GNUNET_PQ_Context *db,
   1701   const char *name,
   1702   size_t *num,
   1703   struct GNUNET_CRYPTO_CSPublicRPairP **cs_r_pubs)
   1704 {
   1705   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1706 
   1707   info->num = num;
   1708   info->typ = TALER_PQ_array_of_cs_r_pub;
   1709   GNUNET_assert (GNUNET_OK ==
   1710                  GNUNET_PQ_get_oid_by_name (db,
   1711                                             "bytea",
   1712                                             &info->oid));
   1713   {
   1714     struct GNUNET_PQ_ResultSpec res = {
   1715       .conv = extract_array_generic,
   1716       .cleaner = &array_cleanup,
   1717       .dst = (void *) cs_r_pubs,
   1718       .fname = name,
   1719       .cls = info
   1720     };
   1721 
   1722     return res;
   1723   }
   1724 }
   1725 
   1726 
   1727 /* end of pq_result_helper.c */