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


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