LCOV - code coverage report
Current view: top level - kyclogic - kyclogic_api.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 80 415 19.3 %
Date: 2022-08-25 06:15:09 Functions: 7 21 33.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero 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 Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file kyclogic_api.c
      18             :  * @brief server-side KYC API
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include "taler_kyclogic_lib.h"
      23             : 
      24             : /**
      25             :  * Information about a KYC provider.
      26             :  */
      27             : struct TALER_KYCLOGIC_KycProvider;
      28             : 
      29             : 
      30             : /**
      31             :  * Abstract representation of a KYC check.
      32             :  */
      33             : struct TALER_KYCLOGIC_KycCheck
      34             : {
      35             :   /**
      36             :    * Human-readable name given to the KYC check.
      37             :    */
      38             :   char *name;
      39             : 
      40             :   /**
      41             :    * Array of @e num_providers providers that offer this type of KYC check.
      42             :    */
      43             :   struct TALER_KYCLOGIC_KycProvider **providers;
      44             : 
      45             :   /**
      46             :    * Length of the @e providers array.
      47             :    */
      48             :   unsigned int num_providers;
      49             : 
      50             : };
      51             : 
      52             : 
      53             : struct TALER_KYCLOGIC_KycProvider
      54             : {
      55             :   /**
      56             :    * Name of the provider (configuration section name).
      57             :    */
      58             :   const char *provider_section_name;
      59             : 
      60             :   /**
      61             :    * Array of @e num_checks checks performed by this provider.
      62             :    */
      63             :   struct TALER_KYCLOGIC_KycCheck **provided_checks;
      64             : 
      65             :   /**
      66             :    * Logic to run for this provider.
      67             :    */
      68             :   struct TALER_KYCLOGIC_Plugin *logic;
      69             : 
      70             :   /**
      71             :    * @e provider_section_name specific details to
      72             :    * pass to the @e logic functions.
      73             :    */
      74             :   struct TALER_KYCLOGIC_ProviderDetails *pd;
      75             : 
      76             :   /**
      77             :    * Cost of running this provider's KYC.
      78             :    */
      79             :   unsigned long long cost;
      80             : 
      81             :   /**
      82             :    * Length of the @e checks array.
      83             :    */
      84             :   unsigned int num_checks;
      85             : 
      86             :   /**
      87             :    * Type of user this provider supports.
      88             :    */
      89             :   enum TALER_KYCLOGIC_KycUserType user_type;
      90             : };
      91             : 
      92             : 
      93             : /**
      94             :  * Condition that triggers a need to perform KYC.
      95             :  */
      96             : struct TALER_KYCLOGIC_KycTrigger
      97             : {
      98             : 
      99             :   /**
     100             :    * Timeframe to consider for computing the amount
     101             :    * to compare against the @e limit.  Zero for the
     102             :    * wallet balance trigger (as not applicable).
     103             :    */
     104             :   struct GNUNET_TIME_Relative timeframe;
     105             : 
     106             :   /**
     107             :    * Maximum amount that can be transacted until
     108             :    * the rule triggers.
     109             :    */
     110             :   struct TALER_Amount threshold;
     111             : 
     112             :   /**
     113             :    * Array of @e num_checks checks to apply on this trigger.
     114             :    */
     115             :   struct TALER_KYCLOGIC_KycCheck **required_checks;
     116             : 
     117             :   /**
     118             :    * Length of the @e checks array.
     119             :    */
     120             :   unsigned int num_checks;
     121             : 
     122             :   /**
     123             :    * What event is this trigger for?
     124             :    */
     125             :   enum TALER_KYCLOGIC_KycTriggerEvent trigger;
     126             : 
     127             : };
     128             : 
     129             : 
     130             : /**
     131             :  * Array of @e num_kyc_logics KYC logic plugins we have loaded.
     132             :  */
     133             : static struct TALER_KYCLOGIC_Plugin **kyc_logics;
     134             : 
     135             : /**
     136             :  * Length of the #kyc_logics array.
     137             :  */
     138             : static unsigned int num_kyc_logics;
     139             : 
     140             : /**
     141             :  * Array of @e num_kyc_checks known types of
     142             :  * KYC checks.
     143             :  */
     144             : static struct TALER_KYCLOGIC_KycCheck **kyc_checks;
     145             : 
     146             : /**
     147             :  * Length of the #kyc_checks array.
     148             :  */
     149             : static unsigned int num_kyc_checks;
     150             : 
     151             : /**
     152             :  * Array of configured triggers.
     153             :  */
     154             : static struct TALER_KYCLOGIC_KycTrigger **kyc_triggers;
     155             : 
     156             : /**
     157             :  * Length of the #kyc_triggers array.
     158             :  */
     159             : static unsigned int num_kyc_triggers;
     160             : 
     161             : /**
     162             :  * Array of configured providers.
     163             :  */
     164             : static struct TALER_KYCLOGIC_KycProvider **kyc_providers;
     165             : 
     166             : /**
     167             :  * Length of the #kyc_providers array.
     168             :  */
     169             : static unsigned int num_kyc_providers;
     170             : 
     171             : 
     172             : enum GNUNET_GenericReturnValue
     173           0 : TALER_KYCLOGIC_kyc_trigger_from_string (const char *trigger_s,
     174             :                                         enum TALER_KYCLOGIC_KycTriggerEvent *
     175             :                                         trigger)
     176             : {
     177             :   struct
     178             :   {
     179             :     const char *in;
     180             :     enum TALER_KYCLOGIC_KycTriggerEvent out;
     181           0 :   } map [] = {
     182             :     { "withdraw", TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW },
     183             :     { "deposit", TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT  },
     184             :     { "merge", TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE },
     185             :     { "balance", TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE },
     186             :     { NULL, 0 }
     187             :   };
     188             : 
     189           0 :   for (unsigned int i = 0; NULL != map[i].in; i++)
     190           0 :     if (0 == strcasecmp (map[i].in,
     191             :                          trigger_s))
     192             :     {
     193           0 :       *trigger = map[i].out;
     194           0 :       return GNUNET_OK;
     195             :     }
     196           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     197             :               "Invalid KYC trigger `%s'\n",
     198             :               trigger_s);
     199           0 :   return GNUNET_SYSERR;
     200             : }
     201             : 
     202             : 
     203             : const char *
     204           0 : TALER_KYCLOGIC_kyc_trigger2s (enum TALER_KYCLOGIC_KycTriggerEvent trigger)
     205             : {
     206           0 :   switch (trigger)
     207             :   {
     208           0 :   case TALER_KYCLOGIC_KYC_TRIGGER_WITHDRAW:
     209           0 :     return "withdraw";
     210           0 :   case TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT:
     211           0 :     return "deposit";
     212           0 :   case TALER_KYCLOGIC_KYC_TRIGGER_P2P_RECEIVE:
     213           0 :     return "merge";
     214           0 :   case TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE:
     215           0 :     return "balance";
     216             :   }
     217           0 :   GNUNET_break (0);
     218           0 :   return NULL;
     219             : }
     220             : 
     221             : 
     222             : enum GNUNET_GenericReturnValue
     223           3 : TALER_KYCLOGIC_kyc_user_type_from_string (const char *ut_s,
     224             :                                           enum TALER_KYCLOGIC_KycUserType *ut)
     225             : {
     226             :   struct
     227             :   {
     228             :     const char *in;
     229             :     enum TALER_KYCLOGIC_KycUserType out;
     230           3 :   } map [] = {
     231             :     { "individual", TALER_KYCLOGIC_KYC_UT_INDIVIDUAL },
     232             :     { "business", TALER_KYCLOGIC_KYC_UT_BUSINESS  },
     233             :     { NULL, 0 }
     234             :   };
     235             : 
     236           3 :   for (unsigned int i = 0; NULL != map[i].in; i++)
     237           3 :     if (0 == strcasecmp (map[i].in,
     238             :                          ut_s))
     239             :     {
     240           3 :       *ut = map[i].out;
     241           3 :       return GNUNET_OK;
     242             :     }
     243           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     244             :               "Invalid user type `%s'\n",
     245             :               ut_s);
     246           0 :   return GNUNET_SYSERR;
     247             : }
     248             : 
     249             : 
     250             : const char *
     251           0 : TALER_KYCLOGIC_kyc_user_type2s (enum TALER_KYCLOGIC_KycUserType ut)
     252             : {
     253           0 :   switch (ut)
     254             :   {
     255           0 :   case TALER_KYCLOGIC_KYC_UT_INDIVIDUAL:
     256           0 :     return "individual";
     257           0 :   case TALER_KYCLOGIC_KYC_UT_BUSINESS:
     258           0 :     return "business";
     259             :   }
     260           0 :   GNUNET_break (0);
     261           0 :   return NULL;
     262             : }
     263             : 
     264             : 
     265             : /**
     266             :  * Load KYC logic plugin.
     267             :  *
     268             :  * @param cfg configuration to use
     269             :  * @param name name of the plugin
     270             :  * @return NULL on error
     271             :  */
     272             : static struct TALER_KYCLOGIC_Plugin *
     273           3 : load_logic (const struct GNUNET_CONFIGURATION_Handle *cfg,
     274             :             const char *name)
     275             : {
     276             :   char *lib_name;
     277             :   struct TALER_KYCLOGIC_Plugin *plugin;
     278             : 
     279           3 :   GNUNET_asprintf (&lib_name,
     280             :                    "libtaler_plugin_kyclogic_%s",
     281             :                    name);
     282           6 :   for (unsigned int i = 0; i<num_kyc_logics; i++)
     283           3 :     if (0 == strcmp (lib_name,
     284           3 :                      kyc_logics[i]->library_name))
     285             :     {
     286           0 :       GNUNET_free (lib_name);
     287           0 :       return kyc_logics[i];
     288             :     }
     289           3 :   plugin = GNUNET_PLUGIN_load (lib_name,
     290             :                                (void *) cfg);
     291           3 :   if (NULL == plugin)
     292             :   {
     293           0 :     GNUNET_free (lib_name);
     294           0 :     return NULL;
     295             :   }
     296           3 :   plugin->library_name = lib_name;
     297           3 :   plugin->name = GNUNET_strdup (name);
     298           3 :   GNUNET_array_append (kyc_logics,
     299             :                        num_kyc_logics,
     300             :                        plugin);
     301           3 :   return plugin;
     302             : }
     303             : 
     304             : 
     305             : /**
     306             :  * Add check type to global array of checks.
     307             :  * First checks if the type already exists, otherwise
     308             :  * adds a new one.
     309             :  *
     310             :  * @param check name of the check
     311             :  * @return pointer into the global list
     312             :  */
     313             : static struct TALER_KYCLOGIC_KycCheck *
     314           3 : add_check (const char *check)
     315             : {
     316             :   struct TALER_KYCLOGIC_KycCheck *kc;
     317             : 
     318           3 :   for (unsigned int i = 0; i<num_kyc_checks; i++)
     319           2 :     if (0 == strcasecmp (check,
     320           2 :                          kyc_checks[i]->name))
     321           2 :       return kyc_checks[i];
     322           1 :   kc = GNUNET_new (struct TALER_KYCLOGIC_KycCheck);
     323           1 :   kc->name = GNUNET_strdup (check);
     324           1 :   GNUNET_array_append (kyc_checks,
     325             :                        num_kyc_checks,
     326             :                        kc);
     327           1 :   return kc;
     328             : }
     329             : 
     330             : 
     331             : /**
     332             :  * Parse list of checks from @a checks and build an
     333             :  * array of aliases into the global checks array
     334             :  * in @a provided_checks.
     335             :  *
     336             :  * @param[in,out] checks list of checks; clobbered
     337             :  * @param[out] p_checks where to put array of aliases
     338             :  * @param[out] num_p_checks set to length of @a p_checks array
     339             :  */
     340             : static void
     341           3 : add_checks (char *checks,
     342             :             struct TALER_KYCLOGIC_KycCheck ***p_checks,
     343             :             unsigned int *num_p_checks)
     344             : {
     345             :   char *sptr;
     346           3 :   struct TALER_KYCLOGIC_KycCheck **rchecks = NULL;
     347           3 :   unsigned int num_rchecks = 0;
     348             : 
     349           6 :   for (char *tok = strtok_r (checks, " ", &sptr);
     350             :        NULL != tok;
     351           3 :        tok = strtok_r (NULL, " ", &sptr))
     352             :   {
     353             :     struct TALER_KYCLOGIC_KycCheck *kc;
     354             : 
     355           3 :     kc = add_check (tok);
     356           3 :     GNUNET_array_append (rchecks,
     357             :                          num_rchecks,
     358             :                          kc);
     359             :   }
     360           3 :   *p_checks = rchecks;
     361           3 :   *num_p_checks = num_rchecks;
     362           3 : }
     363             : 
     364             : 
     365             : /**
     366             :  * Parse configuration of a KYC provider.
     367             :  *
     368             :  * @param cfg configuration to parse
     369             :  * @param section name of the section to analyze
     370             :  * @return #GNUNET_OK on success
     371             :  */
     372             : static enum GNUNET_GenericReturnValue
     373           3 : add_provider (const struct GNUNET_CONFIGURATION_Handle *cfg,
     374             :               const char *section)
     375             : {
     376             :   unsigned long long cost;
     377             :   char *logic;
     378             :   char *ut_s;
     379             :   enum TALER_KYCLOGIC_KycUserType ut;
     380             :   char *checks;
     381             :   struct TALER_KYCLOGIC_Plugin *lp;
     382             : 
     383           3 :   if (GNUNET_OK !=
     384           3 :       GNUNET_CONFIGURATION_get_value_number (cfg,
     385             :                                              section,
     386             :                                              "COST",
     387             :                                              &cost))
     388             :   {
     389           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     390             :                                section,
     391             :                                "COST",
     392             :                                "number required");
     393           0 :     return GNUNET_SYSERR;
     394             :   }
     395           3 :   if (GNUNET_OK !=
     396           3 :       GNUNET_CONFIGURATION_get_value_string (cfg,
     397             :                                              section,
     398             :                                              "USER_TYPE",
     399             :                                              &ut_s))
     400             :   {
     401           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     402             :                                section,
     403             :                                "USER_TYPE");
     404           0 :     return GNUNET_SYSERR;
     405             :   }
     406           3 :   if (GNUNET_OK !=
     407           3 :       TALER_KYCLOGIC_kyc_user_type_from_string (ut_s,
     408             :                                                 &ut))
     409             :   {
     410           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     411             :                                section,
     412             :                                "USER_TYPE",
     413             :                                "valid user type required");
     414           0 :     GNUNET_free (ut_s);
     415           0 :     return GNUNET_SYSERR;
     416             :   }
     417           3 :   GNUNET_free (ut_s);
     418           3 :   if (GNUNET_OK !=
     419           3 :       GNUNET_CONFIGURATION_get_value_string (cfg,
     420             :                                              section,
     421             :                                              "LOGIC",
     422             :                                              &logic))
     423             :   {
     424           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     425             :                                section,
     426             :                                "LOGIC");
     427           0 :     return GNUNET_SYSERR;
     428             :   }
     429           3 :   lp = load_logic (cfg,
     430             :                    logic);
     431           3 :   if (NULL == lp)
     432             :   {
     433           0 :     GNUNET_free (logic);
     434           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     435             :                                section,
     436             :                                "LOGIC",
     437             :                                "logic plugin could not be loaded");
     438           0 :     return GNUNET_SYSERR;
     439             :   }
     440           3 :   GNUNET_free (logic);
     441           3 :   if (GNUNET_OK !=
     442           3 :       GNUNET_CONFIGURATION_get_value_string (cfg,
     443             :                                              section,
     444             :                                              "PROVIDED_CHECKS",
     445             :                                              &checks))
     446             :   {
     447           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     448             :                                section,
     449             :                                "PROVIDED_CHECKS");
     450           0 :     return GNUNET_SYSERR;
     451             :   }
     452             :   {
     453             :     struct TALER_KYCLOGIC_KycProvider *kp;
     454             : 
     455           3 :     kp = GNUNET_new (struct TALER_KYCLOGIC_KycProvider);
     456           3 :     kp->provider_section_name = section;
     457           3 :     kp->user_type = ut;
     458           3 :     kp->logic = lp;
     459           3 :     kp->cost = cost;
     460           3 :     add_checks (checks,
     461             :                 &kp->provided_checks,
     462             :                 &kp->num_checks);
     463           3 :     GNUNET_free (checks);
     464           3 :     kp->pd = lp->load_configuration (lp->cls,
     465             :                                      section);
     466           3 :     if (NULL == kp->pd)
     467             :     {
     468           0 :       GNUNET_free (kp);
     469           0 :       return GNUNET_SYSERR;
     470             :     }
     471           3 :     GNUNET_array_append (kyc_providers,
     472             :                          num_kyc_providers,
     473             :                          kp);
     474           6 :     for (unsigned int i = 0; i<kp->num_checks; i++)
     475             :     {
     476           3 :       struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[i];
     477             : 
     478           3 :       GNUNET_array_append (kc->providers,
     479             :                            kc->num_providers,
     480             :                            kp);
     481             :     }
     482             :   }
     483           3 :   return GNUNET_OK;
     484             : }
     485             : 
     486             : 
     487             : /**
     488             :  * Parse configuration @a cfg in section @a section for
     489             :  * the specification of a KYC trigger.
     490             :  *
     491             :  * @param cfg configuration to parse
     492             :  * @param section configuration section to parse
     493             :  * @return #GNUNET_OK on success
     494             :  */
     495             : static enum GNUNET_GenericReturnValue
     496           0 : add_trigger (const struct GNUNET_CONFIGURATION_Handle *cfg,
     497             :              const char *section)
     498             : {
     499             :   char *ot_s;
     500             :   struct TALER_Amount threshold;
     501             :   struct GNUNET_TIME_Relative timeframe;
     502             :   char *checks;
     503             :   enum TALER_KYCLOGIC_KycTriggerEvent ot;
     504             : 
     505           0 :   if (GNUNET_OK !=
     506           0 :       TALER_config_get_amount (cfg,
     507             :                                section,
     508             :                                "THRESHOLD",
     509             :                                &threshold))
     510             :   {
     511           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     512             :                                section,
     513             :                                "THRESHOLD",
     514             :                                "amount required");
     515           0 :     return GNUNET_SYSERR;
     516             :   }
     517           0 :   if (GNUNET_OK !=
     518           0 :       GNUNET_CONFIGURATION_get_value_string (cfg,
     519             :                                              section,
     520             :                                              "OPERATION_TYPE",
     521             :                                              &ot_s))
     522             :   {
     523           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     524             :                                section,
     525             :                                "OPERATION_TYPE");
     526           0 :     return GNUNET_SYSERR;
     527             :   }
     528           0 :   if (GNUNET_OK !=
     529           0 :       TALER_KYCLOGIC_kyc_trigger_from_string (ot_s,
     530             :                                               &ot))
     531             :   {
     532           0 :     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     533             :                                section,
     534             :                                "OPERATION_TYPE",
     535             :                                "valid trigger type required");
     536           0 :     GNUNET_free (ot_s);
     537           0 :     return GNUNET_SYSERR;
     538             :   }
     539           0 :   GNUNET_free (ot_s);
     540             : 
     541           0 :   if (GNUNET_OK !=
     542           0 :       GNUNET_CONFIGURATION_get_value_time (cfg,
     543             :                                            section,
     544             :                                            "TIMEFRAME",
     545             :                                            &timeframe))
     546             :   {
     547           0 :     if (TALER_KYCLOGIC_KYC_TRIGGER_WALLET_BALANCE == ot)
     548             :     {
     549           0 :       timeframe = GNUNET_TIME_UNIT_ZERO;
     550             :     }
     551             :     else
     552             :     {
     553           0 :       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
     554             :                                  section,
     555             :                                  "TIMEFRAME",
     556             :                                  "duration required");
     557           0 :       return GNUNET_SYSERR;
     558             :     }
     559             :   }
     560           0 :   if (GNUNET_OK !=
     561           0 :       GNUNET_CONFIGURATION_get_value_string (cfg,
     562             :                                              section,
     563             :                                              "REQUIRED_CHECKS",
     564             :                                              &checks))
     565             :   {
     566           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     567             :                                section,
     568             :                                "REQUIRED_CHECKS");
     569           0 :     return GNUNET_SYSERR;
     570             :   }
     571             : 
     572             :   {
     573             :     struct TALER_KYCLOGIC_KycTrigger *kt;
     574             : 
     575           0 :     kt = GNUNET_new (struct TALER_KYCLOGIC_KycTrigger);
     576           0 :     kt->timeframe = timeframe;
     577           0 :     kt->threshold = threshold;
     578           0 :     kt->trigger = ot;
     579           0 :     add_checks (checks,
     580             :                 &kt->required_checks,
     581             :                 &kt->num_checks);
     582           0 :     GNUNET_free (checks);
     583           0 :     GNUNET_array_append (kyc_triggers,
     584             :                          num_kyc_triggers,
     585             :                          kt);
     586             :   }
     587           0 :   return GNUNET_OK;
     588             : }
     589             : 
     590             : 
     591             : /**
     592             :  * Closure for #handle_section().
     593             :  */
     594             : struct SectionContext
     595             : {
     596             :   /**
     597             :    * Configuration to handle.
     598             :    */
     599             :   const struct GNUNET_CONFIGURATION_Handle *cfg;
     600             : 
     601             :   /**
     602             :    * Result to return, set to false on failures.
     603             :    */
     604             :   bool result;
     605             : };
     606             : 
     607             : 
     608             : /**
     609             :  * Function to iterate over configuration sections.
     610             :  *
     611             :  * @param cls a `struct SectionContext *`
     612             :  * @param section name of the section
     613             :  */
     614             : static void
     615          29 : handle_section (void *cls,
     616             :                 const char *section)
     617             : {
     618          29 :   struct SectionContext *sc = cls;
     619             : 
     620          29 :   if (0 == strncasecmp (section,
     621             :                         "kyc-provider-",
     622             :                         strlen ("kyc-provider-")))
     623             :   {
     624           3 :     if (GNUNET_OK !=
     625           3 :         add_provider (sc->cfg,
     626             :                       section))
     627           0 :       sc->result = false;
     628           3 :     return;
     629             :   }
     630          26 :   if (0 == strncasecmp (section,
     631             :                         "kyc-legitimization-",
     632             :                         strlen ("kyc-legitimization-")))
     633             :   {
     634           0 :     if (GNUNET_OK !=
     635           0 :         add_trigger (sc->cfg,
     636             :                      section))
     637           0 :       sc->result = false;
     638           0 :     return;
     639             :   }
     640             : }
     641             : 
     642             : 
     643             : /**
     644             :  * Comparator for qsort. Compares two triggers
     645             :  * by timeframe to sort triggers by time.
     646             :  *
     647             :  * @param p1 first trigger to compare
     648             :  * @param p2 second trigger to compare
     649             :  * @return -1 if p1 < p2, 0 if p1==p2, 1 if p1 > p2.
     650             :  */
     651             : static int
     652           0 : sort_by_timeframe (const void *p1,
     653             :                    const void *p2)
     654             : {
     655           0 :   struct TALER_KYCLOGIC_KycTrigger **t1 = (struct
     656             :                                            TALER_KYCLOGIC_KycTrigger **) p1;
     657           0 :   struct TALER_KYCLOGIC_KycTrigger **t2 = (struct
     658             :                                            TALER_KYCLOGIC_KycTrigger **) p2;
     659             : 
     660           0 :   if (GNUNET_TIME_relative_cmp ((*t1)->timeframe,
     661             :                                 <,
     662             :                                 (*t2)->timeframe))
     663           0 :     return -1;
     664           0 :   if (GNUNET_TIME_relative_cmp ((*t1)->timeframe,
     665             :                                 >,
     666             :                                 (*t2)->timeframe))
     667           0 :     return 1;
     668           0 :   return 0;
     669             : }
     670             : 
     671             : 
     672             : enum GNUNET_GenericReturnValue
     673           1 : TALER_KYCLOGIC_kyc_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
     674             : {
     675           1 :   struct SectionContext sc = {
     676             :     .cfg = cfg,
     677             :     .result = true
     678             :   };
     679             : 
     680           1 :   GNUNET_CONFIGURATION_iterate_sections (cfg,
     681             :                                          &handle_section,
     682             :                                          &sc);
     683           1 :   if (! sc.result)
     684             :   {
     685           0 :     TALER_KYCLOGIC_kyc_done ();
     686           0 :     return GNUNET_SYSERR;
     687             :   }
     688             : 
     689             :   /* sanity check: ensure at least one provider exists
     690             :      for any trigger and indidivual or business. */
     691           2 :   for (unsigned int i = 0; i<num_kyc_checks; i++)
     692           1 :     if (0 == kyc_checks[i]->num_providers)
     693             :     {
     694           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     695             :                   "No provider available for required KYC check `%s'\n",
     696             :                   kyc_checks[i]->name);
     697           0 :       TALER_KYCLOGIC_kyc_done ();
     698           0 :       return GNUNET_SYSERR;
     699             :     }
     700           1 :   qsort (kyc_triggers,
     701             :          num_kyc_triggers,
     702             :          sizeof (struct TALER_KYCLOGIC_KycTrigger *),
     703             :          &sort_by_timeframe);
     704           1 :   return GNUNET_OK;
     705             : }
     706             : 
     707             : 
     708             : void
     709           0 : TALER_KYCLOGIC_kyc_done (void)
     710             : {
     711           0 :   for (unsigned int i = 0; i<num_kyc_triggers; i++)
     712             :   {
     713           0 :     struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
     714             : 
     715           0 :     GNUNET_array_grow (kt->required_checks,
     716             :                        kt->num_checks,
     717             :                        0);
     718           0 :     GNUNET_free (kt);
     719             :   }
     720           0 :   GNUNET_array_grow (kyc_triggers,
     721             :                      num_kyc_triggers,
     722             :                      0);
     723           0 :   for (unsigned int i = 0; i<num_kyc_providers; i++)
     724             :   {
     725           0 :     struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
     726             : 
     727           0 :     kp->logic->unload_configuration (kp->pd);
     728           0 :     GNUNET_array_grow (kp->provided_checks,
     729             :                        kp->num_checks,
     730             :                        0);
     731           0 :     GNUNET_free (kp);
     732             :   }
     733           0 :   GNUNET_array_grow (kyc_providers,
     734             :                      num_kyc_providers,
     735             :                      0);
     736           0 :   for (unsigned int i = 0; i<num_kyc_logics; i++)
     737             :   {
     738           0 :     struct TALER_KYCLOGIC_Plugin *lp = kyc_logics[i];
     739           0 :     char *lib_name = lp->library_name;
     740             : 
     741           0 :     GNUNET_free (lp->name);
     742           0 :     GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name,
     743             :                                                  lp));
     744           0 :     GNUNET_free (lib_name);
     745             :   }
     746           0 :   GNUNET_array_grow (kyc_logics,
     747             :                      num_kyc_logics,
     748             :                      0);
     749           0 :   for (unsigned int i = 0; i<num_kyc_checks; i++)
     750             :   {
     751           0 :     struct TALER_KYCLOGIC_KycCheck *kc = kyc_checks[i];
     752             : 
     753           0 :     GNUNET_array_grow (kc->providers,
     754             :                        kc->num_providers,
     755             :                        0);
     756           0 :     GNUNET_free (kc->name);
     757           0 :     GNUNET_free (kc);
     758             :   }
     759           0 :   GNUNET_array_grow (kyc_checks,
     760             :                      num_kyc_checks,
     761             :                      0);
     762           0 : }
     763             : 
     764             : 
     765             : /**
     766             :  * Closure for the #eval_trigger().
     767             :  */
     768             : struct ThresholdTestContext
     769             : {
     770             :   /**
     771             :    * Total amount so far.
     772             :    */
     773             :   struct TALER_Amount total;
     774             : 
     775             :   /**
     776             :    * Trigger event to evaluate triggers of.
     777             :    */
     778             :   enum TALER_KYCLOGIC_KycTriggerEvent event;
     779             : 
     780             :   /**
     781             :    * Offset in the triggers array where we need to start
     782             :    * checking for triggers. All trigges below this
     783             :    * offset were already hit.
     784             :    */
     785             :   unsigned int start;
     786             : 
     787             :   /**
     788             :    * Array of checks needed so far.
     789             :    */
     790             :   struct TALER_KYCLOGIC_KycCheck **needed;
     791             : 
     792             :   /**
     793             :    * Pointer to number of entries used in @a needed.
     794             :    */
     795             :   unsigned int *needed_cnt;
     796             : 
     797             :   /**
     798             :    * Has @e total been initialized yet?
     799             :    */
     800             :   bool have_total;
     801             : };
     802             : 
     803             : 
     804             : /**
     805             :  * Function called on each @a amount that was found to
     806             :  * be relevant for a KYC check.
     807             :  *
     808             :  * @param cls closure to allow the KYC module to
     809             :  *        total up amounts and evaluate rules
     810             :  * @param amount encountered transaction amount
     811             :  * @param date when was the amount encountered
     812             :  * @return #GNUNET_OK to continue to iterate,
     813             :  *         #GNUNET_NO to abort iteration
     814             :  *         #GNUNET_SYSERR on internal error (also abort itaration)
     815             :  */
     816             : static enum GNUNET_GenericReturnValue
     817           0 : eval_trigger (void *cls,
     818             :               const struct TALER_Amount *amount,
     819             :               struct GNUNET_TIME_Absolute date)
     820             : {
     821           0 :   struct ThresholdTestContext *ttc = cls;
     822             :   struct GNUNET_TIME_Relative duration;
     823           0 :   bool bump = true;
     824             : 
     825           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     826             :               "KYC check with new amount %s\n",
     827             :               TALER_amount2s (amount));
     828           0 :   duration = GNUNET_TIME_absolute_get_duration (date);
     829           0 :   if (ttc->have_total)
     830             :   {
     831           0 :     if (0 >
     832           0 :         TALER_amount_add (&ttc->total,
     833           0 :                           &ttc->total,
     834             :                           amount))
     835             :     {
     836           0 :       GNUNET_break (0);
     837           0 :       return GNUNET_SYSERR;
     838             :     }
     839             :   }
     840             :   else
     841             :   {
     842           0 :     ttc->total = *amount;
     843           0 :     ttc->have_total = true;
     844             :   }
     845           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     846             :               "KYC check: new total is %s\n",
     847             :               TALER_amount2s (&ttc->total));
     848           0 :   for (unsigned int i = ttc->start; i<num_kyc_triggers; i++)
     849             :   {
     850           0 :     const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
     851             : 
     852           0 :     if (ttc->event != kt->trigger)
     853             :     {
     854           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     855             :                   "KYC check #%u: trigger type does not match\n",
     856             :                   i);
     857           0 :       continue;
     858             :     }
     859           0 :     duration = GNUNET_TIME_relative_max (duration,
     860             :                                          kt->timeframe);
     861           0 :     if (GNUNET_TIME_relative_cmp (kt->timeframe,
     862             :                                   >,
     863             :                                   duration))
     864             :     {
     865           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     866             :                   "KYC check #%u: amount is beyond time limit\n",
     867             :                   i);
     868           0 :       if (bump)
     869           0 :         ttc->start = i;
     870           0 :       return GNUNET_OK;
     871             :     }
     872           0 :     if (-1 ==
     873           0 :         TALER_amount_cmp (&ttc->total,
     874             :                           &kt->threshold))
     875             :     {
     876           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     877             :                   "KYC check #%u: amount is below threshold\n",
     878             :                   i);
     879           0 :       if (bump)
     880           0 :         ttc->start = i;
     881           0 :       bump = false;
     882           0 :       continue; /* amount too low to trigger */
     883             :     }
     884             :     /* add check to list of required checks, unless
     885             :        already present... */
     886           0 :     for (unsigned int j = 0; j<kt->num_checks; j++)
     887             :     {
     888           0 :       struct TALER_KYCLOGIC_KycCheck *rc = kt->required_checks[j];
     889           0 :       bool found = false;
     890             : 
     891           0 :       for (unsigned int k = 0; k<*ttc->needed_cnt; k++)
     892           0 :         if (ttc->needed[k] == rc)
     893             :         {
     894           0 :           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     895             :                       "KYC rule #%u already listed\n",
     896             :                       j);
     897           0 :           found = true;
     898           0 :           break;
     899             :         }
     900           0 :       if (! found)
     901             :       {
     902           0 :         ttc->needed[*ttc->needed_cnt] = rc;
     903           0 :         (*ttc->needed_cnt)++;
     904             :       }
     905             :     }
     906           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     907             :                 "KYC check #%u (%s) is applicable, %u checks needed so far\n",
     908             :                 i,
     909             :                 ttc->needed[(*ttc->needed_cnt) - 1]->name,
     910             :                 *ttc->needed_cnt);
     911             :   }
     912           0 :   if (bump)
     913           0 :     return GNUNET_NO; /* we hit all possible triggers! */
     914           0 :   return GNUNET_OK;
     915             : }
     916             : 
     917             : 
     918             : /**
     919             :  * Closure for the #remove_satisfied().
     920             :  */
     921             : struct RemoveContext
     922             : {
     923             : 
     924             :   /**
     925             :    * Array of checks needed so far.
     926             :    */
     927             :   struct TALER_KYCLOGIC_KycCheck **needed;
     928             : 
     929             :   /**
     930             :    * Pointer to number of entries used in @a needed.
     931             :    */
     932             :   unsigned int *needed_cnt;
     933             : 
     934             : };
     935             : 
     936             : 
     937             : /**
     938             :  * Remove all checks satisfied by @a provider_name from
     939             :  * our list of checks.
     940             :  *
     941             :  * @param cls a `struct RemoveContext`
     942             :  * @param provider_name section name of provider that was already run previously
     943             :  */
     944             : static void
     945           0 : remove_satisfied (void *cls,
     946             :                   const char *provider_name)
     947             : {
     948           0 :   struct RemoveContext *rc = cls;
     949             : 
     950           0 :   for (unsigned int i = 0; i<num_kyc_providers; i++)
     951             :   {
     952           0 :     const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
     953             : 
     954           0 :     if (0 != strcasecmp (provider_name,
     955             :                          kp->provider_section_name))
     956           0 :       continue;
     957           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     958             :                 "Provider `%s' satisfied\n",
     959             :                 provider_name);
     960           0 :     for (unsigned int j = 0; j<kp->num_checks; j++)
     961             :     {
     962           0 :       const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
     963             : 
     964           0 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     965             :                   "Provider satisfies check `%s'\n",
     966             :                   kc->name);
     967           0 :       for (unsigned int k = 0; k<*rc->needed_cnt; k++)
     968           0 :         if (kc == rc->needed[k])
     969             :         {
     970           0 :           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     971             :                       "Removing check `%s' from list\n",
     972             :                       kc->name);
     973           0 :           rc->needed[k] = rc->needed[*rc->needed_cnt - 1];
     974           0 :           (*rc->needed_cnt)--;
     975           0 :           if (0 == *rc->needed_cnt)
     976           0 :             return; /* for sure finished */
     977           0 :           break;
     978             :         }
     979             :     }
     980           0 :     break;
     981             :   }
     982             : }
     983             : 
     984             : 
     985             : const char *
     986           0 : TALER_KYCLOGIC_kyc_test_required (enum TALER_KYCLOGIC_KycTriggerEvent event,
     987             :                                   const struct TALER_PaytoHashP *h_payto,
     988             :                                   TALER_KYCLOGIC_KycSatisfiedIterator ki,
     989             :                                   void *ki_cls,
     990             :                                   TALER_KYCLOGIC_KycAmountIterator ai,
     991             :                                   void *ai_cls)
     992           0 : {
     993           0 :   struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
     994           0 :   unsigned int needed_cnt = 0;
     995             :   char *ret;
     996             :   struct GNUNET_TIME_Relative timeframe;
     997             : 
     998           0 :   timeframe = GNUNET_TIME_UNIT_ZERO;
     999           0 :   for (unsigned int i = 0; i<num_kyc_triggers; i++)
    1000             :   {
    1001           0 :     const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
    1002             : 
    1003           0 :     if (event != kt->trigger)
    1004           0 :       continue;
    1005           0 :     timeframe = GNUNET_TIME_relative_max (timeframe,
    1006             :                                           kt->timeframe);
    1007             :   }
    1008             :   {
    1009             :     struct GNUNET_TIME_Absolute now;
    1010           0 :     struct ThresholdTestContext ttc = {
    1011             :       .event = event,
    1012             :       .needed = needed,
    1013             :       .needed_cnt = &needed_cnt
    1014             :     };
    1015             : 
    1016           0 :     now = GNUNET_TIME_absolute_get ();
    1017           0 :     ai (ai_cls,
    1018             :         GNUNET_TIME_absolute_subtract (now,
    1019             :                                        timeframe),
    1020             :         &eval_trigger,
    1021             :         &ttc);
    1022             :   }
    1023           0 :   if (0 == needed_cnt)
    1024           0 :     return NULL;
    1025           0 :   timeframe = GNUNET_TIME_UNIT_ZERO;
    1026           0 :   for (unsigned int i = 0; i<num_kyc_triggers; i++)
    1027             :   {
    1028           0 :     const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
    1029             : 
    1030           0 :     if (event != kt->trigger)
    1031           0 :       continue;
    1032           0 :     timeframe = GNUNET_TIME_relative_max (timeframe,
    1033             :                                           kt->timeframe);
    1034             :   }
    1035             :   {
    1036             :     struct GNUNET_TIME_Absolute now;
    1037           0 :     struct ThresholdTestContext ttc = {
    1038             :       .event = event,
    1039             :       .needed = needed,
    1040             :       .needed_cnt = &needed_cnt
    1041             :     };
    1042             : 
    1043           0 :     now = GNUNET_TIME_absolute_get ();
    1044           0 :     ai (ai_cls,
    1045             :         GNUNET_TIME_absolute_subtract (now,
    1046             :                                        timeframe),
    1047             :         &eval_trigger,
    1048             :         &ttc);
    1049             :   }
    1050           0 :   if (0 == needed_cnt)
    1051           0 :     return NULL;
    1052             :   {
    1053           0 :     struct RemoveContext rc = {
    1054             :       .needed = needed,
    1055             :       .needed_cnt = &needed_cnt
    1056             :     };
    1057             :     enum GNUNET_DB_QueryStatus qs;
    1058             : 
    1059             :     /* Check what provider checks are already satisfied for h_payto (with
    1060             :        database), remove those from the 'needed' array. */
    1061           0 :     qs = ki (ki_cls,
    1062             :              h_payto,
    1063             :              &remove_satisfied,
    1064             :              &rc);
    1065           0 :     GNUNET_break (qs >= 0);  // FIXME: handle DB failure more nicely?
    1066             :   }
    1067           0 :   if (0 == needed_cnt)
    1068           0 :     return NULL;
    1069             :   {
    1070           0 :     struct RemoveContext rc = {
    1071             :       .needed = needed,
    1072             :       .needed_cnt = &needed_cnt
    1073             :     };
    1074             :     enum GNUNET_DB_QueryStatus qs;
    1075             : 
    1076             :     /* Check what provider checks are already satisfied for h_payto (with
    1077             :        database), remove those from the 'needed' array. */
    1078           0 :     qs = ki (ki_cls,
    1079             :              h_payto,
    1080             :              &remove_satisfied,
    1081             :              &rc);
    1082           0 :     GNUNET_break (qs >= 0);  // FIXME: handle DB failure more nicely?
    1083             :   }
    1084           0 :   if (0 == needed_cnt)
    1085           0 :     return NULL;
    1086           0 :   ret = NULL;
    1087           0 :   for (unsigned int k = 0; k<needed_cnt; k++)
    1088             :   {
    1089           0 :     const struct TALER_KYCLOGIC_KycCheck *kc = needed[k];
    1090             : 
    1091           0 :     if (NULL == ret)
    1092             :     {
    1093           0 :       ret = GNUNET_strdup (kc->name);
    1094             :     }
    1095             :     else /* append */
    1096             :     {
    1097           0 :       char *tmp = ret;
    1098             : 
    1099           0 :       GNUNET_asprintf (&ret,
    1100             :                        "%s %s",
    1101             :                        tmp,
    1102             :                        kc->name);
    1103           0 :       GNUNET_free (tmp);
    1104             :     }
    1105             :   }
    1106           0 :   return ret;
    1107             : }
    1108             : 
    1109             : 
    1110             : void
    1111           0 : TALER_KYCLOGIC_kyc_get_details (
    1112             :   const char *logic_name,
    1113             :   TALER_KYCLOGIC_DetailsCallback cb,
    1114             :   void *cb_cls)
    1115             : {
    1116           0 :   for (unsigned int i = 0; i<num_kyc_providers; i++)
    1117             :   {
    1118           0 :     struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
    1119             : 
    1120           0 :     if (0 !=
    1121           0 :         strcmp (kp->logic->name,
    1122             :                 logic_name))
    1123           0 :       continue;
    1124           0 :     if (GNUNET_OK !=
    1125           0 :         cb (cb_cls,
    1126           0 :             kp->pd,
    1127           0 :             kp->logic->cls))
    1128           0 :       return;
    1129             :   }
    1130             : }
    1131             : 
    1132             : 
    1133             : bool
    1134           0 : TALER_KYCLOGIC_check_satisfied (const char *requirements,
    1135             :                                 const struct TALER_PaytoHashP *h_payto,
    1136             :                                 TALER_KYCLOGIC_KycSatisfiedIterator ki,
    1137             :                                 void *ki_cls)
    1138           0 : {
    1139           0 :   struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
    1140           0 :   unsigned int needed_cnt = 0;
    1141             : 
    1142           0 :   if (NULL == requirements)
    1143           0 :     return true;
    1144             :   {
    1145           0 :     char *req = GNUNET_strdup (requirements);
    1146             : 
    1147           0 :     for (const char *tok = strtok (req, " ");
    1148             :          NULL != tok;
    1149           0 :          tok = strtok (NULL, " "))
    1150           0 :       needed[needed_cnt++] = add_check (tok);
    1151           0 :     GNUNET_free (req);
    1152             :   }
    1153             : 
    1154             :   {
    1155           0 :     struct RemoveContext rc = {
    1156             :       .needed = needed,
    1157             :       .needed_cnt = &needed_cnt
    1158             :     };
    1159             :     enum GNUNET_DB_QueryStatus qs;
    1160             : 
    1161             :     /* Check what provider checks are already satisfied for h_payto (with
    1162             :        database), remove those from the 'needed' array. */
    1163           0 :     qs = ki (ki_cls,
    1164             :              h_payto,
    1165             :              &remove_satisfied,
    1166             :              &rc);
    1167           0 :     GNUNET_break (qs >= 0);  // FIXME: handle DB failure more nicely?
    1168             :   }
    1169           0 :   return (0 == needed_cnt);
    1170             : }
    1171             : 
    1172             : 
    1173             : enum GNUNET_GenericReturnValue
    1174           0 : TALER_KYCLOGIC_requirements_to_logic (const char *requirements,
    1175             :                                       enum TALER_KYCLOGIC_KycUserType ut,
    1176             :                                       struct TALER_KYCLOGIC_Plugin **plugin,
    1177             :                                       struct TALER_KYCLOGIC_ProviderDetails **pd,
    1178             :                                       const char **configuration_section)
    1179           0 : {
    1180           0 :   struct TALER_KYCLOGIC_KycCheck *needed[num_kyc_checks];
    1181           0 :   unsigned int needed_cnt = 0;
    1182           0 :   unsigned long long min_cost = ULLONG_MAX;
    1183           0 :   unsigned int max_checks = 0;
    1184           0 :   const struct TALER_KYCLOGIC_KycProvider *kp_best = NULL;
    1185             : 
    1186             :   // FIXME: use 'ut' to filter providers!
    1187           0 :   if (NULL == requirements)
    1188           0 :     return GNUNET_NO;
    1189             :   {
    1190           0 :     char *req = GNUNET_strdup (requirements);
    1191             : 
    1192           0 :     for (const char *tok = strtok (req, " ");
    1193             :          NULL != tok;
    1194           0 :          tok = strtok (NULL, " "))
    1195           0 :       needed[needed_cnt++] = add_check (tok);
    1196           0 :     GNUNET_free (req);
    1197             :   }
    1198             : 
    1199             :   /* Count maximum number of remaining checks covered by any
    1200             :      provider */
    1201           0 :   for (unsigned int i = 0; i<num_kyc_providers; i++)
    1202             :   {
    1203           0 :     const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
    1204           0 :     unsigned int matched = 0;
    1205             : 
    1206           0 :     for (unsigned int j = 0; j<kp->num_checks; j++)
    1207             :     {
    1208           0 :       const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
    1209             : 
    1210           0 :       for (unsigned int k = 0; k<needed_cnt; k++)
    1211           0 :         if (kc == needed[k])
    1212             :         {
    1213           0 :           matched++;
    1214           0 :           break;
    1215             :         }
    1216             :     }
    1217           0 :     max_checks = GNUNET_MAX (max_checks,
    1218             :                              matched);
    1219             :   }
    1220           0 :   if (0 == max_checks)
    1221           0 :     return GNUNET_SYSERR;
    1222             : 
    1223             :   /* Find min-cost provider covering max_checks. */
    1224           0 :   for (unsigned int i = 0; i<num_kyc_providers; i++)
    1225             :   {
    1226           0 :     const struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
    1227           0 :     unsigned int matched = 0;
    1228             : 
    1229           0 :     for (unsigned int j = 0; j<kp->num_checks; j++)
    1230             :     {
    1231           0 :       const struct TALER_KYCLOGIC_KycCheck *kc = kp->provided_checks[j];
    1232             : 
    1233           0 :       for (unsigned int k = 0; k<needed_cnt; k++)
    1234           0 :         if (kc == needed[k])
    1235             :         {
    1236           0 :           matched++;
    1237           0 :           break;
    1238             :         }
    1239             :     }
    1240           0 :     if ( (max_checks == matched) &&
    1241           0 :          (kp->cost < min_cost) )
    1242             :     {
    1243           0 :       min_cost = kp->cost;
    1244           0 :       kp_best = kp;
    1245             :     }
    1246             :   }
    1247           0 :   *plugin = kp_best->logic;
    1248           0 :   *pd = kp_best->pd;
    1249           0 :   *configuration_section = kp_best->provider_section_name;
    1250           0 :   return GNUNET_OK;
    1251             : }
    1252             : 
    1253             : 
    1254             : enum GNUNET_GenericReturnValue
    1255           0 : TALER_KYCLOGIC_lookup_logic (const char *name,
    1256             :                              struct TALER_KYCLOGIC_Plugin **plugin,
    1257             :                              struct TALER_KYCLOGIC_ProviderDetails **pd,
    1258             :                              const char **provider_section)
    1259             : {
    1260           0 :   for (unsigned int i = 0; i<num_kyc_providers; i++)
    1261             :   {
    1262           0 :     struct TALER_KYCLOGIC_KycProvider *kp = kyc_providers[i];
    1263             : 
    1264           0 :     if (0 !=
    1265           0 :         strcasecmp (name,
    1266             :                     kp->provider_section_name))
    1267           0 :       continue;
    1268           0 :     *plugin = kp->logic;
    1269           0 :     *pd = kp->pd;
    1270           0 :     *provider_section = kp->provider_section_name;
    1271           0 :     return GNUNET_OK;
    1272             :   }
    1273           0 :   for (unsigned int i = 0; i<num_kyc_logics; i++)
    1274             :   {
    1275           0 :     struct TALER_KYCLOGIC_Plugin *logic = kyc_logics[i];
    1276             : 
    1277           0 :     if (0 !=
    1278           0 :         strcasecmp (logic->name,
    1279             :                     name))
    1280           0 :       continue;
    1281           0 :     *plugin = logic;
    1282           0 :     *pd = NULL;
    1283           0 :     *provider_section = NULL;
    1284           0 :     return GNUNET_OK;
    1285             :   }
    1286           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1287             :               "Provider `%s' unknown\n",
    1288             :               name);
    1289           0 :   return GNUNET_SYSERR;
    1290             : }
    1291             : 
    1292             : 
    1293             : void
    1294           0 : TALER_KYCLOGIC_kyc_iterate_thresholds (
    1295             :   enum TALER_KYCLOGIC_KycTriggerEvent event,
    1296             :   TALER_KYCLOGIC_KycThresholdIterator it,
    1297             :   void *it_cls)
    1298             : {
    1299           0 :   for (unsigned int i = 0; i<num_kyc_triggers; i++)
    1300             :   {
    1301           0 :     const struct TALER_KYCLOGIC_KycTrigger *kt = kyc_triggers[i];
    1302             : 
    1303           0 :     if (event != kt->trigger)
    1304           0 :       continue;
    1305           0 :     it (it_cls,
    1306             :         &kt->threshold);
    1307             :   }
    1308           0 : }
    1309             : 
    1310             : 
    1311             : /* end of taler-exchange-httpd_kyc.c */

Generated by: LCOV version 1.14