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


      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 <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 
   1185   /* Report if this field is empty */
   1186   if (0 == (size_t) data_sz)
   1187     return GNUNET_NO;
   1188 
   1189   data = PQgetvalue (result, row, col_num);
   1190 
   1191   if (sizeof(header) > (size_t) data_sz)
   1192   {
   1193     uint32_t ndim;
   1194 
   1195     /* data_sz is shorter than header if the
   1196        array length is 0, in which case ndim is 0! */
   1197     FAIL_IF (sizeof(uint32_t) > (size_t) data_sz);
   1198     memcpy (&ndim,
   1199             data,
   1200             sizeof (ndim));
   1201     FAIL_IF (0 != ndim);
   1202     *info->num = 0;
   1203     return GNUNET_OK;
   1204   }
   1205   FAIL_IF (sizeof(header) > (size_t) data_sz);
   1206   FAIL_IF (NULL == data);
   1207 
   1208   {
   1209     struct GNUNET_PQ_ArrayHeader_P *h =
   1210       (struct GNUNET_PQ_ArrayHeader_P *) data;
   1211 
   1212     header.ndim = ntohl (h->ndim);
   1213     header.has_null = ntohl (h->has_null);
   1214     header.oid = ntohl (h->oid);
   1215     header.dim = ntohl (h->dim);
   1216     header.lbound = ntohl (h->lbound);
   1217 
   1218     FAIL_IF (1 != header.ndim);
   1219     FAIL_IF (INT_MAX <= header.dim);
   1220     FAIL_IF (0 != header.has_null);
   1221     FAIL_IF (1 != header.lbound);
   1222     FAIL_IF (info->oid != header.oid);
   1223   }
   1224 
   1225   if (NULL != info->num)
   1226     *info->num = header.dim;
   1227 
   1228   {
   1229     char *in = data + sizeof(header);
   1230 
   1231     switch (info->typ)
   1232     {
   1233     case TALER_PQ_array_of_amount:
   1234       {
   1235         struct TALER_Amount *amounts;
   1236         if (NULL != dst_size)
   1237           *dst_size = sizeof(struct TALER_Amount) * (header.dim);
   1238 
   1239         amounts = GNUNET_new_array (header.dim,
   1240                                     struct TALER_Amount);
   1241         *((void **) dst) = amounts;
   1242 
   1243         for (uint32_t i = 0; i < header.dim; i++)
   1244         {
   1245           struct TALER_PQ_AmountP ap;
   1246           struct TALER_Amount *amount = &amounts[i];
   1247           uint32_t val;
   1248           size_t sz;
   1249 
   1250           GNUNET_memcpy (&val,
   1251                          in,
   1252                          sizeof(val));
   1253           sz =  ntohl (val);
   1254           in += sizeof(val);
   1255 
   1256           /* total size for this array-entry */
   1257           FAIL_IF (sizeof(ap) != sz);
   1258 
   1259           GNUNET_memcpy (&ap,
   1260                          in,
   1261                          sz);
   1262           FAIL_IF (2 != ntohl (ap.cnt));
   1263 
   1264           amount->value = GNUNET_ntohll (ap.v);
   1265           amount->fraction = ntohl (ap.f);
   1266           GNUNET_memcpy (amount->currency,
   1267                          info->currency,
   1268                          TALER_CURRENCY_LEN);
   1269 
   1270           in += sizeof(struct TALER_PQ_AmountP);
   1271         }
   1272         return GNUNET_OK;
   1273       }
   1274     case TALER_PQ_array_of_amount_currency:
   1275       {
   1276         struct TALER_Amount *amounts;
   1277         if (NULL != dst_size)
   1278           *dst_size = sizeof(struct TALER_Amount) * (header.dim);
   1279 
   1280         amounts = GNUNET_new_array (header.dim,
   1281                                     struct TALER_Amount);
   1282         *((void **) dst) = amounts;
   1283 
   1284         for (uint32_t i = 0; i < header.dim; i++)
   1285         {
   1286           struct TALER_PQ_AmountCurrencyP ap;
   1287           struct TALER_Amount *amount = &amounts[i];
   1288           uint32_t val;
   1289           size_t sz;
   1290 
   1291           GNUNET_memcpy (&val,
   1292                          in,
   1293                          sizeof(val));
   1294           sz =  ntohl (val);
   1295           in += sizeof(val);
   1296 
   1297           FAIL_IF ( (sz >= sizeof(ap)) ||
   1298                     (sz <= sizeof(ap) - TALER_CURRENCY_LEN) );
   1299 
   1300           memset (&ap,
   1301                   0,
   1302                   sizeof(ap));
   1303           GNUNET_memcpy (&ap,
   1304                          in,
   1305                          sz);
   1306           FAIL_IF (3 != ntohl (ap.cnt));
   1307 
   1308           amount->value = GNUNET_ntohll (ap.v);
   1309           amount->fraction = ntohl (ap.f);
   1310           GNUNET_memcpy (amount->currency,
   1311                          ap.c,
   1312                          TALER_CURRENCY_LEN);
   1313 
   1314           FAIL_IF ('\0' != amount->currency[TALER_CURRENCY_LEN - 1]);
   1315           FAIL_IF (amount->value >= TALER_AMOUNT_MAX_VALUE);
   1316           FAIL_IF (amount->fraction >= TALER_AMOUNT_FRAC_BASE);
   1317 
   1318           in += sz;
   1319         }
   1320         return GNUNET_OK;
   1321       }
   1322     case TALER_PQ_array_of_denom_hash:
   1323       if (NULL != dst_size)
   1324         *dst_size = sizeof(struct TALER_DenominationHashP) * (header.dim);
   1325       out = GNUNET_new_array (header.dim,
   1326                               struct TALER_DenominationHashP);
   1327       *((void **) dst) = out;
   1328       for (uint32_t i = 0; i < header.dim; i++)
   1329       {
   1330         uint32_t val;
   1331         size_t sz;
   1332 
   1333         GNUNET_memcpy (&val,
   1334                        in,
   1335                        sizeof(val));
   1336         sz =  ntohl (val);
   1337         FAIL_IF (sz != sizeof(struct TALER_DenominationHashP));
   1338         in += sizeof(uint32_t);
   1339         *(struct TALER_DenominationHashP *) out =
   1340           *(struct TALER_DenominationHashP *) in;
   1341         in += sz;
   1342         out += sz;
   1343       }
   1344       return GNUNET_OK;
   1345 
   1346     case TALER_PQ_array_of_hash_code:
   1347       if (NULL != dst_size)
   1348         *dst_size = sizeof(struct GNUNET_HashCode) * (header.dim);
   1349       out = GNUNET_new_array (header.dim,
   1350                               struct GNUNET_HashCode);
   1351       *((void **) dst) = out;
   1352       for (uint32_t i = 0; i < header.dim; i++)
   1353       {
   1354         uint32_t val;
   1355         size_t sz;
   1356 
   1357         GNUNET_memcpy (&val,
   1358                        in,
   1359                        sizeof(val));
   1360         sz =  ntohl (val);
   1361         FAIL_IF (sz != sizeof(struct GNUNET_HashCode));
   1362         in += sizeof(uint32_t);
   1363         *(struct GNUNET_HashCode *) out =
   1364           *(struct GNUNET_HashCode *) in;
   1365         in += sz;
   1366         out += sz;
   1367       }
   1368       return GNUNET_OK;
   1369 
   1370     case TALER_PQ_array_of_blinded_coin_hash:
   1371       if (NULL != dst_size)
   1372         *dst_size = sizeof(struct TALER_BlindedCoinHashP) * (header.dim);
   1373       out = GNUNET_new_array (header.dim,
   1374                               struct TALER_BlindedCoinHashP);
   1375       *((void **) dst) = out;
   1376       for (uint32_t i = 0; i < header.dim; i++)
   1377       {
   1378         uint32_t val;
   1379         size_t sz;
   1380 
   1381         GNUNET_memcpy (&val,
   1382                        in,
   1383                        sizeof(val));
   1384         sz =  ntohl (val);
   1385         FAIL_IF (sz != sizeof(struct TALER_BlindedCoinHashP));
   1386         in += sizeof(uint32_t);
   1387         *(struct TALER_BlindedCoinHashP *) out =
   1388           *(struct TALER_BlindedCoinHashP *) in;
   1389         in += sz;
   1390         out += sz;
   1391       }
   1392       return GNUNET_OK;
   1393 
   1394     case TALER_PQ_array_of_cs_r_pub:
   1395       if (NULL != dst_size)
   1396         *dst_size = sizeof(struct GNUNET_CRYPTO_CSPublicRPairP) * (header.dim);
   1397       out = GNUNET_new_array (header.dim,
   1398                               struct GNUNET_CRYPTO_CSPublicRPairP);
   1399       *((void **) dst) = out;
   1400       for (uint32_t i = 0; i < header.dim; i++)
   1401       {
   1402         uint32_t val;
   1403         size_t sz;
   1404 
   1405         GNUNET_memcpy (&val,
   1406                        in,
   1407                        sizeof(val));
   1408         sz =  ntohl (val);
   1409         FAIL_IF (sz != sizeof(struct GNUNET_CRYPTO_CSPublicRPairP));
   1410         in += sizeof(uint32_t);
   1411         *(struct GNUNET_CRYPTO_CSPublicRPairP *) out =
   1412           *(struct GNUNET_CRYPTO_CSPublicRPairP *) in;
   1413         in += sz;
   1414         out += sz;
   1415       }
   1416       return GNUNET_OK;
   1417 
   1418     case TALER_PQ_array_of_blinded_denom_sig:
   1419       {
   1420         struct TALER_BlindedDenominationSignature *denom_sigs;
   1421         if (0 == header.dim)
   1422         {
   1423           if (NULL != dst_size)
   1424             *dst_size = 0;
   1425           break;
   1426         }
   1427 
   1428         denom_sigs = GNUNET_new_array (header.dim,
   1429                                        struct TALER_BlindedDenominationSignature);
   1430         *((void **) dst) = denom_sigs;
   1431 
   1432         /* copy data */
   1433         for (uint32_t i = 0; i < header.dim; i++)
   1434         {
   1435           struct TALER_BlindedDenominationSignature *denom_sig = &denom_sigs[i];
   1436           struct GNUNET_CRYPTO_BlindedSignature *bs;
   1437           uint32_t be[2];
   1438           uint32_t val;
   1439           size_t sz;
   1440 
   1441           GNUNET_memcpy (&val,
   1442                          in,
   1443                          sizeof(val));
   1444           sz = ntohl (val);
   1445           FAIL_IF (sizeof(be) > sz);
   1446 
   1447           in += sizeof(val);
   1448           GNUNET_memcpy (&be,
   1449                          in,
   1450                          sizeof(be));
   1451           FAIL_IF (0x01 != ntohl (be[1]));  /* magic marker: blinded */
   1452 
   1453           in += sizeof(be);
   1454           sz -= sizeof(be);
   1455           bs = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
   1456           bs->cipher = ntohl (be[0]);
   1457           bs->rc = 1;
   1458           switch (bs->cipher)
   1459           {
   1460           case GNUNET_CRYPTO_BSA_RSA:
   1461             bs->details.blinded_rsa_signature
   1462               = GNUNET_CRYPTO_rsa_signature_decode (in,
   1463                                                     sz);
   1464             if (NULL == bs->details.blinded_rsa_signature)
   1465             {
   1466               GNUNET_free (bs);
   1467               FAIL_IF (true);
   1468             }
   1469             break;
   1470           case GNUNET_CRYPTO_BSA_CS:
   1471             if (sizeof(bs->details.blinded_cs_answer) != sz)
   1472             {
   1473               GNUNET_free (bs);
   1474               FAIL_IF (true);
   1475             }
   1476             GNUNET_memcpy (&bs->details.blinded_cs_answer,
   1477                            in,
   1478                            sz);
   1479             break;
   1480           default:
   1481             GNUNET_free (bs);
   1482             FAIL_IF (true);
   1483           }
   1484           denom_sig->blinded_sig = bs;
   1485           in += sz;
   1486         }
   1487         return GNUNET_OK;
   1488       }
   1489     default:
   1490       FAIL_IF (true);
   1491     }
   1492   }
   1493 FAIL:
   1494   GNUNET_free (*(void **) dst);
   1495   return GNUNET_SYSERR;
   1496 #undef FAIL_IF
   1497 }
   1498 
   1499 
   1500 /**
   1501  * Cleanup of the data and closure of an array spec.
   1502  */
   1503 static void
   1504 array_cleanup (void *cls,
   1505                void *rd)
   1506 {
   1507   struct ArrayResultCls *info = cls;
   1508   void **dst = rd;
   1509 
   1510   if ( (0 == info->same_size) &&
   1511        (NULL != info->sizes) )
   1512     GNUNET_free (*(info->sizes));
   1513 
   1514   /* Clean up signatures, if applicable */
   1515   if ((TALER_PQ_array_of_blinded_denom_sig == info->typ) &&
   1516       (NULL != *dst))
   1517   {
   1518     struct TALER_BlindedDenominationSignature *denom_sigs = *dst;
   1519 
   1520     GNUNET_assert (NULL != info->num);
   1521     for (size_t i = 0; i < *info->num; i++)
   1522       GNUNET_free (denom_sigs[i].blinded_sig);
   1523   }
   1524   GNUNET_free (info);
   1525   GNUNET_free (*dst);
   1526   *dst = NULL;
   1527 }
   1528 
   1529 
   1530 struct GNUNET_PQ_ResultSpec
   1531 TALER_PQ_result_spec_array_blinded_denom_sig (
   1532   struct GNUNET_PQ_Context *db,
   1533   const char *name,
   1534   size_t *num,
   1535   struct TALER_BlindedDenominationSignature **denom_sigs)
   1536 {
   1537   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1538 
   1539   info->num = num;
   1540   info->typ = TALER_PQ_array_of_blinded_denom_sig;
   1541   GNUNET_assert (GNUNET_OK ==
   1542                  GNUNET_PQ_get_oid_by_name (db,
   1543                                             "bytea",
   1544                                             &info->oid));
   1545   {
   1546     struct GNUNET_PQ_ResultSpec res = {
   1547       .conv = extract_array_generic,
   1548       .cleaner = &array_cleanup,
   1549       .dst = (void *) denom_sigs,
   1550       .fname = name,
   1551       .cls = info
   1552     };
   1553 
   1554     return res;
   1555   }
   1556 }
   1557 
   1558 
   1559 struct GNUNET_PQ_ResultSpec
   1560 TALER_PQ_result_spec_array_blinded_coin_hash (
   1561   struct GNUNET_PQ_Context *db,
   1562   const char *name,
   1563   size_t *num,
   1564   struct TALER_BlindedCoinHashP **h_coin_evs)
   1565 {
   1566   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1567 
   1568   info->num = num;
   1569   info->typ = TALER_PQ_array_of_blinded_coin_hash;
   1570   GNUNET_assert (GNUNET_OK ==
   1571                  GNUNET_PQ_get_oid_by_name (db,
   1572                                             "bytea",
   1573                                             &info->oid));
   1574   {
   1575     struct GNUNET_PQ_ResultSpec res = {
   1576       .conv = extract_array_generic,
   1577       .cleaner = &array_cleanup,
   1578       .dst = (void *) h_coin_evs,
   1579       .fname = name,
   1580       .cls = info
   1581     };
   1582 
   1583     return res;
   1584   }
   1585 }
   1586 
   1587 
   1588 struct GNUNET_PQ_ResultSpec
   1589 TALER_PQ_result_spec_array_denom_hash (
   1590   struct GNUNET_PQ_Context *db,
   1591   const char *name,
   1592   size_t *num,
   1593   struct TALER_DenominationHashP **denom_hs)
   1594 {
   1595   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1596 
   1597   info->num = num;
   1598   info->typ = TALER_PQ_array_of_denom_hash;
   1599   GNUNET_assert (GNUNET_OK ==
   1600                  GNUNET_PQ_get_oid_by_name (db,
   1601                                             "bytea",
   1602                                             &info->oid));
   1603   {
   1604     struct GNUNET_PQ_ResultSpec res = {
   1605       .conv = extract_array_generic,
   1606       .cleaner = &array_cleanup,
   1607       .dst = (void *) denom_hs,
   1608       .fname = name,
   1609       .cls = info
   1610     };
   1611 
   1612     return res;
   1613   }
   1614 }
   1615 
   1616 
   1617 struct GNUNET_PQ_ResultSpec
   1618 TALER_PQ_result_spec_array_amount (
   1619   struct GNUNET_PQ_Context *db,
   1620   const char *name,
   1621   const char *currency,
   1622   size_t *num,
   1623   struct TALER_Amount **amounts)
   1624 {
   1625   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1626 
   1627   info->num = num;
   1628   info->typ = TALER_PQ_array_of_amount;
   1629   info->db = db;
   1630   GNUNET_assert (GNUNET_OK ==
   1631                  GNUNET_PQ_get_oid_by_name (db,
   1632                                             "taler_amount",
   1633                                             &info->oid));
   1634 
   1635   {
   1636     size_t clen = GNUNET_MIN (TALER_CURRENCY_LEN - 1,
   1637                               strlen (currency));
   1638     GNUNET_memcpy (&info->currency,
   1639                    currency,
   1640                    clen);
   1641   }
   1642   {
   1643     struct GNUNET_PQ_ResultSpec res = {
   1644       .conv = extract_array_generic,
   1645       .cleaner = &array_cleanup,
   1646       .dst = (void *) amounts,
   1647       .fname = name,
   1648       .cls = info,
   1649     };
   1650 
   1651     return res;
   1652   }
   1653 }
   1654 
   1655 
   1656 struct GNUNET_PQ_ResultSpec
   1657 TALER_PQ_result_spec_array_amount_with_currency (
   1658   struct GNUNET_PQ_Context *db,
   1659   const char *name,
   1660   size_t *num,
   1661   struct TALER_Amount **amounts)
   1662 {
   1663   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1664 
   1665   info->num = num;
   1666   info->typ = TALER_PQ_array_of_amount_currency;
   1667   info->db = db;
   1668   GNUNET_assert (GNUNET_OK ==
   1669                  GNUNET_PQ_get_oid_by_name (db,
   1670                                             "taler_amount_currency",
   1671                                             &info->oid));
   1672 
   1673   {
   1674     struct GNUNET_PQ_ResultSpec res = {
   1675       .conv = extract_array_generic,
   1676       .cleaner = &array_cleanup,
   1677       .dst = (void *) amounts,
   1678       .fname = name,
   1679       .cls = info,
   1680     };
   1681 
   1682     return res;
   1683   }
   1684 }
   1685 
   1686 
   1687 struct GNUNET_PQ_ResultSpec
   1688 TALER_PQ_result_spec_array_hash_code (
   1689   struct GNUNET_PQ_Context *db,
   1690   const char *name,
   1691   size_t *num,
   1692   struct GNUNET_HashCode **hashes)
   1693 {
   1694   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1695 
   1696   info->num = num;
   1697   info->typ = TALER_PQ_array_of_hash_code;
   1698   info->db = db;
   1699   GNUNET_assert (GNUNET_OK ==
   1700                  GNUNET_PQ_get_oid_by_name (db,
   1701                                             "gnunet_hashcode",
   1702                                             &info->oid));
   1703   {
   1704     struct GNUNET_PQ_ResultSpec res = {
   1705       .conv = extract_array_generic,
   1706       .cleaner = &array_cleanup,
   1707       .dst = (void *) hashes,
   1708       .fname = name,
   1709       .cls = info,
   1710     };
   1711 
   1712     return res;
   1713   }
   1714 }
   1715 
   1716 
   1717 struct GNUNET_PQ_ResultSpec
   1718 TALER_PQ_result_spec_array_cs_r_pub (
   1719   struct GNUNET_PQ_Context *db,
   1720   const char *name,
   1721   size_t *num,
   1722   struct GNUNET_CRYPTO_CSPublicRPairP **cs_r_pubs)
   1723 {
   1724   struct ArrayResultCls *info = GNUNET_new (struct ArrayResultCls);
   1725 
   1726   info->num = num;
   1727   info->typ = TALER_PQ_array_of_cs_r_pub;
   1728   GNUNET_assert (GNUNET_OK ==
   1729                  GNUNET_PQ_get_oid_by_name (db,
   1730                                             "bytea",
   1731                                             &info->oid));
   1732   {
   1733     struct GNUNET_PQ_ResultSpec res = {
   1734       .conv = extract_array_generic,
   1735       .cleaner = &array_cleanup,
   1736       .dst = (void *) cs_r_pubs,
   1737       .fname = name,
   1738       .cls = info
   1739     };
   1740 
   1741     return res;
   1742   }
   1743 }
   1744 
   1745 
   1746 /* end of pq_result_helper.c */