src/pEpEngine.c
author Volker Birk <vb@pep-project.org>
Wed, 27 Jul 2016 12:55:01 +0200
changeset 930 c201a657e628
parent 929 b094dd6bb553
child 932 d35b292fe141
permissions -rw-r--r--
duplicating flags with identity
     1 #include "pEp_internal.h"
     2 #include "dynamic_api.h"
     3 #include "cryptotech.h"
     4 #include "transport.h"
     5 #include "blacklist.h"
     6 
     7 static int init_count = -1;
     8 
     9 static int user_version(void *_version, int count, char **text, char **name)
    10 {
    11     assert(_version);
    12     assert(count == 1);
    13     assert(text && text[0]);
    14     if (!(_version && count == 1 && text && text[0]))
    15         return -1;
    16 
    17     int *version = (int *) _version;
    18     *version = atoi(text[0]);
    19     return 0;
    20 }
    21 
    22 DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
    23 {
    24     PEP_STATUS status = PEP_STATUS_OK;
    25     int int_result;
    26     static const char *sql_log;
    27     static const char *sql_trustword;
    28     static const char *sql_get_identity;
    29     static const char *sql_set_person;
    30     static const char *sql_set_pgp_keypair;
    31     static const char *sql_set_identity;
    32     static const char *sql_set_trust;
    33     static const char *sql_get_trust;
    34     static const char *sql_least_trust;
    35     static const char *sql_mark_as_compromized;
    36     static const char *sql_crashdump;
    37     static const char *sql_languagelist;
    38     static const char *sql_i18n_token;
    39 
    40     // blacklist
    41     static const char *sql_blacklist_add;
    42     static const char *sql_blacklist_delete;
    43     static const char *sql_blacklist_is_listed;
    44     static const char *sql_blacklist_retrieve;
    45 
    46     // Own keys
    47     static const char *sql_own_key_is_listed;
    48     static const char *sql_own_key_retrieve;
    49 
    50     // Sequence
    51     static const char *sql_sequence_value1;
    52     static const char *sql_sequence_value2;
    53 
    54     // Revocation tracking
    55     static const char *sql_set_revoked;
    56     static const char *sql_get_revoked;
    57     
    58     bool in_first = false;
    59 
    60     assert(sqlite3_threadsafe());
    61     if (!sqlite3_threadsafe())
    62         return PEP_INIT_SQLITE3_WITHOUT_MUTEX;
    63 
    64     // a little race condition - but still a race condition
    65     // mitigated by calling caveat (see documentation)
    66 
    67     ++init_count;
    68     if (init_count == 0)
    69         in_first = true;
    70 
    71     assert(session);
    72     if (session == NULL)
    73         return PEP_ILLEGAL_VALUE;
    74 
    75     *session = NULL;
    76 
    77     pEpSession *_session = calloc(1, sizeof(pEpSession));
    78     assert(_session);
    79     if (_session == NULL)
    80         goto enomem;
    81 
    82     _session->version = PEP_ENGINE_VERSION;
    83 
    84     assert(LOCAL_DB);
    85     if (LOCAL_DB == NULL) {
    86         status = PEP_INIT_CANNOT_OPEN_DB;
    87         goto pep_error;
    88     }
    89 
    90     int_result = sqlite3_open_v2(
    91             LOCAL_DB,
    92             &_session->db,
    93             SQLITE_OPEN_READWRITE
    94                 | SQLITE_OPEN_CREATE
    95                 | SQLITE_OPEN_FULLMUTEX
    96                 | SQLITE_OPEN_PRIVATECACHE,
    97             NULL 
    98         );
    99 
   100     if (int_result != SQLITE_OK) {
   101         status = PEP_INIT_CANNOT_OPEN_DB;
   102         goto pep_error;
   103     }
   104 
   105     sqlite3_busy_timeout(_session->db, BUSY_WAIT_TIME);
   106 
   107     assert(SYSTEM_DB);
   108     if (SYSTEM_DB == NULL) {
   109         status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
   110         goto pep_error;
   111     }
   112 
   113     int_result = sqlite3_open_v2(
   114             SYSTEM_DB, &_session->system_db,
   115             SQLITE_OPEN_READONLY
   116                 | SQLITE_OPEN_FULLMUTEX
   117                 | SQLITE_OPEN_SHAREDCACHE,
   118             NULL
   119         );
   120 
   121     if (int_result != SQLITE_OK) {
   122         status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
   123         goto pep_error;
   124     }
   125 
   126     sqlite3_busy_timeout(_session->system_db, 1000);
   127 
   128 // increment this when patching DDL
   129 #define _DDL_USER_VERSION "1"
   130 
   131     if (in_first) {
   132         int_result = sqlite3_exec(
   133             _session->db,
   134                 "create table version_info (\n"
   135                 "   id integer primary key,\n"
   136                 "   timestamp integer default (datetime('now')) ,\n"
   137                 "   version text,\n"
   138                 "   comment text\n"
   139                 ");\n",
   140                 NULL,
   141                 NULL,
   142                 NULL
   143         );
   144         if (int_result == SQLITE_OK) {
   145             int_result = sqlite3_exec(
   146                 _session->db,
   147                 "pragma user_version = "_DDL_USER_VERSION";\n"
   148                 "insert or replace into version_info (id, version)"
   149                     "values (1, '" PEP_ENGINE_VERSION "');",
   150                 NULL,
   151                 NULL,
   152                 NULL
   153             );
   154             assert(int_result == SQLITE_OK);
   155         }
   156 
   157         int_result = sqlite3_exec(
   158             _session->db,
   159                 "create table if not exists log (\n"
   160                 "   timestamp integer default (datetime('now')) ,\n"
   161                 "   title text not null,\n"
   162                 "   entity text not null,\n"
   163                 "   description text,\n"
   164                 "   comment text\n"
   165                 ");\n"
   166                 "create index if not exists log_timestamp on log (\n"
   167                 "   timestamp\n"
   168                 ");\n"
   169                 "create table if not exists pgp_keypair (\n"
   170                 "   fpr text primary key,\n"
   171                 "   public_id text unique,\n"
   172                 "   private_id text,\n"
   173                 "   created integer,\n"
   174                 "   expires integer,\n"
   175                 "   comment text\n"
   176                 ");\n"
   177                 "create index if not exists pgp_keypair_expires on pgp_keypair (\n"
   178                 "   expires\n"
   179                 ");\n"
   180                 "create table if not exists person (\n"
   181                 "   id text primary key,\n"
   182                 "   username text not null,\n"
   183                 "   main_key_id text\n"
   184                 "       references pgp_keypair (fpr)\n"
   185                 "       on delete set null,\n"
   186                 "   lang text,\n"
   187                 "   comment text\n"
   188                 ");\n"
   189                 "create table if not exists identity (\n"
   190                 "   address text,\n"
   191                 "   user_id text\n"
   192                 "       references person (id)\n"
   193                 "       on delete cascade,\n"
   194                 "   main_key_id text\n"
   195                 "       references pgp_keypair (fpr)\n"
   196                 "       on delete set null,\n"
   197                 "   comment text,\n"
   198                 "   flags integer default (0),"
   199                 "   primary key (address, user_id)\n"
   200                 ");\n"
   201                 "create table if not exists trust (\n"
   202                 "   user_id text not null\n"
   203                 "       references person (id)\n"
   204                 "       on delete cascade,\n"
   205                 "   pgp_keypair_fpr text not null\n"
   206                 "       references pgp_keypair (fpr)\n"
   207                 "       on delete cascade,\n"
   208                 "   comm_type integer not null,\n"
   209                 "   comment text,\n"
   210                 "   primary key (user_id, pgp_keypair_fpr)\n"
   211                 ");\n"
   212                 // blacklist
   213                 "create table if not exists blacklist_keys (\n"
   214                 "   fpr text primary key\n"
   215                 ");\n"
   216                 // sequences
   217                 "create table if not exists sequences(\n"
   218                 "   name text primary key,\n"
   219                 "   value integer default 0\n"
   220                 ");\n"
   221                 "create table if not exists revoked_keys (\n"
   222                 "   revoked_fpr text primary key,\n"
   223                 "   replacement_fpr text not null\n"
   224                 "       references pgp_keypair (fpr)\n"
   225                 "       on delete cascade,\n"
   226                 "   revocation_date integer\n"
   227                 ");\n"
   228                 ,
   229             NULL,
   230             NULL,
   231             NULL
   232         );
   233         assert(int_result == SQLITE_OK);
   234 
   235         int version;
   236         int_result = sqlite3_exec(
   237             _session->db,
   238             "pragma user_version;",
   239             user_version,
   240             &version,
   241             NULL
   242         );
   243         assert(int_result == SQLITE_OK);
   244 
   245         if (version < 1) {
   246             int_result = sqlite3_exec(
   247                 _session->db,
   248                 "alter table identity\n"
   249                 "   add column flags integer default (0);",
   250                 NULL,
   251                 NULL,
   252                 NULL
   253             );
   254             assert(int_result == SQLITE_OK);
   255         }
   256 
   257         if (version < atoi(_DDL_USER_VERSION)) {
   258             int_result = sqlite3_exec(
   259                 _session->db,
   260                 "pragma user_version = "_DDL_USER_VERSION";\n"
   261                 "insert or replace into version_info (id, version)"
   262                     "values (1, '" PEP_ENGINE_VERSION "');",
   263                 NULL,
   264                 NULL,
   265                 NULL
   266             );
   267             assert(int_result == SQLITE_OK);
   268         }
   269 
   270         sql_log = "insert into log (title, entity, description, comment)"
   271                   "values (?1, ?2, ?3, ?4);";
   272 
   273         sql_get_identity =  "select fpr, username, comm_type, lang, flags"
   274                             "   from identity"
   275                             "   join person on id = identity.user_id"
   276                             "   join pgp_keypair on fpr = identity.main_key_id"
   277                             "   join trust on id = trust.user_id"
   278                             "       and pgp_keypair_fpr = identity.main_key_id"
   279                             "   where address = ?1 and identity.user_id = ?2;";
   280 
   281         sql_trustword = "select id, word from wordlist where lang = lower(?1) "
   282                        "and id = ?2 ;";
   283 
   284         // Set person, but if already exist, only update.
   285         // if main_key_id already set, don't touch.
   286         sql_set_person = "insert or replace into person (id, username, lang, main_key_id)"
   287                          "  values (?1, ?2, ?3,"
   288                          "    (select coalesce((select main_key_id from person "
   289                          "      where id = ?1), upper(replace(?4,' ',''))))) ;";
   290 
   291         sql_set_pgp_keypair = "insert or replace into pgp_keypair (fpr) "
   292                               "values (upper(replace(?1,' ',''))) ;";
   293 
   294         sql_set_identity = "insert or replace into identity (address, main_key_id, "
   295                            "user_id, flags) values (?1, upper(replace(?2,' ','')),"
   296                            "?3, ?4) ;";
   297 
   298         sql_set_trust = "insert or replace into trust (user_id, pgp_keypair_fpr, comm_type) "
   299                         "values (?1, upper(replace(?2,' ','')), ?3) ;";
   300 
   301         sql_get_trust = "select comm_type from trust where user_id = ?1 "
   302                         "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;";
   303 
   304         sql_least_trust = "select min(comm_type) from trust where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   305 
   306         sql_mark_as_compromized = "update trust not indexed set comm_type = 15"
   307                                   " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;";
   308 
   309         sql_crashdump = "select timestamp, title, entity, description, comment"
   310                         " from log order by timestamp desc limit ?1 ;";
   311 
   312         sql_languagelist = "select i18n_language.lang, name, phrase from i18n_language join i18n_token using (lang) where i18n_token.id = 1000;" ;
   313 
   314         sql_i18n_token = "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;";
   315 
   316         // blacklist
   317 
   318         sql_blacklist_add = "insert or replace into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;"
   319                             "delete from identity where main_key_id = upper(replace(?1,' ','')) ;"
   320                             "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;";
   321 
   322         sql_blacklist_delete = "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   323 
   324         sql_blacklist_is_listed = "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;";
   325 
   326         sql_blacklist_retrieve = "select * from blacklist_keys ;";
   327         
   328         // Own keys
   329         
   330         sql_own_key_is_listed =
   331                                 "select count(*) from ("
   332                                 " select main_key_id from person "
   333                                 "   where main_key_id = upper(replace(?1,' ',''))"
   334                                 "    and id = '" PEP_OWN_USERID "' "
   335                                 " union "
   336                                 "  select main_key_id from identity "
   337                                 "   where main_key_id = upper(replace(?1,' ',''))"
   338                                 "    and user_id = '" PEP_OWN_USERID "' );";
   339 
   340         sql_own_key_retrieve = "select main_key_id from person "
   341                                "  where main_key_id is not null"
   342                                "   and id = '" PEP_OWN_USERID "' "
   343                                "union "
   344                                " select main_key_id from identity "
   345                                "  where main_key_id is not null"
   346                                "   and user_id = '" PEP_OWN_USERID "' ;";
   347         
   348         sql_sequence_value1 = "insert or replace into sequences (name, value) "
   349                               "values (?1, "
   350                               "(select coalesce((select value + 1 from sequences "
   351                               "where name = ?1), 1 ))) ; ";
   352         sql_sequence_value2 = "select value from sequences where name = ?1 ;";
   353         
   354         sql_set_revoked =     "insert or replace into revoked_keys ("
   355                               "    revoked_fpr, replacement_fpr, revocation_date) "
   356                               "values (upper(replace(?1,' ','')),"
   357                               "        upper(replace(?2,' ','')),"
   358                               "        ?3) ;";
   359         
   360         sql_get_revoked =     "select revoked_fpr, revocation_date from revoked_keys"
   361                               "    where replacement_fpr = upper(replace(?1,' ','')) ;";
   362     }
   363 
   364     int_result = sqlite3_prepare_v2(_session->db, sql_log, (int)strlen(sql_log),
   365             &_session->log, NULL);
   366     assert(int_result == SQLITE_OK);
   367 
   368     int_result = sqlite3_prepare_v2(_session->system_db, sql_trustword,
   369             (int)strlen(sql_trustword), &_session->trustword, NULL);
   370     assert(int_result == SQLITE_OK);
   371 
   372     int_result = sqlite3_prepare_v2(_session->db, sql_get_identity,
   373             (int)strlen(sql_get_identity), &_session->get_identity, NULL);
   374     assert(int_result == SQLITE_OK);
   375 
   376     int_result = sqlite3_prepare_v2(_session->db, sql_set_person,
   377             (int)strlen(sql_set_person), &_session->set_person, NULL);
   378     assert(int_result == SQLITE_OK);
   379 
   380     int_result = sqlite3_prepare_v2(_session->db, sql_set_pgp_keypair,
   381             (int)strlen(sql_set_pgp_keypair), &_session->set_pgp_keypair, NULL);
   382     assert(int_result == SQLITE_OK);
   383 
   384     int_result = sqlite3_prepare_v2(_session->db, sql_set_identity,
   385             (int)strlen(sql_set_identity), &_session->set_identity, NULL);
   386     assert(int_result == SQLITE_OK);
   387 
   388     int_result = sqlite3_prepare_v2(_session->db, sql_set_trust,
   389             (int)strlen(sql_set_trust), &_session->set_trust, NULL);
   390     assert(int_result == SQLITE_OK);
   391 
   392     int_result = sqlite3_prepare_v2(_session->db, sql_get_trust,
   393             (int)strlen(sql_get_trust), &_session->get_trust, NULL);
   394     assert(int_result == SQLITE_OK);
   395 
   396     int_result = sqlite3_prepare_v2(_session->db, sql_least_trust,
   397             (int)strlen(sql_least_trust), &_session->least_trust, NULL);
   398     assert(int_result == SQLITE_OK);
   399 
   400     int_result = sqlite3_prepare_v2(_session->db, sql_mark_as_compromized,
   401             (int)strlen(sql_mark_as_compromized), &_session->mark_compromized, NULL);
   402     assert(int_result == SQLITE_OK);
   403 
   404     int_result = sqlite3_prepare_v2(_session->db, sql_crashdump,
   405             (int)strlen(sql_crashdump), &_session->crashdump, NULL);
   406     assert(int_result == SQLITE_OK);
   407 
   408     int_result = sqlite3_prepare_v2(_session->system_db, sql_languagelist,
   409             (int)strlen(sql_languagelist), &_session->languagelist, NULL);
   410     assert(int_result == SQLITE_OK);
   411 
   412     int_result = sqlite3_prepare_v2(_session->system_db, sql_i18n_token,
   413             (int)strlen(sql_i18n_token), &_session->i18n_token, NULL);
   414     assert(int_result == SQLITE_OK);
   415 
   416     // blacklist
   417 
   418     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_add,
   419             (int)strlen(sql_blacklist_add), &_session->blacklist_add, NULL);
   420     assert(int_result == SQLITE_OK);
   421 
   422     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_delete,
   423             (int)strlen(sql_blacklist_delete), &_session->blacklist_delete, NULL);
   424     assert(int_result == SQLITE_OK);
   425 
   426     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_is_listed,
   427             (int)strlen(sql_blacklist_is_listed), &_session->blacklist_is_listed, NULL);
   428     assert(int_result == SQLITE_OK);
   429 
   430     int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_retrieve,
   431             (int)strlen(sql_blacklist_retrieve), &_session->blacklist_retrieve, NULL);
   432     assert(int_result == SQLITE_OK);
   433 
   434     // Own keys
   435     
   436     int_result = sqlite3_prepare_v2(_session->db, sql_own_key_is_listed,
   437             (int)strlen(sql_own_key_is_listed), &_session->own_key_is_listed, NULL);
   438     assert(int_result == SQLITE_OK);
   439     
   440     int_result = sqlite3_prepare_v2(_session->db, sql_own_key_retrieve,
   441             (int)strlen(sql_own_key_retrieve), &_session->own_key_retrieve, NULL);
   442     assert(int_result == SQLITE_OK);
   443  
   444     // Sequence
   445 
   446     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value1,
   447             (int)strlen(sql_sequence_value1), &_session->sequence_value1, NULL);
   448     assert(int_result == SQLITE_OK);
   449 
   450     int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value2,
   451             (int)strlen(sql_sequence_value2), &_session->sequence_value2, NULL);
   452     assert(int_result == SQLITE_OK);
   453 
   454     // Revocation tracking
   455     
   456     int_result = sqlite3_prepare_v2(_session->db, sql_set_revoked,
   457                                     (int)strlen(sql_set_revoked), &_session->set_revoked, NULL);
   458     assert(int_result == SQLITE_OK);
   459     
   460     int_result = sqlite3_prepare_v2(_session->db, sql_get_revoked,
   461                                     (int)strlen(sql_get_revoked), &_session->get_revoked, NULL);
   462     assert(int_result == SQLITE_OK);
   463     
   464     status = init_cryptotech(_session, in_first);
   465     if (status != PEP_STATUS_OK)
   466         goto pep_error;
   467 
   468     status = init_transport_system(_session, in_first);
   469     if (status != PEP_STATUS_OK)
   470         goto pep_error;
   471 
   472     status = log_event(_session, "init", "pEp " PEP_ENGINE_VERSION, NULL, NULL);
   473     if (status != PEP_STATUS_OK)
   474         goto pep_error;
   475 
   476     // runtime config
   477 
   478     _session->passive_mode = false;
   479     _session->unencrypted_subject = false;
   480 #ifdef ANDROID
   481     _session->use_only_own_private_keys = true;
   482 #elif TARGET_OS_IPHONE
   483     _session->use_only_own_private_keys = true;
   484 #else
   485     _session->use_only_own_private_keys = false;
   486 #endif
   487 
   488     *session = _session;
   489     return PEP_STATUS_OK;
   490 
   491 enomem:
   492     status = PEP_OUT_OF_MEMORY;
   493 
   494 pep_error:
   495     release(_session);
   496     return status;
   497 }
   498 
   499 DYNAMIC_API void release(PEP_SESSION session)
   500 {
   501     bool out_last = false;
   502 
   503     assert(init_count >= 0);
   504     assert(session);
   505 
   506     if (!((init_count >= 0) && session))
   507         return;
   508 
   509     // a small race condition but still a race condition
   510     // mitigated by calling caveat (see documentation)
   511 
   512     if (init_count == 0)
   513         out_last = true;
   514     --init_count;
   515 
   516     if (session) {
   517         if (session->db) {
   518             if (session->log)
   519                 sqlite3_finalize(session->log);
   520             if (session->trustword)
   521                 sqlite3_finalize(session->trustword);
   522             if (session->get_identity)
   523                 sqlite3_finalize(session->get_identity);
   524             if (session->set_person)
   525                 sqlite3_finalize(session->set_person);
   526             if (session->set_pgp_keypair)
   527                 sqlite3_finalize(session->set_pgp_keypair);
   528             if (session->set_identity)
   529                 sqlite3_finalize(session->set_identity);
   530             if (session->set_trust)
   531                 sqlite3_finalize(session->set_trust);
   532             if (session->get_trust)
   533                 sqlite3_finalize(session->get_trust);
   534             if (session->least_trust)
   535                 sqlite3_finalize(session->least_trust);
   536             if (session->mark_compromized)
   537                 sqlite3_finalize(session->mark_compromized);
   538             if (session->crashdump)
   539                 sqlite3_finalize(session->crashdump);
   540             if (session->languagelist)
   541                 sqlite3_finalize(session->languagelist);
   542             if (session->i18n_token)
   543                 sqlite3_finalize(session->i18n_token);
   544             if (session->blacklist_add)
   545                 sqlite3_finalize(session->blacklist_add);
   546             if (session->blacklist_delete)
   547                 sqlite3_finalize(session->blacklist_delete);
   548             if (session->blacklist_is_listed)
   549                 sqlite3_finalize(session->blacklist_is_listed);
   550             if (session->blacklist_retrieve)
   551                 sqlite3_finalize(session->blacklist_retrieve);
   552 
   553             if (session->db)
   554                 sqlite3_close_v2(session->db);
   555             if (session->system_db)
   556                 sqlite3_close_v2(session->system_db);
   557         }
   558 
   559         release_transport_system(session, out_last);
   560         release_cryptotech(session, out_last);
   561 
   562         free(session);
   563     }
   564 }
   565 
   566 DYNAMIC_API void config_passive_mode(PEP_SESSION session, bool enable)
   567 {
   568     assert(session);
   569     session->passive_mode = enable;
   570 }
   571 
   572 DYNAMIC_API void config_unencrypted_subject(PEP_SESSION session, bool enable)
   573 {
   574     assert(session);
   575     session->unencrypted_subject = enable;
   576 }
   577 
   578 DYNAMIC_API void config_use_only_own_private_keys(PEP_SESSION session, bool enable)
   579 {
   580     assert(session);
   581     session->use_only_own_private_keys = enable;
   582 }
   583 
   584 DYNAMIC_API PEP_STATUS log_event(
   585         PEP_SESSION session,
   586         const char *title,
   587         const char *entity,
   588         const char *description,
   589         const char *comment
   590     )
   591 {
   592     PEP_STATUS status = PEP_STATUS_OK;
   593     int result;
   594 
   595     assert(session);
   596     assert(title);
   597     assert(entity);
   598 
   599     if (!(session && title && entity))
   600         return PEP_ILLEGAL_VALUE;
   601 
   602     sqlite3_reset(session->log);
   603     sqlite3_bind_text(session->log, 1, title, -1, SQLITE_STATIC);
   604     sqlite3_bind_text(session->log, 2, entity, -1, SQLITE_STATIC);
   605     if (description)
   606         sqlite3_bind_text(session->log, 3, description, -1, SQLITE_STATIC);
   607     else
   608         sqlite3_bind_null(session->log, 3);
   609     if (comment)
   610         sqlite3_bind_text(session->log, 4, comment, -1, SQLITE_STATIC);
   611     else
   612         sqlite3_bind_null(session->log, 4);
   613     do {
   614         result = sqlite3_step(session->log);
   615         assert(result == SQLITE_DONE || result == SQLITE_BUSY);
   616         if (result != SQLITE_DONE && result != SQLITE_BUSY)
   617             status = PEP_UNKNOWN_ERROR;
   618     } while (result == SQLITE_BUSY);
   619     sqlite3_reset(session->log);
   620 
   621     return status;
   622 }
   623 
   624 DYNAMIC_API PEP_STATUS trustword(
   625             PEP_SESSION session, uint16_t value, const char *lang,
   626             char **word, size_t *wsize
   627         )
   628 {
   629     PEP_STATUS status = PEP_STATUS_OK;
   630 
   631     assert(session);
   632     assert(word);
   633     assert(wsize);
   634 
   635     if (!(session && word && wsize))
   636         return PEP_ILLEGAL_VALUE;
   637 
   638     *word = NULL;
   639     *wsize = 0;
   640 
   641     if (lang == NULL)
   642         lang = "en";
   643 
   644     assert((lang[0] >= 'A' && lang[0] <= 'Z')
   645             || (lang[0] >= 'a' && lang[0] <= 'z'));
   646     assert((lang[1] >= 'A' && lang[1] <= 'Z')
   647             || (lang[1] >= 'a' && lang[1] <= 'z'));
   648     assert(lang[2] == 0);
   649 
   650     sqlite3_reset(session->trustword);
   651     sqlite3_bind_text(session->trustword, 1, lang, -1, SQLITE_STATIC);
   652     sqlite3_bind_int(session->trustword, 2, value);
   653 
   654     const int result = sqlite3_step(session->trustword);
   655     if (result == SQLITE_ROW) {
   656         *word = strdup((const char *) sqlite3_column_text(session->trustword,
   657                     1));
   658         if (*word)
   659             *wsize = sqlite3_column_bytes(session->trustword, 1);
   660         else
   661             status = PEP_OUT_OF_MEMORY;
   662     } else
   663         status = PEP_TRUSTWORD_NOT_FOUND;
   664 
   665     sqlite3_reset(session->trustword);
   666     return status;
   667 }
   668 
   669 DYNAMIC_API PEP_STATUS trustwords(
   670         PEP_SESSION session, const char *fingerprint, const char *lang,
   671         char **words, size_t *wsize, int max_words
   672     )
   673 {
   674     const char *source = fingerprint;
   675     char *buffer;
   676     char *dest;
   677     size_t fsize;
   678     PEP_STATUS _status;
   679 
   680     assert(session);
   681     assert(fingerprint);
   682     assert(words);
   683     assert(wsize);
   684     assert(max_words >= 0);
   685 
   686     if (!(session && fingerprint && words && wsize && max_words >= 0))
   687         return PEP_ILLEGAL_VALUE;
   688 
   689     *words = NULL;
   690     *wsize = 0;
   691 
   692     buffer = calloc(1, MAX_TRUSTWORDS_SPACE);
   693     assert(buffer);
   694     if (buffer == NULL)
   695         return PEP_OUT_OF_MEMORY;
   696     dest = buffer;
   697 
   698     fsize = strlen(fingerprint);
   699 
   700     if (!lang || !lang[0])
   701         lang = "en";
   702 
   703     assert((lang[0] >= 'A' && lang[0] <= 'Z')
   704             || (lang[0] >= 'a' && lang[0] <= 'z'));
   705     assert((lang[1] >= 'A' && lang[1] <= 'Z')
   706             || (lang[1] >= 'a' && lang[1] <= 'z'));
   707     assert(lang[2] == 0);
   708 
   709     int n_words = 0;
   710     while (source < fingerprint + fsize) {
   711         uint16_t value;
   712         char *word;
   713         size_t _wsize;
   714         int j;
   715 
   716         for (value=0, j=0; j < 4 && source < fingerprint + fsize; ) {
   717             if (*source >= 'a' && *source <= 'f')
   718                 value += (*source - 'a' + 10) << (3 - j++) * 4;
   719             else if (*source >= 'A' && *source <= 'F')
   720                 value += (*source - 'A' + 10) << (3 - j++) * 4;
   721             else if (*source >= '0' && *source <= '9')
   722                 value += (*source - '0') << (3 - j++) * 4;
   723             
   724             source++;
   725         }
   726 
   727         _status = trustword(session, value, lang, &word, &_wsize);
   728         if (_status == PEP_OUT_OF_MEMORY) {
   729             free(buffer);
   730             return PEP_OUT_OF_MEMORY;
   731         }
   732         if (word == NULL) {
   733             free(buffer);
   734             return PEP_TRUSTWORD_NOT_FOUND;
   735         }
   736 
   737         if (dest + _wsize < buffer + MAX_TRUSTWORDS_SPACE - 1) {
   738             strncpy(dest, word, _wsize);
   739             free(word);
   740             dest += _wsize;
   741         }
   742         else {
   743             free(word);
   744             break; // buffer full
   745         }
   746 
   747         if (source < fingerprint + fsize
   748                 && dest + _wsize < buffer + MAX_TRUSTWORDS_SPACE - 1)
   749             *dest++ = ' ';
   750 
   751         ++n_words;
   752         if (max_words && n_words >= max_words)
   753             break;
   754     }
   755 
   756     *words = buffer;
   757     *wsize = dest - buffer;
   758     return PEP_STATUS_OK;
   759 }
   760 
   761 pEp_identity *new_identity(
   762         const char *address, const char *fpr, const char *user_id,
   763         const char *username
   764     )
   765 {
   766     pEp_identity *result = calloc(1, sizeof(pEp_identity));
   767     assert(result);
   768     if (result) {
   769         if (address) {
   770             result->address = strdup(address);
   771             assert(result->address);
   772             if (result->address == NULL) {
   773                 free(result);
   774                 return NULL;
   775             }
   776         }
   777         if (fpr) {
   778             result->fpr = strdup(fpr);
   779             assert(result->fpr);
   780             if (result->fpr == NULL) {
   781                 free_identity(result);
   782                 return NULL;
   783             }
   784         }
   785         if (user_id) {
   786             result->user_id = strdup(user_id);
   787             assert(result->user_id);
   788             if (result->user_id == NULL) {
   789                 free_identity(result);
   790                 return NULL;
   791             }
   792         }
   793         if (username) {
   794             result->username = strdup(username);
   795             assert(result->username);
   796             if (result->username == NULL) {
   797                 free_identity(result);
   798                 return NULL;
   799             }
   800         }
   801     }
   802     return result;
   803 }
   804 
   805 pEp_identity *identity_dup(const pEp_identity *src)
   806 {
   807     assert(src);
   808 
   809     pEp_identity *dup = new_identity(src->address, src->fpr, src->user_id, src->username);
   810     assert(dup);
   811     if (dup == NULL)
   812         return NULL;
   813     
   814     dup->comm_type = src->comm_type;
   815     dup->lang[0] = src->lang[0];
   816     dup->lang[1] = src->lang[1];
   817     dup->lang[2] = 0;
   818     dup->me = src->me;
   819     dup->flags = src->flags;
   820 
   821     return dup;
   822 }
   823 
   824 void free_identity(pEp_identity *identity)
   825 {
   826     if (identity) {
   827         free(identity->address);
   828         free(identity->fpr);
   829         free(identity->user_id);
   830         free(identity->username);
   831         free(identity);
   832     }
   833 }
   834 
   835 DYNAMIC_API PEP_STATUS get_identity(
   836         PEP_SESSION session,
   837         const char *address,
   838         const char *user_id,
   839         pEp_identity **identity
   840     )
   841 {
   842     PEP_STATUS status = PEP_STATUS_OK;
   843     static pEp_identity *_identity;
   844 
   845     assert(session);
   846     assert(address);
   847     assert(address[0]);
   848     assert(identity);
   849 
   850     if (!(session && address && address[0] && identity))
   851         return PEP_ILLEGAL_VALUE;
   852 
   853     *identity = NULL;
   854 
   855     sqlite3_reset(session->get_identity);
   856     sqlite3_bind_text(session->get_identity, 1, address, -1, SQLITE_STATIC);
   857     sqlite3_bind_text(session->get_identity, 2, user_id, -1, SQLITE_STATIC);
   858 
   859     const int result = sqlite3_step(session->get_identity);
   860     switch (result) {
   861     case SQLITE_ROW:
   862         _identity = new_identity(
   863                 address,
   864                 (const char *) sqlite3_column_text(session->get_identity, 0),
   865                 user_id,
   866                 (const char *) sqlite3_column_text(session->get_identity, 1)
   867                 );
   868         assert(_identity);
   869         if (_identity == NULL)
   870             return PEP_OUT_OF_MEMORY;
   871 
   872         _identity->comm_type = (PEP_comm_type) sqlite3_column_int(session->get_identity, 2);
   873         const char* const _lang = (const char *) sqlite3_column_text(session->get_identity, 3);
   874         if (_lang && _lang[0]) {
   875             assert(_lang[0] >= 'a' && _lang[0] <= 'z');
   876             assert(_lang[1] >= 'a' && _lang[1] <= 'z');
   877             assert(_lang[2] == 0);
   878             _identity->lang[0] = _lang[0];
   879             _identity->lang[1] = _lang[1];
   880             _identity->lang[2] = 0;
   881         }
   882         _identity->flags = (unsigned int) sqlite3_column_int(session->get_identity, 4);
   883         *identity = _identity;
   884         break;
   885     default:
   886         status = PEP_CANNOT_FIND_IDENTITY;
   887         *identity = NULL;
   888     }
   889 
   890     sqlite3_reset(session->get_identity);
   891     return status;
   892 }
   893 
   894 DYNAMIC_API PEP_STATUS set_identity(
   895         PEP_SESSION session, const pEp_identity *identity
   896     )
   897 {
   898     int result;
   899 
   900     assert(session);
   901     assert(identity);
   902     assert(identity->address);
   903     assert(identity->fpr);
   904     assert(identity->user_id);
   905     assert(identity->username);
   906 
   907     if (!(session && identity && identity->address && identity->fpr &&
   908                 identity->user_id && identity->username))
   909         return PEP_ILLEGAL_VALUE;
   910 
   911     bool listed;
   912     PEP_STATUS status = blacklist_is_listed(session, identity->fpr, &listed);
   913     assert(status == PEP_STATUS_OK);
   914     if (status != PEP_STATUS_OK)
   915         return status;
   916 
   917     if (listed)
   918         return PEP_KEY_BLACKLISTED;
   919 
   920     sqlite3_exec(session->db, "BEGIN ;", NULL, NULL, NULL);
   921 
   922     sqlite3_reset(session->set_person);
   923     sqlite3_bind_text(session->set_person, 1, identity->user_id, -1,
   924             SQLITE_STATIC);
   925     sqlite3_bind_text(session->set_person, 2, identity->username, -1,
   926             SQLITE_STATIC);
   927     if (identity->lang[0])
   928         sqlite3_bind_text(session->set_person, 3, identity->lang, 1,
   929                 SQLITE_STATIC);
   930     else
   931         sqlite3_bind_null(session->set_person, 3);
   932     sqlite3_bind_text(session->set_person, 4, identity->fpr, -1,
   933                       SQLITE_STATIC);
   934     result = sqlite3_step(session->set_person);
   935     sqlite3_reset(session->set_person);
   936     if (result != SQLITE_DONE) {
   937         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   938         return PEP_CANNOT_SET_PERSON;
   939     }
   940 
   941     sqlite3_reset(session->set_pgp_keypair);
   942     sqlite3_bind_text(session->set_pgp_keypair, 1, identity->fpr, -1,
   943             SQLITE_STATIC);
   944     result = sqlite3_step(session->set_pgp_keypair);
   945     sqlite3_reset(session->set_pgp_keypair);
   946     if (result != SQLITE_DONE) {
   947         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   948         return PEP_CANNOT_SET_PGP_KEYPAIR;
   949     }
   950 
   951     sqlite3_reset(session->set_identity);
   952     sqlite3_bind_text(session->set_identity, 1, identity->address, -1,
   953             SQLITE_STATIC);
   954     sqlite3_bind_text(session->set_identity, 2, identity->fpr, -1,
   955             SQLITE_STATIC);
   956     sqlite3_bind_text(session->set_identity, 3, identity->user_id, -1,
   957             SQLITE_STATIC);
   958     sqlite3_bind_int(session->set_trust, 4, identity->flags);
   959     result = sqlite3_step(session->set_identity);
   960     sqlite3_reset(session->set_identity);
   961     if (result != SQLITE_DONE) {
   962         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   963         return PEP_CANNOT_SET_IDENTITY;
   964     }
   965 
   966     sqlite3_reset(session->set_trust);
   967     sqlite3_bind_text(session->set_trust, 1, identity->user_id, -1,
   968             SQLITE_STATIC);
   969     sqlite3_bind_text(session->set_trust, 2, identity->fpr, -1,
   970             SQLITE_STATIC);
   971     sqlite3_bind_int(session->set_trust, 3, identity->comm_type);
   972     result = sqlite3_step(session->set_trust);
   973     sqlite3_reset(session->set_trust);
   974     if (result != SQLITE_DONE) {
   975         sqlite3_exec(session->db, "ROLLBACK ;", NULL, NULL, NULL);
   976         return PEP_CANNOT_SET_TRUST;
   977     }
   978 
   979     result = sqlite3_exec(session->db, "COMMIT ;", NULL, NULL, NULL);
   980     if (result == SQLITE_OK)
   981         return PEP_STATUS_OK;
   982     else
   983         return PEP_COMMIT_FAILED;
   984 }
   985 
   986 DYNAMIC_API PEP_STATUS mark_as_compromized(
   987         PEP_SESSION session,
   988         const char *fpr
   989     )
   990 {
   991     int result;
   992 
   993     assert(session);
   994     assert(fpr && fpr[0]);
   995 
   996     if (!(session && fpr && fpr[0]))
   997         return PEP_ILLEGAL_VALUE;
   998 
   999     sqlite3_reset(session->mark_compromized);
  1000     sqlite3_bind_text(session->mark_compromized, 1, fpr, -1,
  1001             SQLITE_STATIC);
  1002     result = sqlite3_step(session->mark_compromized);
  1003     sqlite3_reset(session->mark_compromized);
  1004 
  1005     if (result != SQLITE_DONE)
  1006         return PEP_CANNOT_SET_TRUST;
  1007 
  1008     return PEP_STATUS_OK;
  1009 }
  1010 
  1011 void pEp_free(void *p)
  1012 {
  1013     free(p);
  1014 }
  1015 
  1016 DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity)
  1017 {
  1018     PEP_STATUS status = PEP_STATUS_OK;
  1019     int result;
  1020 
  1021     assert(session);
  1022     assert(identity);
  1023     assert(identity->user_id);
  1024     assert(identity->user_id[0]);
  1025     assert(identity->fpr);
  1026     assert(identity->fpr[0]);
  1027 
  1028     if (!(session && identity && identity->user_id && identity->user_id[0] &&
  1029                 identity->fpr && identity->fpr[0]))
  1030         return PEP_ILLEGAL_VALUE;
  1031 
  1032     identity->comm_type = PEP_ct_unknown;
  1033 
  1034     sqlite3_reset(session->get_trust);
  1035     sqlite3_bind_text(session->get_trust, 1, identity->user_id, -1, SQLITE_STATIC);
  1036     sqlite3_bind_text(session->get_trust, 2, identity->fpr, -1, SQLITE_STATIC);
  1037 
  1038     result = sqlite3_step(session->get_trust);
  1039     switch (result) {
  1040     case SQLITE_ROW: {
  1041         int comm_type = (PEP_comm_type) sqlite3_column_int(session->get_trust, 0);
  1042         identity->comm_type = comm_type;
  1043         break;
  1044     }
  1045  
  1046     default:
  1047         status = PEP_CANNOT_FIND_IDENTITY;
  1048     }
  1049 
  1050     sqlite3_reset(session->get_trust);
  1051     return status;
  1052 }
  1053 
  1054 DYNAMIC_API PEP_STATUS least_trust(
  1055         PEP_SESSION session,
  1056         const char *fpr,
  1057         PEP_comm_type *comm_type
  1058     )
  1059 {
  1060     PEP_STATUS status = PEP_STATUS_OK;
  1061     int result;
  1062 
  1063     assert(session);
  1064     assert(fpr);
  1065     assert(comm_type);
  1066 
  1067     if (!(session && fpr && comm_type))
  1068         return PEP_ILLEGAL_VALUE;
  1069 
  1070     *comm_type = PEP_ct_unknown;
  1071 
  1072     sqlite3_reset(session->least_trust);
  1073     sqlite3_bind_text(session->least_trust, 1, fpr, -1, SQLITE_STATIC);
  1074 
  1075     result = sqlite3_step(session->least_trust);
  1076     switch (result) {
  1077         case SQLITE_ROW: {
  1078             int _comm_type = sqlite3_column_int(session->least_trust, 0);
  1079             *comm_type = (PEP_comm_type) _comm_type;
  1080             break;
  1081         }
  1082         default:
  1083             status = PEP_CANNOT_FIND_IDENTITY;
  1084     }
  1085 
  1086     sqlite3_reset(session->least_trust);
  1087     return status;
  1088 }
  1089 
  1090 DYNAMIC_API PEP_STATUS decrypt_and_verify(
  1091     PEP_SESSION session, const char *ctext, size_t csize,
  1092     char **ptext, size_t *psize, stringlist_t **keylist
  1093     )
  1094 {
  1095     assert(session);
  1096     assert(ctext);
  1097     assert(csize);
  1098     assert(ptext);
  1099     assert(psize);
  1100     assert(keylist);
  1101 
  1102     if (!(session && ctext && csize && ptext && psize && keylist && keylist))
  1103         return PEP_ILLEGAL_VALUE;
  1104 
  1105     return session->cryptotech[PEP_crypt_OpenPGP].decrypt_and_verify(session, ctext, csize, ptext, psize, keylist);
  1106 }
  1107 
  1108 DYNAMIC_API PEP_STATUS encrypt_and_sign(
  1109     PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
  1110     size_t psize, char **ctext, size_t *csize
  1111     )
  1112 {
  1113     assert(session);
  1114     assert(keylist);
  1115     assert(ptext);
  1116     assert(psize);
  1117     assert(ctext);
  1118     assert(csize);
  1119 
  1120     if (!(session && keylist && ptext && psize && ctext && csize))
  1121         return PEP_ILLEGAL_VALUE;
  1122 
  1123     return session->cryptotech[PEP_crypt_OpenPGP].encrypt_and_sign(session, keylist, ptext, psize, ctext, csize);
  1124 }
  1125 
  1126 DYNAMIC_API PEP_STATUS verify_text(
  1127     PEP_SESSION session, const char *text, size_t size,
  1128     const char *signature, size_t sig_size, stringlist_t **keylist
  1129     )
  1130 {
  1131     assert(session);
  1132     assert(text);
  1133     assert(size);
  1134     assert(signature);
  1135     assert(sig_size);
  1136     assert(keylist);
  1137 
  1138     if (!(session && text && size && signature && sig_size && keylist))
  1139         return PEP_ILLEGAL_VALUE;
  1140 
  1141     return session->cryptotech[PEP_crypt_OpenPGP].verify_text(session, text, size, signature, sig_size, keylist);
  1142 }
  1143 
  1144 DYNAMIC_API PEP_STATUS delete_keypair(PEP_SESSION session, const char *fpr)
  1145 {
  1146     assert(session);
  1147     assert(fpr);
  1148 
  1149     if (!(session && fpr))
  1150         return PEP_ILLEGAL_VALUE;
  1151 
  1152     return session->cryptotech[PEP_crypt_OpenPGP].delete_keypair(session, fpr);
  1153 }
  1154 
  1155 DYNAMIC_API PEP_STATUS export_key(
  1156         PEP_SESSION session, const char *fpr, char **key_data, size_t *size
  1157     )
  1158 {
  1159     assert(session);
  1160     assert(fpr);
  1161     assert(key_data);
  1162     assert(size);
  1163 
  1164     if (!(session && fpr && key_data && size))
  1165         return PEP_ILLEGAL_VALUE;
  1166 
  1167     return session->cryptotech[PEP_crypt_OpenPGP].export_key(session, fpr, key_data, size);
  1168 }
  1169 
  1170 DYNAMIC_API PEP_STATUS find_keys(
  1171         PEP_SESSION session, const char *pattern, stringlist_t **keylist
  1172     )
  1173 {
  1174     assert(session);
  1175     assert(pattern);
  1176     assert(keylist);
  1177 
  1178     if (!(session && pattern && keylist))
  1179         return PEP_ILLEGAL_VALUE;
  1180 
  1181     return session->cryptotech[PEP_crypt_OpenPGP].find_keys(session, pattern, keylist);
  1182 }
  1183 
  1184 DYNAMIC_API PEP_STATUS generate_keypair(
  1185         PEP_SESSION session, pEp_identity *identity
  1186     )
  1187 {
  1188     assert(session);
  1189     assert(identity);
  1190     assert(identity->address);
  1191     assert(identity->fpr == NULL || identity->fpr[0] == 0);
  1192     assert(identity->username);
  1193 
  1194     if (!(session && identity && identity->address &&
  1195         (identity->fpr == NULL || identity->fpr[0] == 0) && identity->username))
  1196         return PEP_ILLEGAL_VALUE;
  1197 
  1198     return session->cryptotech[PEP_crypt_OpenPGP].generate_keypair(session, identity);
  1199 }
  1200 
  1201 DYNAMIC_API PEP_STATUS get_key_rating(
  1202         PEP_SESSION session,
  1203         const char *fpr,
  1204         PEP_comm_type *comm_type
  1205     )
  1206 {
  1207     assert(session);
  1208     assert(fpr);
  1209     assert(comm_type);
  1210 
  1211     if (!(session && fpr && comm_type))
  1212         return PEP_ILLEGAL_VALUE;
  1213 
  1214     return session->cryptotech[PEP_crypt_OpenPGP].get_key_rating(session, fpr, comm_type);
  1215 }
  1216 
  1217 DYNAMIC_API PEP_STATUS import_key(
  1218         PEP_SESSION session,
  1219         const char *key_data,
  1220         size_t size,
  1221         identity_list **private_keys
  1222     )
  1223 {
  1224     assert(session);
  1225     assert(key_data);
  1226 
  1227     if (!(session && key_data))
  1228         return PEP_ILLEGAL_VALUE;
  1229 
  1230     return session->cryptotech[PEP_crypt_OpenPGP].import_key(session, key_data, size, private_keys);
  1231 }
  1232 
  1233 DYNAMIC_API PEP_STATUS recv_key(PEP_SESSION session, const char *pattern)
  1234 {
  1235     assert(session);
  1236     assert(pattern);
  1237 
  1238     if (!(session && pattern))
  1239         return PEP_ILLEGAL_VALUE;
  1240 
  1241     return session->cryptotech[PEP_crypt_OpenPGP].recv_key(session, pattern);
  1242 }
  1243 
  1244 DYNAMIC_API PEP_STATUS send_key(PEP_SESSION session, const char *pattern)
  1245 {
  1246     assert(session);
  1247     assert(pattern);
  1248 
  1249     if (!(session && pattern))
  1250         return PEP_ILLEGAL_VALUE;
  1251 
  1252     return session->cryptotech[PEP_crypt_OpenPGP].send_key(session, pattern);
  1253 }
  1254 
  1255 DYNAMIC_API PEP_STATUS renew_key(
  1256         PEP_SESSION session,
  1257         const char *fpr,
  1258         const timestamp *ts
  1259     )
  1260 {
  1261     assert(session);
  1262     assert(fpr);
  1263 
  1264     if (!(session && fpr))
  1265         return PEP_ILLEGAL_VALUE;
  1266 
  1267     return session->cryptotech[PEP_crypt_OpenPGP].renew_key(session, fpr, ts);
  1268 }
  1269 
  1270 DYNAMIC_API PEP_STATUS revoke_key(
  1271         PEP_SESSION session,
  1272         const char *fpr,
  1273         const char *reason
  1274     )
  1275 {
  1276     assert(session);
  1277     assert(fpr);
  1278 
  1279     if (!(session && fpr))
  1280         return PEP_ILLEGAL_VALUE;
  1281 
  1282     return session->cryptotech[PEP_crypt_OpenPGP].revoke_key(session, fpr,
  1283             reason);
  1284 }
  1285 
  1286 DYNAMIC_API PEP_STATUS key_expired(
  1287         PEP_SESSION session,
  1288         const char *fpr,
  1289         const time_t when,
  1290         bool *expired
  1291     )
  1292 {
  1293     assert(session);
  1294     assert(fpr);
  1295     assert(expired);
  1296 
  1297     if (!(session && fpr && expired))
  1298         return PEP_ILLEGAL_VALUE;
  1299 
  1300     return session->cryptotech[PEP_crypt_OpenPGP].key_expired(session, fpr,
  1301             when, expired);
  1302 }
  1303 
  1304 DYNAMIC_API PEP_STATUS key_revoked(
  1305                                    PEP_SESSION session,
  1306                                    const char *fpr,
  1307                                    bool *revoked
  1308                                    )
  1309 {
  1310     assert(session);
  1311     assert(fpr);
  1312     assert(revoked);
  1313     
  1314     if (!(session && fpr && revoked))
  1315         return PEP_ILLEGAL_VALUE;
  1316     
  1317     return session->cryptotech[PEP_crypt_OpenPGP].key_revoked(session, fpr,
  1318                                                               revoked);
  1319 }
  1320 
  1321 static void _clean_log_value(char *text)
  1322 {
  1323     if (text) {
  1324         for (char *c = text; *c; c++) {
  1325             if (*c < 32 && *c != '\n')
  1326                 *c = 32;
  1327             else if (*c == '"')
  1328                 *c = '\'';
  1329         }
  1330     }
  1331 }
  1332 
  1333 static char *_concat_string(char *str1, const char *str2, char delim)
  1334 {
  1335     str2 = str2 ? str2 : "";
  1336     size_t len1 = str1 ? strlen(str1) : 0;
  1337     size_t len2 = strlen(str2);
  1338     size_t len = len1 + len2 + 3;
  1339     char * result = realloc(str1, len + 1);
  1340 
  1341     if (result) {
  1342         result[len1] = '"';
  1343         strcpy(result + len1 + 1, str2);
  1344         result[len - 2] = '"';
  1345         result[len - 1] = delim;
  1346         result[len] = 0;
  1347     }
  1348     else {
  1349         free(str1);
  1350     }
  1351 
  1352     return result;
  1353 }
  1354 
  1355 DYNAMIC_API PEP_STATUS get_crashdump_log(
  1356         PEP_SESSION session,
  1357         int maxlines,
  1358         char **logdata
  1359     )
  1360 {
  1361     PEP_STATUS status = PEP_STATUS_OK;
  1362     char *_logdata= NULL;
  1363 
  1364     assert(session);
  1365     assert(maxlines >= 0 && maxlines <= CRASHDUMP_MAX_LINES);
  1366     assert(logdata);
  1367 
  1368     if (!(session && logdata && maxlines >= 0 && maxlines <=
  1369             CRASHDUMP_MAX_LINES))
  1370         return PEP_ILLEGAL_VALUE;
  1371 
  1372     *logdata = NULL;
  1373 
  1374     int limit = maxlines ? maxlines : CRASHDUMP_DEFAULT_LINES;
  1375     const char *timestamp = NULL;
  1376     const char *title = NULL;
  1377     const char *entity = NULL;
  1378     const char *desc = NULL;
  1379     const char *comment = NULL;
  1380 
  1381     sqlite3_reset(session->crashdump);
  1382     sqlite3_bind_int(session->crashdump, 1, limit);
  1383 
  1384     int result;
  1385 
  1386     do {
  1387         result = sqlite3_step(session->crashdump);
  1388         switch (result) {
  1389         case SQLITE_ROW:
  1390             timestamp = (const char *) sqlite3_column_text(session->crashdump, 0);
  1391             title   = (const char *) sqlite3_column_text(session->crashdump, 1);
  1392             entity  = (const char *) sqlite3_column_text(session->crashdump, 2);
  1393             desc    = (const char *) sqlite3_column_text(session->crashdump, 3);
  1394             comment = (const char *) sqlite3_column_text(session->crashdump, 4);
  1395 
  1396             _logdata = _concat_string(_logdata, timestamp, ',');
  1397             if (_logdata == NULL)
  1398                 goto enomem;
  1399 
  1400             _logdata = _concat_string(_logdata, title, ',');
  1401             if (_logdata == NULL)
  1402                 goto enomem;
  1403 
  1404             _logdata = _concat_string(_logdata, entity, ',');
  1405             if (_logdata == NULL)
  1406                 goto enomem;
  1407 
  1408             _logdata = _concat_string(_logdata, desc, ',');
  1409             if (_logdata == NULL)
  1410                 goto enomem;
  1411 
  1412             _logdata = _concat_string(_logdata, comment, '\n');
  1413             if (_logdata == NULL)
  1414                 goto enomem;
  1415 
  1416             _clean_log_value(_logdata);
  1417             break;
  1418 
  1419         case SQLITE_DONE:
  1420             break;
  1421 
  1422         default:
  1423             status = PEP_UNKNOWN_ERROR;
  1424             result = SQLITE_DONE;
  1425         }
  1426     } while (result != SQLITE_DONE);
  1427 
  1428     sqlite3_reset(session->crashdump);
  1429     if (status == PEP_STATUS_OK)
  1430         *logdata = _logdata;
  1431 
  1432     goto the_end;
  1433 
  1434 enomem:
  1435     status = PEP_OUT_OF_MEMORY;
  1436 
  1437 the_end:
  1438     return status;
  1439 }
  1440 
  1441 DYNAMIC_API PEP_STATUS get_languagelist(
  1442         PEP_SESSION session,
  1443         char **languages
  1444     )
  1445 {
  1446     PEP_STATUS status = PEP_STATUS_OK;
  1447     char *_languages= NULL;
  1448 
  1449     assert(session);
  1450     assert(languages);
  1451 
  1452     if (!(session && languages))
  1453         return PEP_ILLEGAL_VALUE;
  1454 
  1455     *languages = NULL;
  1456 
  1457     const char *lang = NULL;
  1458     const char *name = NULL;
  1459     const char *phrase = NULL;
  1460 
  1461     sqlite3_reset(session->languagelist);
  1462 
  1463     int result;
  1464 
  1465     do {
  1466         result = sqlite3_step(session->languagelist);
  1467         switch (result) {
  1468         case SQLITE_ROW:
  1469             lang = (const char *) sqlite3_column_text(session->languagelist, 0);
  1470             name = (const char *) sqlite3_column_text(session->languagelist, 1);
  1471             phrase = (const char *) sqlite3_column_text(session->languagelist, 2);
  1472 
  1473             _languages = _concat_string(_languages, lang, ',');
  1474             if (_languages == NULL)
  1475                 goto enomem;
  1476 
  1477             _languages = _concat_string(_languages, name, ',');
  1478             if (_languages == NULL)
  1479                 goto enomem;
  1480 
  1481             _languages = _concat_string(_languages, phrase, '\n');
  1482             if (_languages == NULL)
  1483                 goto enomem;
  1484 
  1485             break;
  1486 
  1487         case SQLITE_DONE:
  1488             break;
  1489 
  1490         default:
  1491             status = PEP_UNKNOWN_ERROR;
  1492             result = SQLITE_DONE;
  1493         }
  1494     } while (result != SQLITE_DONE);
  1495 
  1496     sqlite3_reset(session->languagelist);
  1497     if (status == PEP_STATUS_OK)
  1498         *languages = _languages;
  1499 
  1500     goto the_end;
  1501 
  1502 enomem:
  1503     status = PEP_OUT_OF_MEMORY;
  1504 
  1505 the_end:
  1506     return status;
  1507 }
  1508 
  1509 DYNAMIC_API PEP_STATUS get_phrase(
  1510         PEP_SESSION session,
  1511         const char *lang,
  1512         int phrase_id,
  1513         char **phrase
  1514     )
  1515 {
  1516     PEP_STATUS status = PEP_STATUS_OK;
  1517 
  1518     assert(session && lang && lang[0] && lang[1] && lang[2] == 0 && phrase);
  1519     if (!(session && lang && lang[0] && lang[1] && lang[2] == 0 && phrase))
  1520         return PEP_ILLEGAL_VALUE;
  1521 
  1522     *phrase = NULL;
  1523 
  1524     sqlite3_reset(session->i18n_token);
  1525     sqlite3_bind_text(session->i18n_token, 1, lang, -1, SQLITE_STATIC);
  1526     sqlite3_bind_int(session->i18n_token, 2, phrase_id);
  1527 
  1528     const char *_phrase = NULL;
  1529     int result;
  1530 
  1531     result = sqlite3_step(session->i18n_token);
  1532     switch (result) {
  1533     case SQLITE_ROW:
  1534         _phrase = (const char *) sqlite3_column_text(session->i18n_token, 0);
  1535         break;
  1536 
  1537     case SQLITE_DONE:
  1538         status = PEP_PHRASE_NOT_FOUND;
  1539         break;
  1540 
  1541     default:
  1542         status = PEP_UNKNOWN_ERROR;
  1543     }
  1544 
  1545     if (status == PEP_STATUS_OK) {
  1546         *phrase = strdup(_phrase);
  1547         if (*phrase == NULL)
  1548             goto enomem;
  1549     }
  1550 
  1551     sqlite3_reset(session->i18n_token);
  1552     goto the_end;
  1553 
  1554 enomem:
  1555     status = PEP_OUT_OF_MEMORY;
  1556 
  1557 the_end:
  1558     return status;
  1559 }
  1560 
  1561 DYNAMIC_API PEP_STATUS sequence_value(
  1562         PEP_SESSION session,
  1563         const char *name,
  1564         int32_t *value
  1565     )
  1566 {
  1567     PEP_STATUS status = PEP_STATUS_OK;
  1568     int result;
  1569 
  1570     assert(session);
  1571     assert(name);
  1572     assert(value);
  1573 
  1574     if (!(session && name && value))
  1575         return PEP_ILLEGAL_VALUE;
  1576 
  1577     *value = 0;
  1578 
  1579     sqlite3_reset(session->sequence_value1);
  1580     sqlite3_bind_text(session->sequence_value1, 1, name, -1, SQLITE_STATIC);
  1581     result = sqlite3_step(session->sequence_value1);
  1582     assert(result == SQLITE_DONE);
  1583     sqlite3_reset(session->sequence_value1);
  1584     if (result != SQLITE_DONE) {
  1585         status = PEP_UNKNOWN_ERROR;
  1586     }
  1587     else {
  1588         sqlite3_reset(session->sequence_value2);
  1589         sqlite3_bind_text(session->sequence_value2, 1, name, -1, SQLITE_STATIC);
  1590         result = sqlite3_step(session->sequence_value2);
  1591         switch (result) {
  1592             case SQLITE_ROW: {
  1593                 int32_t _value = (int32_t)
  1594                         sqlite3_column_int64(session->sequence_value2, 0);
  1595                 *value = _value;
  1596                 break;
  1597             }
  1598             default:
  1599                 status = PEP_UNKNOWN_ERROR;
  1600         }
  1601         sqlite3_reset(session->sequence_value2);
  1602     }
  1603     return status;
  1604 }
  1605 
  1606 DYNAMIC_API PEP_STATUS set_revoked(
  1607        PEP_SESSION session,
  1608        const char *revoked_fpr,
  1609        const char *replacement_fpr,
  1610        const uint64_t revocation_date
  1611     )
  1612 {
  1613     PEP_STATUS status = PEP_STATUS_OK;
  1614     
  1615     assert(session &&
  1616            revoked_fpr && revoked_fpr[0] &&
  1617            replacement_fpr && replacement_fpr[0]
  1618           );
  1619     
  1620     if (!(session &&
  1621           revoked_fpr && revoked_fpr[0] &&
  1622           replacement_fpr && replacement_fpr[0]
  1623          ))
  1624         return PEP_ILLEGAL_VALUE;
  1625     
  1626     sqlite3_reset(session->set_revoked);
  1627     sqlite3_bind_text(session->set_revoked, 1, revoked_fpr, -1, SQLITE_STATIC);
  1628     sqlite3_bind_text(session->set_revoked, 2, replacement_fpr, -1, SQLITE_STATIC);
  1629     sqlite3_bind_int64(session->set_revoked, 3, revocation_date);
  1630 
  1631     int result;
  1632     
  1633     result = sqlite3_step(session->set_revoked);
  1634     switch (result) {
  1635         case SQLITE_DONE:
  1636             status = PEP_STATUS_OK;
  1637             break;
  1638             
  1639         default:
  1640             status = PEP_UNKNOWN_ERROR;
  1641     }
  1642     
  1643     sqlite3_reset(session->set_revoked);
  1644     return status;
  1645 }
  1646 
  1647 DYNAMIC_API PEP_STATUS get_revoked(
  1648         PEP_SESSION session,
  1649         const char *fpr,
  1650         char **revoked_fpr,
  1651         uint64_t *revocation_date
  1652     )
  1653 {
  1654     PEP_STATUS status = PEP_STATUS_OK;
  1655 
  1656     assert(session &&
  1657            revoked_fpr &&
  1658            fpr && fpr[0]
  1659           );
  1660     
  1661     if (!(session &&
  1662            revoked_fpr &&
  1663            fpr && fpr[0]
  1664           ))
  1665         return PEP_ILLEGAL_VALUE;
  1666 
  1667     *revoked_fpr = NULL;
  1668     *revocation_date = 0;
  1669 
  1670     sqlite3_reset(session->get_revoked);
  1671     sqlite3_bind_text(session->get_revoked, 1, fpr, -1, SQLITE_STATIC);
  1672 
  1673     int result;
  1674     
  1675     result = sqlite3_step(session->get_revoked);
  1676     switch (result) {
  1677         case SQLITE_ROW: {
  1678             *revoked_fpr = strdup((const char *) sqlite3_column_text(session->get_revoked, 0));
  1679             if(*revoked_fpr)
  1680                 *revocation_date = sqlite3_column_int64(session->get_revoked, 1);
  1681             else
  1682                 status = PEP_OUT_OF_MEMORY;
  1683 
  1684             break;
  1685         }
  1686         default:
  1687             status = PEP_CANNOT_FIND_IDENTITY;
  1688     }
  1689 
  1690     sqlite3_reset(session->get_revoked);
  1691 
  1692     return status;
  1693 }
  1694 
  1695 DYNAMIC_API PEP_STATUS reset_peptest_hack(PEP_SESSION session)
  1696 {
  1697     assert(session);
  1698 
  1699     if (!session)
  1700         return PEP_ILLEGAL_VALUE;
  1701 
  1702     int int_result = sqlite3_exec(
  1703         session->db,
  1704         "delete from identity where address like '%@peptest.ch' ;",
  1705         NULL,
  1706         NULL,
  1707         NULL
  1708     );
  1709     assert(int_result == SQLITE_OK);
  1710 
  1711     return PEP_STATUS_OK;
  1712 }
  1713