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 (45311B)


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