From c52f4d39fb8b2c73b6d5c5f37addce0516af9aca Mon Sep 17 00:00:00 2001 From: Krista Bennett Date: Mon, 22 Feb 2021 20:00:04 +0100 Subject: [PATCH] Added sql separate from ENGINE-606/ENGINE-822 so that the DDLs don't diverge any further (merges are difficult without this being separated this way in master as well). This means that some of the groups sql logic is present here, but it won't get used until the branch code makes it in here. If you have problems merging a branch, let me know. Better now than later. --- src/engine_sql.c | 2642 ++++++++++++++++++++++++++++++++++++++++++ src/engine_sql.h | 560 +++++++++ src/key_reset.c | 15 - src/pEpEngine.c | 2735 +------------------------------------------- src/pEp_internal.h | 48 +- 5 files changed, 3305 insertions(+), 2695 deletions(-) create mode 100644 src/engine_sql.c create mode 100644 src/engine_sql.h diff --git a/src/engine_sql.c b/src/engine_sql.c new file mode 100644 index 000000000..2dbe91281 --- /dev/null +++ b/src/engine_sql.c @@ -0,0 +1,2642 @@ +#include "pEp_internal.h" +#include "engine_sql.h" + +// sql overloaded functions - modified from sqlite3.c +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] *ctx sqlite3_context + * @param[in] argc int + * @param[in] **argv sqlite3_value + * + */ +static void _sql_lower(sqlite3_context* ctx, int argc, sqlite3_value** argv) { + const char *z2; + int n; + z2 = (char*)sqlite3_value_text(argv[0]); + n = sqlite3_value_bytes(argv[0]); + /* Verify that the call to _bytes() does not invalidate the _text() pointer */ + assert( z2==(char*)sqlite3_value_text(argv[0]) ); + if( z2 ){ + char *z1 = (char*)sqlite3_malloc(n+1); + if( z1 ){ + for(int i=0; i 0x7a) + c_mod = c; + z1[i] = c_mod; + } + z1[n] = '\0'; + sqlite3_result_text(ctx, z1, n, sqlite3_free); + } + } +} + +#ifdef _PEP_SQLITE_DEBUG +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] trace_constant unsigned + * @param[in] *context_ptr void + * @param[in] *P void + * @param[in] *X void + * + */ +int sql_trace_callback (unsigned trace_constant, + void* context_ptr, + void* P, + void* X) { + switch (trace_constant) { + case SQLITE_TRACE_STMT: + fprintf(stderr, "SQL_DEBUG: STMT - "); + const char* X_str = (const char*) X; + if (!EMPTYSTR(X_str) && X_str[0] == '-' && X_str[1] == '-') + fprintf(stderr, "%s\n", X_str); + else + fprintf(stderr, "%s\n", sqlite3_expanded_sql((sqlite3_stmt*)P)); + break; + case SQLITE_TRACE_ROW: + fprintf(stderr, "SQL_DEBUG: ROW - "); + fprintf(stderr, "%s\n", sqlite3_expanded_sql((sqlite3_stmt*)P)); + break; + case SQLITE_TRACE_CLOSE: + fprintf(stderr, "SQL_DEBUG: CLOSE - "); + break; + default: + break; + } + return 0; +} +#endif + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] *pArg void + * @param[in] iErrCode int + * @param[in] *zMsg constchar + * + */ +void errorLogCallback(void *pArg, int iErrCode, const char *zMsg){ + fprintf(stderr, "(%d) %s\n", iErrCode, zMsg); +} + +// TODO: refactor and generalise these two functions if possible. +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] session PEP_SESSION + * @param[in] *table_name constchar + * + */ +static int db_contains_table(PEP_SESSION session, const char* table_name) { + if (!session || !table_name) + return -1; + + // Table names can't be SQL parameters, so we do it this way. + + // these two must be the same number. + char sql_buf[500]; + const size_t max_q_len = 500; + + size_t t_size, q_size; + + const char* q1 = "SELECT name FROM sqlite_master WHERE type='table' AND name='{"; // 61 + const char* q2 = "}';"; // 3 + + q_size = 64; + t_size = strlen(table_name); + + size_t query_len = q_size + t_size + 1; + + if (query_len > max_q_len) + return -1; + + strlcpy(sql_buf, q1, max_q_len); + strlcat(sql_buf, table_name, max_q_len); + strlcat(sql_buf, q2, max_q_len); + + sqlite3_stmt *stmt; + + sqlite3_prepare_v2(session->db, sql_buf, -1, &stmt, NULL); + + int retval = 0; + + int rc = sqlite3_step(stmt); + if (rc == SQLITE_DONE || rc == SQLITE_OK || rc == SQLITE_ROW) { + retval = 1; + } + + sqlite3_finalize(stmt); + + return retval; + +} + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] session PEP_SESSION + * @param[in] *table_name constchar + * @param[in] *col_name constchar + * + */ +static int table_contains_column(PEP_SESSION session, const char* table_name, + const char* col_name) { + + + if (!session || !table_name || !col_name) + return -1; + + // Table names can't be SQL parameters, so we do it this way. + + // these two must be the same number. + char sql_buf[500]; + const size_t max_q_len = 500; + + size_t t_size, c_size, q_size; + + const char* q1 = "SELECT "; // 7 + const char* q2 = " from "; // 6 + const char* q3 = ";"; // 1 + + q_size = 14; + t_size = strlen(table_name); + c_size = strlen(col_name); + + size_t query_len = q_size + c_size + t_size + 1; + + if (query_len > max_q_len) + return -1; + + strlcpy(sql_buf, q1, max_q_len); + strlcat(sql_buf, col_name, max_q_len); + strlcat(sql_buf, q2, max_q_len); + strlcat(sql_buf, table_name, max_q_len); + strlcat(sql_buf, q3, max_q_len); + + sqlite3_stmt *stmt; + + sqlite3_prepare_v2(session->db, sql_buf, -1, &stmt, NULL); + + int retval = 0; + + int rc = sqlite3_step(stmt); + if (rc == SQLITE_DONE || rc == SQLITE_OK || rc == SQLITE_ROW) { + retval = 1; + } + + sqlite3_finalize(stmt); + + return retval; +} + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] session PEP_SESSION + * + */ +#define _PEP_MAX_AFFECTED 5 +PEP_STATUS repair_altered_tables(PEP_SESSION session) { + PEP_STATUS status = PEP_STATUS_OK; + + char* table_names[_PEP_MAX_AFFECTED] = {0}; + + const char* sql_query = "select tbl_name from sqlite_master WHERE sql LIKE '%REFERENCES%' AND sql LIKE '%_old%';"; + sqlite3_stmt *stmt; + sqlite3_prepare_v2(session->db, sql_query, -1, &stmt, NULL); + int i = 0; + int int_result = 0; + while ((int_result = sqlite3_step(stmt)) == SQLITE_ROW && i < _PEP_MAX_AFFECTED) { + table_names[i++] = strdup((const char*)(sqlite3_column_text(stmt, 0))); + } + + sqlite3_finalize(stmt); + + if ((int_result != SQLITE_DONE && int_result != SQLITE_OK) || i > (_PEP_MAX_AFFECTED + 1)) { + status = PEP_UNKNOWN_DB_ERROR; + goto pEp_free; + } + + for (i = 0; i < _PEP_MAX_AFFECTED; i++) { + const char* table_name = table_names[i]; + if (!table_name) + break; + + if (strcmp(table_name, "identity") == 0) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _identity_new (\n" + " address text,\n" + " user_id text\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " comment text,\n" + " flags integer default 0,\n" + " is_own integer default 0,\n" + " timestamp integer default (datetime('now')),\n" + " primary key (address, user_id)\n" + ");\n" + "INSERT INTO _identity_new SELECT * from identity;\n" + "DROP TABLE identity;\n" + "ALTER TABLE _identity_new RENAME TO identity;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + else if (strcmp(table_name, "trust") == 0) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _trust_new (\n" + " user_id text not null\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " pgp_keypair_fpr text not null\n" + " references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " comm_type integer not null,\n" + " comment text,\n" + " primary key (user_id, pgp_keypair_fpr)\n" + ");\n" + "INSERT INTO _trust_new SELECT * from trust;\n" + "DROP TABLE trust;\n" + "ALTER TABLE _trust_new RENAME TO trust;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + else if (strcmp(table_name, "alternate_user_id") == 0) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _alternate_user_id_new (\n" + " default_id text references person (id)\n" + " on delete cascade on update cascade,\n" + " alternate_id text primary key\n" + ");\n" + "INSERT INTO _alternate_user_id_new SELECT * from alternate_user_id;\n" + "DROP TABLE alternate_user_id;\n" + "ALTER TABLE _alternate_user_id_new RENAME TO alternate_user_id;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + else if (strcmp(table_name, "revocation_contact_list") == 0) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _revocation_contact_list_new (\n" + " fpr text not null references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " contact_id text not null references person (id)\n" + " on delete cascade on update cascade,\n" + " timestamp integer default (datetime('now')),\n" + " PRIMARY KEY(fpr, contact_id)\n" + ");\n" + "INSERT INTO _revocation_contact_list_new SELECT * from revocation_contact_list;\n" + "DROP TABLE revocation_contact_list;\n" + "ALTER TABLE _revocation_contact_list_new RENAME TO revocation_contact_list;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + else if (strcmp(table_name, "social_graph")) { + int_result = sqlite3_exec(session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _social_new (\n" + " own_userid text,\n" + " own_address text,\n" + " contact_userid text,\n" + " CONSTRAINT fk_own_identity\n" + " FOREIGN KEY(own_address, own_userid)\n" + " REFERENCES identity(address, user_id)\n" + " ON DELETE CASCADE ON UPDATE CASCADE\n" + ");\n" + "INSERT INTO _social_graph_new SELECT * from social_graph;\n" + "DROP TABLE social_graph;\n" + "ALTER TABLE _social_graph_new RENAME TO social_graph;\n" + "COMMIT;\n" + "PRAGMA foreign_keys=on;" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + } + } + + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_key_check;\n" + , + NULL, + NULL, + NULL + ); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + pEp_free: + for (i = 0; i < _PEP_MAX_AFFECTED; i++) { + free(table_names[i]); + } + return status; +} + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] session PEP_SESSION + * + */ +static PEP_STATUS upgrade_revoc_contact_to_13(PEP_SESSION session) { + // I HATE SQLITE. + PEP_STATUS status = PEP_STATUS_OK; + int int_result = 0; + + // Ok, first we ADD the column so we can USE it. + // We will end up propagating the "error" this first time + // (one-to-one revoke-replace relationships), but since key reset + // hasn't been used in production, this is not a customer-facing + // issue. + + // Note: the check upfront is to deal with partially-upgraded DB issues + if (!table_contains_column(session, "revocation_contact_list", "own_address")) { + int_result = sqlite3_exec( + session->db, + "alter table revocation_contact_list\n" + " add column own_address text;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + } + + // the best we can do here is search per address, since these + // are no longer associated with an identity. For now, if we find + // something we can't add an address to, we'll delete the record. + // this should not, in the current environment, ever happen, but + // since we need to make the address part of the primary key, it's + // the right thing to do. sqlite does support null fields in a primary + // key for a weird version compatibility reason, but that doesn't + // mean we should use it, and we should be *safe*, not relying + // on an implementation-specific quirk which might be sanely removed + // in a future sqlite version. + + identity_list* id_list = NULL; + + sqlite3_stmt* tmp_own_id_retrieve = NULL; + sqlite3_prepare_v2(session->db, sql_own_identities_retrieve, -1, &tmp_own_id_retrieve, NULL); + + // Kludgey - put the stmt in temporarily, and then remove again, so less code dup. + // FIXME LATER: refactor if possible, but... chicken and egg, and thiis case rarely happens. + session->own_identities_retrieve = tmp_own_id_retrieve; + status = own_identities_retrieve(session, &id_list); + sqlite3_finalize(tmp_own_id_retrieve); + session->own_identities_retrieve = NULL; + + if (!status || !id_list) + return PEP_STATUS_OK; // it's empty AFAIK (FIXME) + + identity_list* curr_own = id_list; + + sqlite3_stmt* update_revoked_w_addr_stmt = NULL; + const char* sql_query = "update revocation_contact_list set own_address = ?1 where fpr = ?2;"; + sqlite3_prepare_v2(session->db, sql_query, -1, &update_revoked_w_addr_stmt, NULL); + + // Ok, go through and find any keys associated with this address + for ( ; curr_own && curr_own->ident; curr_own = curr_own->next) { + if (EMPTYSTR(curr_own->ident->address)) // shouldn't happen + continue; + stringlist_t* keylist = NULL; + status = find_keys(session, curr_own->ident->address, &keylist); + stringlist_t* curr_key = keylist; + for ( ; curr_key && curr_key->value; curr_key = curr_key->next) { + if (EMPTYSTR(curr_key->value)) + continue; + + // We just do this lazily - if this isn't a revoked key, it + // won't do anything. + sqlite3_bind_text(update_revoked_w_addr_stmt, 1, curr_own->ident->address, -1, + SQLITE_STATIC); + sqlite3_bind_text(update_revoked_w_addr_stmt, 2, curr_key->value, -1, + SQLITE_STATIC); + + int_result = sqlite3_step(update_revoked_w_addr_stmt); + assert(int_result == SQLITE_DONE); + + sqlite3_reset(update_revoked_w_addr_stmt); + + if (int_result != SQLITE_DONE) + return PEP_UNKNOWN_DB_ERROR; + + } + } + sqlite3_finalize(update_revoked_w_addr_stmt); + + int_result = sqlite3_exec( + session->db, + "delete from revocation_contact_list where own_address is NULL;\n" + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table if not exists _revocation_contact_list_new (\n" + " fpr text not null references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " own_address text,\n" + " contact_id text not null references person (id)\n" + " on delete cascade on update cascade,\n" + " timestamp integer default (datetime('now')),\n" + " PRIMARY KEY(fpr, own_address, contact_id)\n" + ");\n" + "INSERT INTO _revocation_contact_list_new (fpr, " + " own_address, " + " contact_id) " + " SELECT revocation_contact_list.fpr, " + " revocation_contact_list.own_address, " + " revocation_contact_list.contact_id " + " FROM revocation_contact_list " + " WHERE 1;\n" + "DROP TABLE revocation_contact_list;\n" + "ALTER TABLE _revocation_contact_list_new RENAME TO revocation_contact_list;\n" + "COMMIT;\n" + "\n" + "PRAGMA foreign_keys=on;\n" + , + NULL, + NULL, + NULL + ); + + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return status; +} + + +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] *_version void + * @param[in] count int + * @param[in] **text char + * @param[in] **name char + * + */ +static int user_version(void *_version, int count, char **text, char **name) +{ + if (!(_version && count == 1 && text && text[0])) + return -1; + + int *version = (int *) _version; + *version = atoi(text[0]); + return 0; +} + +PEP_STATUS init_databases(PEP_SESSION session) { + assert(LOCAL_DB); + if (LOCAL_DB == NULL) + return PEP_INIT_CANNOT_OPEN_DB; + +#ifdef _PEP_SQLITE_DEBUG + sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, NULL); +#endif + + int int_result = sqlite3_open_v2( + LOCAL_DB, + &session->db, + SQLITE_OPEN_READWRITE + | SQLITE_OPEN_CREATE + | SQLITE_OPEN_FULLMUTEX + | SQLITE_OPEN_PRIVATECACHE, + NULL + ); + + if (int_result != SQLITE_OK) + return PEP_INIT_CANNOT_OPEN_DB; + + int_result = sqlite3_exec( + session->db, + "PRAGMA locking_mode=NORMAL;\n" + "PRAGMA journal_mode=WAL;\n", + NULL, + NULL, + NULL + ); + + sqlite3_busy_timeout(session->db, BUSY_WAIT_TIME); + +#ifdef _PEP_SQLITE_DEBUG + sqlite3_trace_v2(session->db, + SQLITE_TRACE_STMT | SQLITE_TRACE_ROW | SQLITE_TRACE_CLOSE, + sql_trace_callback, + NULL); +#endif + + assert(SYSTEM_DB); + if (SYSTEM_DB == NULL) + return PEP_INIT_CANNOT_OPEN_SYSTEM_DB; + + int_result = sqlite3_open_v2( + SYSTEM_DB, &session->system_db, + SQLITE_OPEN_READONLY + | SQLITE_OPEN_FULLMUTEX + | SQLITE_OPEN_SHAREDCACHE, + NULL + ); + + if (int_result != SQLITE_OK) + return PEP_INIT_CANNOT_OPEN_SYSTEM_DB; + + sqlite3_busy_timeout(session->system_db, 1000); + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_initial_tables(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "create table if not exists version_info (\n" + " id integer primary key,\n" + " timestamp integer default (datetime('now')),\n" + " version text,\n" + " comment text\n" + ");\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + // This string is now too large for the C standard, so we're going to break it up some. + // I presume we use the enormous string for performance purposes... terrible for debugging purposes, but OK. + int_result = sqlite3_exec( + session->db, + "PRAGMA application_id = 0x23423423;\n" + "create table if not exists log (\n" + " timestamp integer default (datetime('now')),\n" + " title text not null,\n" + " description text,\n" + " entity text not null,\n" + " comment text\n" + ");\n" + "create index if not exists log_timestamp on log (\n" + " timestamp\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_core_tables(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "create table if not exists pgp_keypair (\n" + " fpr text primary key,\n" + " created integer,\n" + " expires integer,\n" + " comment text,\n" + " flags integer default 0,\n" + " manually_set integer default 0\n" + ");\n" + "create index if not exists pgp_keypair_expires on pgp_keypair (\n" + " expires\n" + ");\n" + "create table if not exists person (\n" + " id text primary key,\n" + " username text not null,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " lang text,\n" + " comment text,\n" + // " device_group text,\n" + " is_pEp_user integer default 0\n" + ");\n" + "create table if not exists identity (\n" + " address text,\n" + " user_id text\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " comment text,\n" + " flags integer default 0,\n" + " is_own integer default 0,\n" + " pEp_version_major integer default 0,\n" + " pEp_version_minor integer default 0,\n" + " enc_format integer default 0,\n" + " timestamp integer default (datetime('now')),\n" + " primary key (address, user_id)\n" + ");\n" + "create index if not exists identity_userid_addr on identity(address, user_id);\n" + "create table if not exists trust (\n" + " user_id text not null\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " pgp_keypair_fpr text not null\n" + " references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " comm_type integer not null,\n" + " comment text,\n" + " primary key (user_id, pgp_keypair_fpr)\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_group_tables(PEP_SESSION session) { + if (!session) + return PEP_ILLEGAL_VALUE; + + int int_result = sqlite3_exec( + session->db, + // group information + "create table if not exists groups (\n" + " group_id text,\n" + " group_address text,\n" + " manager_userid text,\n" + " manager_address text,\n" + " active integer default 0,\n" + " constraint groups_pk\n" + " primary key (group_address, group_id),\n" + " constraint group_identity_fk\n" + " foreign key (group_address, group_id) references identity\n" + " on update cascade on delete cascade,\n" + " constraint manager_identity_fk\n" + " foreign key (manager_address, manager_userid) references identity\n" + " on update cascade on delete cascade\n" + ");\n" + "create table if not exists own_memberships (\n" + " group_id text,\n" + " group_address text,\n" + " own_id text,\n" + " own_address text,\n" + " have_joined int default 0,\n" + " constraint own_memberships_pk\n" + " primary key (group_address, group_id),\n" + " constraint own_memberships_own_id_fk\n" + " foreign key (own_address, own_id) references identity\n" + " on update cascade on delete cascade,\n" + " constraint own_memberships_group_fk\n" + " foreign key (group_address, group_id) references groups\n" + " on update cascade on delete cascade\n" + ");\n" + "create table if not exists own_groups_members (\n" + " group_id text,\n" + " group_address text,\n" + " member_id text,\n" + " member_address text,\n" + " active_member int default 0,\n" + " constraint own_groups_members_pk\n" + " primary key (group_address, group_id, member_address, member_id),\n" + " constraint group_ident_fk\n" + " foreign key (group_address, group_id) references groups\n" + " on update cascade on delete cascade,\n" + " constraint member_ident_fk\n" + " foreign key (member_address, member_id) references identity\n" + " on update cascade on delete cascade\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_supplementary_key_tables(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + // blacklist + "create table if not exists blacklist_keys (\n" + " fpr text primary key\n" + ");\n" + "create table if not exists revoked_keys (\n" + " revoked_fpr text primary key,\n" + " replacement_fpr text not null\n" + " references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " revocation_date integer\n" + ");\n" + // mistrusted keys + "create table if not exists mistrusted_keys (\n" + " fpr text primary key\n" + ");\n" + // social graph for key resets + "create table if not exists social_graph (\n" + " own_userid text,\n" + " own_address text,\n" + " contact_userid text,\n" + " CONSTRAINT fk_own_identity\n" + " FOREIGN KEY(own_address, own_userid)\n" + " REFERENCES identity(address, user_id)\n" + " ON DELETE CASCADE ON UPDATE CASCADE\n" + ");\n" + // list of user_ids sent revocation + "create table if not exists revocation_contact_list (\n" + " fpr text not null references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " own_address text,\n" + " contact_id text not null references person (id)\n" + " on delete cascade on update cascade,\n" + " timestamp integer default (datetime('now')),\n" + " PRIMARY KEY(fpr, own_address, contact_id)\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _create_misc_admin_tables(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + // sequences + "create table if not exists sequences(\n" + " name text primary key,\n" + " value integer default 0\n" + ");\n" + // user id aliases + "create table if not exists alternate_user_id (\n" + " default_id text references person (id)\n" + " on delete cascade on update cascade,\n" + " alternate_id text primary key\n" + ");\n" + , + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + + +// The create tables string is now too large for the C standard, so we're going to break it up some. +// I presume we use the enormous string for performance purposes... terrible for debugging purposes, but OK. +PEP_STATUS create_tables(PEP_SESSION session) { + + if (!session) + return PEP_ILLEGAL_VALUE; + + PEP_STATUS status = PEP_STATUS_OK; + + status = _create_initial_tables(session); + if (status != PEP_STATUS_OK) + return status; + + status = _create_core_tables(session); + if (status != PEP_STATUS_OK) + return status; + + status = _create_group_tables(session); + if (status != PEP_STATUS_OK) + return status; + + status = _create_supplementary_key_tables(session); + if (status != PEP_STATUS_OK) + return status; + + status = _create_misc_admin_tables(session); + + return status; +} + +PEP_STATUS get_db_user_version(PEP_SESSION session, int* version) { + int int_result = sqlite3_exec( + session->db, + "pragma user_version;", + user_version, + version, + NULL + ); + + assert(int_result == SQLITE_OK); + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _verify_version(PEP_SESSION session, int* version) { + // Sometimes the user_version wasn't set correctly. + bool version_changed = true; + int int_result; + if (table_contains_column(session, "pgp_keypair", "manually_set")) { + *version = 16; + } + else if (table_contains_column(session, "groups", "group_identity")) { + *version = 15; + } + else if (table_contains_column(session, "identity", "enc_format")) { + *version = 14; + } else if (table_contains_column(session, "revocation_contact_list", "own_address")) { + *version = 13; + } else if (table_contains_column(session, "identity", "pEp_version_major")) { + *version = 12; + } else if (db_contains_table(session, "social_graph") > 0) { + if (!table_contains_column(session, "person", "device_group")) + *version = 10; + else + *version = 9; + } else if (table_contains_column(session, "identity", "timestamp") > 0) { + *version = 8; + } else if (table_contains_column(session, "person", "is_pEp_user") > 0) { + *version = 7; + } else if (table_contains_column(session, "identity", "is_own") > 0) { + *version = 6; + } else if (table_contains_column(session, "pgp_keypair", "flags") > 0) { + *version = 2; + } else { + version_changed = false; + } + + if (version_changed) { + // set it in the DB, finally. Yeesh. + char verbuf[21]; // enough digits for a max-sized 64 bit int, cmon. + sprintf(verbuf, "%d", *version); + + size_t query_size = strlen(verbuf) + 25; + char *query = calloc(query_size, 1); + + strlcpy(query, "pragma user_version = ", query_size); + strlcat(query, verbuf, query_size); + strlcat(query, ";", query_size); + + int_result = sqlite3_exec( + session->db, + query, + user_version, + &*version, + NULL + ); + free(query); + } + + // FIXME: status + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_2(PEP_SESSION session) { + // N.B. addition of device_group column removed in DDL v10 + int int_result = sqlite3_exec( + session->db, + "alter table pgp_keypair\n" + " add column flags integer default 0;\n", + // "alter table person\n" + // " add column device_group text;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_5(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "delete from pgp_keypair where fpr = '';", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_exec( + session->db, + "delete from trust where pgp_keypair_fpr = '';", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_6(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "alter table identity\n" + " add column is_own integer default 0;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_exec( + session->db, + "update identity\n" + " set is_own = 1\n" + " where (user_id = '" PEP_OWN_USERID "');\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // Turns out that just adding "on update cascade" in + // sqlite is a PITA. We need to be able to cascade + // person->id replacements (for temp ids like "TOFU_") + // so here we go... + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _identity_new (\n" + " address text,\n" + " user_id text\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " comment text,\n" + " flags integer default 0,\n" + " is_own integer default 0,\n" + " primary key (address, user_id)\n" + ");\n" + "INSERT INTO _identity_new SELECT * FROM identity;\n" + "DROP TABLE identity;\n" + "ALTER TABLE _identity_new RENAME TO identity;\n" + "COMMIT;\n" + "\n" + "BEGIN TRANSACTION;\n" + "create table _trust_new (\n" + " user_id text not null\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " pgp_keypair_fpr text not null\n" + " references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " comm_type integer not null,\n" + " comment text,\n" + " primary key (user_id, pgp_keypair_fpr)\n" + ");\n" + "INSERT INTO _trust_new SELECT * FROM trust;\n" + "DROP TABLE trust;\n" + "ALTER TABLE _trust_new RENAME TO trust;\n" + "COMMIT;\n" + "\n" + "PRAGMA foreign_keys=on;\n" + "create table if not exists alternate_user_id (\n" + " default_id text references person (id)\n" + " on delete cascade on update cascade,\n" + " alternate_id text primary key\n" + ");\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_key_check;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // FIXME: foreign key check here + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_7(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "alter table person\n" + " add column is_pEp_user integer default 0;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_exec( + session->db, + "update person\n" + " set is_pEp_user = 1\n" + " where id = " + " (select distinct id from person " + " join trust on id = user_id " + " where (case when (comm_type = 127) then (id) " + " when (comm_type = 255) then (id) " + " else 0" + " end) = id );\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "create table if not exists mistrusted_keys (\n" + " fpr text primary key\n" + ");\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_8(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _identity_new (\n" + " address text,\n" + " user_id text\n" + " references person (id)\n" + " on delete cascade on update cascade,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " comment text,\n" + " flags integer default 0,\n" + " is_own integer default 0,\n" + " timestamp integer default (datetime('now')),\n" + " primary key (address, user_id)\n" + ");\n" + "INSERT INTO _identity_new (address, user_id, main_key_id, " + " comment, flags, is_own) " + " SELECT identity.address, identity.user_id, " + " identity.main_key_id, identity.comment, " + " identity.flags, identity.is_own " + " FROM identity " + " WHERE 1;\n" + "DROP TABLE identity;\n" + "ALTER TABLE _identity_new RENAME TO identity;\n" + "COMMIT;\n" + "\n" + "PRAGMA foreign_keys=on;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_key_check;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + // FIXME: foreign key check + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + + +static PEP_STATUS _upgrade_DB_to_ver_9(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "create table if not exists social_graph (\n" + " own_userid text,\n" + " own_address text,\n" + " contact_userid text,\n" + " CONSTRAINT fk_own_identity\n" + " FOREIGN KEY(own_address, own_userid)\n" + " REFERENCES identity(address, user_id)\n" + " ON DELETE CASCADE ON UPDATE CASCADE\n" + ");\n" + "create table if not exists revocation_contact_list (\n" + " fpr text not null references pgp_keypair (fpr)\n" + " on delete cascade,\n" + " contact_id text not null references person (id)\n" + " on delete cascade on update cascade,\n" + " timestamp integer default (datetime('now')),\n" + " PRIMARY KEY(fpr, contact_id)\n" + ");\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_10(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_keys=off;\n" + "BEGIN TRANSACTION;\n" + "create table _person_new (\n" + " id text primary key,\n" + " username text not null,\n" + " main_key_id text\n" + " references pgp_keypair (fpr)\n" + " on delete set null,\n" + " lang text,\n" + " comment text,\n" + " is_pEp_user integer default 0\n" + ");\n" + "INSERT INTO _person_new (id, username, main_key_id, " + " lang, comment, is_pEp_user) " + " SELECT person.id, person.username, " + " person.main_key_id, person.lang, " + " person.comment, person.is_pEp_user " + " FROM person " + " WHERE 1;\n" + "DROP TABLE person;\n" + "ALTER TABLE _person_new RENAME TO person;\n" + "COMMIT;\n" + "\n" + "PRAGMA foreign_keys=on;\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_exec( + session->db, + "PRAGMA foreign_key_check;\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_12(PEP_SESSION session) { + PEP_STATUS status = PEP_STATUS_OK; + + int int_result = sqlite3_exec( + session->db, + "create index if not exists identity_userid_addr on identity(address, user_id);\n", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "alter table identity\n" + " add column pEp_version_major integer default 0;\n" + "alter table identity\n" + " add column pEp_version_minor integer default 0;\n", + NULL, + NULL, + NULL + ); + if (status != PEP_STATUS_OK) + return status; + + int_result = sqlite3_exec( + session->db, + "update identity\n" + " set pEp_version_major = 2\n" + " where exists (select * from person\n" + " where identity.user_id = person.id\n" + " and identity.is_own = 0\n" + " and person.is_pEp_user = 1);\n", + NULL, + NULL, + NULL + ); + if (status != PEP_STATUS_OK) + return status; + + // N.B. WE DEFINE PEP_VERSION - IF WE'RE AT 9-DIGIT MAJOR OR MINOR VERSIONS, ER, BAD. + char major_buf[10]; + char minor_buf[10]; + + // Guess we were abusing sscanf here, so we'll do it this way: + const char *cptr = PEP_VERSION; + size_t major_len = 0; + size_t minor_len = 0; + + char *bufptr = major_buf; + while (*cptr != '.' && *cptr != '\0') { + *bufptr++ = *cptr++; + major_len++; + } + *bufptr = '\0'; + bufptr = minor_buf; + + if (*cptr == '.') { + cptr++; + while (*cptr != '\0') { + *bufptr++ = *cptr++; + minor_len++; + } + } else { + *bufptr++ = '0'; + } + *bufptr = '\0'; + + const char *_ver_12_startstr = + "update identity\n" + " set pEp_version_major = "; + const char *_ver_12_midstr = ",\n" + " pEp_version_minor = "; + const char *_ver_12_endstr = + "\n" + " where identity.is_own = 1;\n"; + + size_t new_stringlen = strlen(_ver_12_startstr) + major_len + + strlen(_ver_12_midstr) + minor_len + + strlen(_ver_12_endstr); + + char *_ver_12_stmt = calloc(new_stringlen + 1, 1); + snprintf(_ver_12_stmt, new_stringlen + 1, "%s%s%s%s%s", + _ver_12_startstr, major_buf, _ver_12_midstr, minor_buf, _ver_12_endstr); + + int_result = sqlite3_exec( + session->db, + _ver_12_stmt, + NULL, + NULL, + NULL + ); + free(_ver_12_stmt); + if (status != PEP_STATUS_OK) + return status; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_14(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "alter table identity\n" + " add column enc_format integer default 0;\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_15(PEP_SESSION session) { +// int int_result = sqlite3_exec( +// session->db, +// "alter table pgp_keypair\n" +// " add column manually_set integer default 0;\n", +// NULL, +// NULL, +// NULL +// ); +// +// assert(int_result == SQLITE_OK); +// +// if (int_result != SQLITE_OK) +// return PEP_UNKNOWN_DB_ERROR; + + // FIXME! DO THIS! + return PEP_STATUS_OK; +} + +static PEP_STATUS _upgrade_DB_to_ver_16(PEP_SESSION session) { + int int_result = sqlite3_exec( + session->db, + "alter table pgp_keypair\n" + " add column manually_set integer default 0;\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + return PEP_STATUS_OK; +} + +static PEP_STATUS _check_and_execute_upgrades(PEP_SESSION session, int version) { + PEP_STATUS status = PEP_STATUS_OK; + + switch(version) { + case 1: + status = _upgrade_DB_to_ver_2(session); + if (status != PEP_STATUS_OK) + return status; + case 2: + case 3: + case 4: + status = _upgrade_DB_to_ver_5(session); + if (status != PEP_STATUS_OK) + return status; + case 5: + status = _upgrade_DB_to_ver_6(session); + if (status != PEP_STATUS_OK) + return status; + case 6: + status = _upgrade_DB_to_ver_7(session); + if (status != PEP_STATUS_OK) + return status; + case 7: + status = _upgrade_DB_to_ver_8(session); + if (status != PEP_STATUS_OK) + return status; + case 8: + status = _upgrade_DB_to_ver_9(session); + if (status != PEP_STATUS_OK) + return status; + case 9: + if (version > 1) { + status = _upgrade_DB_to_ver_10(session); + if (status != PEP_STATUS_OK) + return status; + } + case 10: + status = repair_altered_tables(session); + assert(status == PEP_STATUS_OK); + if (status != PEP_STATUS_OK) + return status; + case 11: + status = _upgrade_DB_to_ver_12(session); + if (status != PEP_STATUS_OK) + return status; + case 12: + status = upgrade_revoc_contact_to_13(session); + assert(status == PEP_STATUS_OK); + if (status != PEP_STATUS_OK) + return status; + case 13: + status = _upgrade_DB_to_ver_14(session); + if (status != PEP_STATUS_OK) + return status; + case 14: + status = _upgrade_DB_to_ver_15(session); + if (status != PEP_STATUS_OK) + return status; + case 15: + status = _upgrade_DB_to_ver_16(session); + if (status != PEP_STATUS_OK) + return status; + case 16: + break; + default: + return PEP_ILLEGAL_VALUE; + } + return PEP_STATUS_OK; +} + + +PEP_STATUS pEp_sql_init(PEP_SESSION session) { + bool very_first = false; + PEP_STATUS status = create_tables(session); + if (status != PEP_STATUS_OK) + return status; + + int version = 0; + status = get_db_user_version(session, &version); + if (status != PEP_STATUS_OK) + return status; + + void (*xFunc_lower)(sqlite3_context *, int, sqlite3_value **) = &_sql_lower; + + int int_result = sqlite3_create_function_v2( + session->db, + "lower", + 1, + SQLITE_UTF8 | SQLITE_DETERMINISTIC, + NULL, + xFunc_lower, + NULL, + NULL, + NULL); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_exec( + session->db, + "pragma foreign_keys=ON;\n", + NULL, + NULL, + NULL + ); + + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + if (version > atoi(_DDL_USER_VERSION)) { + // This is *explicitly* not allowed. + return PEP_INIT_DB_DOWNGRADE_VIOLATION; + } + + if (version == 1) { + // Sometimes the user_version wasn't set correctly. + status = _verify_version(session, &version); + if (status != PEP_STATUS_OK) + return PEP_ILLEGAL_VALUE; + } + + + if (version != 0) { + // Version has been already set + + // Early mistake : version 0 shouldn't have existed. + // Numbering should have started at 1 to detect newly created DB. + // Version 0 DBs are not anymore compatible. + status = _check_and_execute_upgrades(session, version); + if (status != PEP_STATUS_OK) + return PEP_ILLEGAL_VALUE; + } else { + // Version from DB was 0, it means this is initial setup. + // DB has just been created, and all tables are empty. + very_first = true; + } + + if (version < atoi(_DDL_USER_VERSION)) { + int_result = sqlite3_exec( + session->db, + "pragma user_version = "_DDL_USER_VERSION";\n" + "insert or replace into version_info (id, version)" + "values (1, '" PEP_ENGINE_VERSION "');", + NULL, + NULL, + NULL + ); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + } + return PEP_STATUS_OK; +} + + +// This whole mess really does need to be generated somewhere. +PEP_STATUS pEp_prepare_sql_stmts(PEP_SESSION session) { + + int int_result = sqlite3_prepare_v2(session->system_db, sql_trustword, + (int)strlen(sql_trustword), &session->trustword, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_get_identity, + (int)strlen(sql_get_identity), &session->get_identity, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_get_identity_without_trust_check, + (int)strlen(sql_get_identity_without_trust_check), + &session->get_identity_without_trust_check, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_identities_by_address, + (int)strlen(sql_get_identities_by_address), + &session->get_identities_by_address, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_identities_by_userid, + (int)strlen(sql_get_identities_by_userid), + &session->get_identities_by_userid, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_identities_by_main_key_id, + (int)strlen(sql_get_identities_by_main_key_id), + &session->get_identities_by_main_key_id, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_user_default_key, + (int)strlen(sql_get_user_default_key), &session->get_user_default_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_all_keys_for_user, + (int)strlen(sql_get_all_keys_for_user), &session->get_all_keys_for_user, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_default_own_userid, + (int)strlen(sql_get_default_own_userid), &session->get_default_own_userid, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_userid_alias_default, + (int)strlen(sql_get_userid_alias_default), &session->get_userid_alias_default, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_add_userid_alias, + (int)strlen(sql_add_userid_alias), &session->add_userid_alias, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_replace_userid, + (int)strlen(sql_replace_userid), &session->replace_userid, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_delete_key, + (int)strlen(sql_delete_key), &session->delete_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_replace_main_user_fpr, + (int)strlen(sql_replace_main_user_fpr), &session->replace_main_user_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_replace_main_user_fpr_if_equal, + (int)strlen(sql_replace_main_user_fpr_if_equal), &session->replace_main_user_fpr_if_equal, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_main_user_fpr, + (int)strlen(sql_get_main_user_fpr), &session->get_main_user_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_refresh_userid_default_key, + (int)strlen(sql_refresh_userid_default_key), &session->refresh_userid_default_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_replace_identities_fpr, + (int)strlen(sql_replace_identities_fpr), + &session->replace_identities_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_remove_fpr_as_identity_default, + (int)strlen(sql_remove_fpr_as_identity_default), + &session->remove_fpr_as_identity_default, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_remove_fpr_as_user_default, + (int)strlen(sql_remove_fpr_as_user_default), + &session->remove_fpr_as_user_default, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_person, + (int)strlen(sql_set_person), &session->set_person, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_person, + (int)strlen(sql_update_person), &session->update_person, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_delete_person, + (int)strlen(sql_delete_person), &session->delete_person, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_exists_person, + (int)strlen(sql_exists_person), &session->exists_person, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_as_pEp_user, + (int)strlen(sql_set_as_pEp_user), &session->set_as_pEp_user, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_is_pEp_user, + (int)strlen(sql_is_pEp_user), &session->is_pEp_user, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_add_into_social_graph, + (int)strlen(sql_add_into_social_graph), &session->add_into_social_graph, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_get_own_address_binding_from_contact, + (int)strlen(sql_get_own_address_binding_from_contact), + &session->get_own_address_binding_from_contact, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_set_revoke_contact_as_notified, + (int)strlen(sql_set_revoke_contact_as_notified), + &session->set_revoke_contact_as_notified, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_get_contacted_ids_from_revoke_fpr, + (int)strlen(sql_get_contacted_ids_from_revoke_fpr), + &session->get_contacted_ids_from_revoke_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_was_id_for_revoke_contacted, + (int)strlen(sql_was_id_for_revoke_contacted), + &session->was_id_for_revoke_contacted, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_has_id_contacted_address, + (int)strlen(sql_has_id_contacted_address), + &session->has_id_contacted_address, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_get_last_contacted, + (int)strlen(sql_get_last_contacted), + &session->get_last_contacted, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, + sql_get_own_address_binding_from_contact, + (int)strlen(sql_get_own_address_binding_from_contact), + &session->get_own_address_binding_from_contact, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_pgp_keypair, + (int)strlen(sql_set_pgp_keypair), &session->set_pgp_keypair, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_identity_entry, + (int)strlen(sql_set_identity_entry), &session->set_identity_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_identity_entry, + (int)strlen(sql_update_identity_entry), &session->update_identity_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_exists_identity_entry, + (int)strlen(sql_exists_identity_entry), &session->exists_identity_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_identity_flags, + (int)strlen(sql_set_identity_flags), &session->set_identity_flags, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_unset_identity_flags, + (int)strlen(sql_unset_identity_flags), &session->unset_identity_flags, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_ident_enc_format, + (int)strlen(sql_set_ident_enc_format), &session->set_ident_enc_format, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_pEp_version, + (int)strlen(sql_set_pEp_version), &session->set_pEp_version, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_upgrade_pEp_version_by_user_id, + (int)strlen(sql_upgrade_pEp_version_by_user_id), &session->upgrade_pEp_version_by_user_id, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_clear_trust_info, + (int)strlen(sql_clear_trust_info), &session->clear_trust_info, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_trust, + (int)strlen(sql_set_trust), &session->set_trust, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_trust, + (int)strlen(sql_update_trust), &session->update_trust, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_trust_to_pEp, + (int)strlen(sql_update_trust_to_pEp), &session->update_trust_to_pEp, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_exists_trust_entry, + (int)strlen(sql_exists_trust_entry), &session->exists_trust_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_update_trust_for_fpr, + (int)strlen(sql_update_trust_for_fpr), &session->update_trust_for_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_trust, + (int)strlen(sql_get_trust), &session->get_trust, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_trust_by_userid, + (int)strlen(sql_get_trust_by_userid), &session->get_trust_by_userid, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_least_trust, + (int)strlen(sql_least_trust), &session->least_trust, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_mark_as_compromised, + (int)strlen(sql_mark_as_compromised), &session->mark_compromised, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_crashdump, + (int)strlen(sql_crashdump), &session->crashdump, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->system_db, sql_languagelist, + (int)strlen(sql_languagelist), &session->languagelist, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->system_db, sql_i18n_token, + (int)strlen(sql_i18n_token), &session->i18n_token, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // blacklist + + int_result = sqlite3_prepare_v2(session->db, sql_blacklist_add, + (int)strlen(sql_blacklist_add), &session->blacklist_add, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_blacklist_delete, + (int)strlen(sql_blacklist_delete), &session->blacklist_delete, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_blacklist_is_listed, + (int)strlen(sql_blacklist_is_listed), + &session->blacklist_is_listed, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_blacklist_retrieve, + (int)strlen(sql_blacklist_retrieve), &session->blacklist_retrieve, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // Own keys + + int_result = sqlite3_prepare_v2(session->db, sql_own_key_is_listed, + (int)strlen(sql_own_key_is_listed), &session->own_key_is_listed, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_is_own_address, + (int)strlen(sql_is_own_address), &session->is_own_address, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_own_identities_retrieve, + (int)strlen(sql_own_identities_retrieve), + &session->own_identities_retrieve, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_own_keys_retrieve, + (int)strlen(sql_own_keys_retrieve), + &session->own_keys_retrieve, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // int_result = sqlite3_prepare_v2(session->db, sql_set_own_key, + // (int)strlen(sql_set_own_key), + // &session->set_own_key, NULL); + // assert(int_result == SQLITE_OK); + + + // Sequence + + int_result = sqlite3_prepare_v2(session->db, sql_sequence_value1, + (int)strlen(sql_sequence_value1), &session->sequence_value1, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_sequence_value2, + (int)strlen(sql_sequence_value2), &session->sequence_value2, + NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + // Revocation tracking + + int_result = sqlite3_prepare_v2(session->db, sql_set_revoked, + (int)strlen(sql_set_revoked), &session->set_revoked, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_revoked, + (int)strlen(sql_get_revoked), &session->get_revoked, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_replacement_fpr, + (int)strlen(sql_get_replacement_fpr), &session->get_replacement_fpr, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_add_mistrusted_key, + (int)strlen(sql_add_mistrusted_key), &session->add_mistrusted_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_delete_mistrusted_key, + (int)strlen(sql_delete_mistrusted_key), &session->delete_mistrusted_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_is_mistrusted_key, + (int)strlen(sql_is_mistrusted_key), &session->is_mistrusted_key, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + /* Groups */ + int_result = sqlite3_prepare_v2(session->db, sql_create_group, + (int)strlen(sql_create_group), &session->create_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_enable_group, + (int)strlen(sql_enable_group), &session->enable_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_disable_group, + (int)strlen(sql_disable_group), &session->disable_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_exists_group_entry, + (int)strlen(sql_exists_group_entry), &session->exists_group_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_group_add_member, + (int)strlen(sql_group_add_member), &session->group_add_member, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_set_group_member_status, + (int)strlen(sql_set_group_member_status), &session->set_group_member_status, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_join_group, + (int)strlen(sql_join_group), &session->join_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_leave_group, + (int)strlen(sql_leave_group), &session->leave_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_all_members, + (int)strlen(sql_get_all_members), &session->get_all_members, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + + int_result = sqlite3_prepare_v2(session->db, sql_get_active_members, + (int)strlen(sql_get_active_members), &session->get_active_members, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_all_groups, + (int)strlen(sql_get_all_groups), &session->get_all_groups, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_get_active_groups, + (int)strlen(sql_get_active_groups), &session->get_active_groups, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_add_own_membership_entry, + (int)strlen(sql_add_own_membership_entry), &session->add_own_membership_entry, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_get_own_membership_status, + (int)strlen(sql_get_own_membership_status), &session->get_own_membership_status, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_retrieve_own_membership_info_for_group_and_ident, + (int)strlen(sql_retrieve_own_membership_info_for_group_and_ident), &session->retrieve_own_membership_info_for_group_and_ident, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_retrieve_own_membership_info_for_group, + (int)strlen(sql_retrieve_own_membership_info_for_group), &session->retrieve_own_membership_info_for_group, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_get_group_manager, + (int)strlen(sql_get_group_manager), &session->get_group_manager, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_is_invited_group_member, + (int)strlen(sql_is_invited_group_member), &session->is_invited_group_member, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + + int_result = sqlite3_prepare_v2(session->db, sql_is_group_active, + (int)strlen(sql_is_group_active), &session->is_group_active, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + +// int_result = sqlite3_prepare_v2(session->db, sql_group_invite_exists, +// (int)strlen(sql_group_invite_exists), &session->group_invite_exists, NULL); +// assert(int_result == SQLITE_OK); +// +// if (int_result != SQLITE_OK) +// return PEP_UNKNOWN_DB_ERROR; + + int_result = sqlite3_prepare_v2(session->db, sql_log, + (int)strlen(sql_log), &session->log, NULL); + assert(int_result == SQLITE_OK); + + if (int_result != SQLITE_OK) + return PEP_UNKNOWN_DB_ERROR; + + /* End groups */ + return PEP_STATUS_OK; +} + +PEP_STATUS pEp_finalize_sql_stmts(PEP_SESSION session) { + if (session->log) + sqlite3_finalize(session->log); + if (session->trustword) + sqlite3_finalize(session->trustword); + if (session->get_identity) + sqlite3_finalize(session->get_identity); + if (session->get_identity_without_trust_check) + sqlite3_finalize(session->get_identity_without_trust_check); + if (session->get_identities_by_address) + sqlite3_finalize(session->get_identities_by_address); + if (session->get_identities_by_userid) + sqlite3_finalize(session->get_identities_by_userid); + if (session->get_identities_by_main_key_id) + sqlite3_finalize(session->get_identities_by_main_key_id); + if (session->get_user_default_key) + sqlite3_finalize(session->get_user_default_key); + if (session->get_all_keys_for_user) + sqlite3_finalize(session->get_all_keys_for_user); + if (session->get_default_own_userid) + sqlite3_finalize(session->get_default_own_userid); + if (session->get_userid_alias_default) + sqlite3_finalize(session->get_userid_alias_default); + if (session->add_userid_alias) + sqlite3_finalize(session->add_userid_alias); + if (session->replace_identities_fpr) + sqlite3_finalize(session->replace_identities_fpr); + if (session->remove_fpr_as_identity_default) + sqlite3_finalize(session->remove_fpr_as_identity_default); + if (session->remove_fpr_as_user_default) + sqlite3_finalize(session->remove_fpr_as_user_default); + if (session->set_person) + sqlite3_finalize(session->set_person); + if (session->delete_person) + sqlite3_finalize(session->delete_person); + if (session->set_as_pEp_user) + sqlite3_finalize(session->set_as_pEp_user); + if (session->upgrade_pEp_version_by_user_id) + sqlite3_finalize(session->upgrade_pEp_version_by_user_id); + if (session->is_pEp_user) + sqlite3_finalize(session->is_pEp_user); + if (session->exists_person) + sqlite3_finalize(session->exists_person); + if (session->add_into_social_graph) + sqlite3_finalize(session->add_into_social_graph); + if (session->get_own_address_binding_from_contact) + sqlite3_finalize(session->get_own_address_binding_from_contact); + if (session->set_revoke_contact_as_notified) + sqlite3_finalize(session->set_revoke_contact_as_notified); + if (session->get_contacted_ids_from_revoke_fpr) + sqlite3_finalize(session->get_contacted_ids_from_revoke_fpr); + if (session->was_id_for_revoke_contacted) + sqlite3_finalize(session->was_id_for_revoke_contacted); + if (session->has_id_contacted_address) + sqlite3_finalize(session->has_id_contacted_address); + if (session->get_last_contacted) + sqlite3_finalize(session->get_last_contacted); + if (session->set_pgp_keypair) + sqlite3_finalize(session->set_pgp_keypair); + if (session->exists_identity_entry) + sqlite3_finalize(session->exists_identity_entry); + if (session->set_identity_entry) + sqlite3_finalize(session->set_identity_entry); + if (session->update_identity_entry) + sqlite3_finalize(session->update_identity_entry); + if (session->set_identity_flags) + sqlite3_finalize(session->set_identity_flags); + if (session->unset_identity_flags) + sqlite3_finalize(session->unset_identity_flags); + if (session->set_ident_enc_format) + sqlite3_finalize(session->set_ident_enc_format); + if (session->set_pEp_version) + sqlite3_finalize(session->set_pEp_version); + if (session->exists_trust_entry) + sqlite3_finalize(session->exists_trust_entry); + if (session->clear_trust_info) + sqlite3_finalize(session->clear_trust_info); + if (session->set_trust) + sqlite3_finalize(session->set_trust); + if (session->update_trust) + sqlite3_finalize(session->update_trust); + if (session->update_trust_to_pEp) + sqlite3_finalize(session->update_trust_to_pEp); + if (session->update_trust_for_fpr) + sqlite3_finalize(session->update_trust_for_fpr); + if (session->get_trust) + sqlite3_finalize(session->get_trust); + if (session->get_trust_by_userid) + sqlite3_finalize(session->get_trust_by_userid); + if (session->least_trust) + sqlite3_finalize(session->least_trust); + if (session->mark_compromised) + sqlite3_finalize(session->mark_compromised); + if (session->crashdump) + sqlite3_finalize(session->crashdump); + if (session->languagelist) + sqlite3_finalize(session->languagelist); + if (session->i18n_token) + sqlite3_finalize(session->i18n_token); + if (session->replace_userid) + sqlite3_finalize(session->replace_userid); + if (session->delete_key) + sqlite3_finalize(session->delete_key); + if (session->replace_main_user_fpr) + sqlite3_finalize(session->replace_main_user_fpr); + if (session->replace_main_user_fpr_if_equal) + sqlite3_finalize(session->replace_main_user_fpr_if_equal); + if (session->get_main_user_fpr) + sqlite3_finalize(session->get_main_user_fpr); + if (session->refresh_userid_default_key) + sqlite3_finalize(session->refresh_userid_default_key); + if (session->blacklist_add) + sqlite3_finalize(session->blacklist_add); + if (session->blacklist_delete) + sqlite3_finalize(session->blacklist_delete); + if (session->blacklist_is_listed) + sqlite3_finalize(session->blacklist_is_listed); + if (session->blacklist_retrieve) + sqlite3_finalize(session->blacklist_retrieve); + if (session->own_key_is_listed) + sqlite3_finalize(session->own_key_is_listed); + if (session->is_own_address) + sqlite3_finalize(session->is_own_address); + if (session->own_identities_retrieve) + sqlite3_finalize(session->own_identities_retrieve); + if (session->own_keys_retrieve) + sqlite3_finalize(session->own_keys_retrieve); + // if (session->set_own_key) + // sqlite3_finalize(session->set_own_key); + if (session->sequence_value1) + sqlite3_finalize(session->sequence_value1); + if (session->sequence_value2) + sqlite3_finalize(session->sequence_value2); + if (session->set_revoked) + sqlite3_finalize(session->set_revoked); + if (session->get_revoked) + sqlite3_finalize(session->get_revoked); + if (session->get_replacement_fpr) + sqlite3_finalize(session->get_replacement_fpr); + if (session->add_mistrusted_key) + sqlite3_finalize(session->add_mistrusted_key); + if (session->delete_mistrusted_key) + sqlite3_finalize(session->delete_mistrusted_key); + if (session->is_mistrusted_key) + sqlite3_finalize(session->is_mistrusted_key); + if (session->create_group) + sqlite3_finalize(session->create_group); + if (session->enable_group) + sqlite3_finalize(session->enable_group); + if (session->disable_group) + sqlite3_finalize(session->disable_group); + if (session->exists_group_entry) + sqlite3_finalize(session->exists_group_entry); + if (session->group_add_member) + sqlite3_finalize(session->group_add_member); + if (session->set_group_member_status) + sqlite3_finalize(session->set_group_member_status); + if (session->join_group) + sqlite3_finalize(session->join_group); + if (session->leave_group) + sqlite3_finalize(session->leave_group); + if (session->get_all_members) + sqlite3_finalize(session->get_all_members); + if (session->get_active_members) + sqlite3_finalize(session->get_active_members); + if (session->get_active_groups) + sqlite3_finalize(session->get_active_groups); + if (session->get_all_groups) + sqlite3_finalize(session->get_all_groups); + if (session->add_own_membership_entry) + sqlite3_finalize(session->add_own_membership_entry); + if (session->get_own_membership_status) + sqlite3_finalize(session->get_own_membership_status); + if (session->retrieve_own_membership_info_for_group_and_ident) + sqlite3_finalize(session->retrieve_own_membership_info_for_group_and_ident); + if (session->retrieve_own_membership_info_for_group) + sqlite3_finalize(session->retrieve_own_membership_info_for_group); + if (session->get_group_manager) + sqlite3_finalize(session->get_group_manager); + if (session->is_invited_group_member) + sqlite3_finalize(session->is_invited_group_member); + if (session->is_group_active) + sqlite3_finalize(session->is_group_active); + // retrieve_own_membership_info_for_group_and_ident + // if (session->group_invite_exists) +// sqlite3_finalize(session->group_invite_exists); + return PEP_STATUS_OK; +} diff --git a/src/engine_sql.h b/src/engine_sql.h new file mode 100644 index 000000000..2ca72e042 --- /dev/null +++ b/src/engine_sql.h @@ -0,0 +1,560 @@ +#pragma once + +#include "pEp_internal.h" + +// increment this when patching DDL +#define _DDL_USER_VERSION "16" + +PEP_STATUS init_databases(PEP_SESSION session); +PEP_STATUS pEp_sql_init(PEP_SESSION session); +PEP_STATUS pEp_prepare_sql_stmts(PEP_SESSION session); +PEP_STATUS pEp_finalize_sql_stmts(PEP_SESSION session); + +/** + * Strings to feed into prepared statements + */ +static const char *sql_log = + "insert into log (title, entity, description, comment)" + "values (?1, ?2, ?3, ?4);"; + +static const char *sql_trustword = + "select id, word from wordlist where lang = lower(?1) " + "and id = ?2 ;"; + +// FIXME?: problems if we don't have a key for the user - we get nothing +static const char *sql_get_identity = + "select identity.main_key_id, username, comm_type, lang," + " identity.flags | pgp_keypair.flags," + " is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " left join pgp_keypair on fpr = identity.main_key_id" + " left join trust on id = trust.user_id" + " and pgp_keypair_fpr = identity.main_key_id" + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1" + " and identity.user_id = ?2" + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_get_identities_by_main_key_id = + "select address, identity.user_id, username, comm_type, lang," + " identity.flags | pgp_keypair.flags," + " is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " left join pgp_keypair on fpr = identity.main_key_id" + " left join trust on id = trust.user_id" + " and pgp_keypair_fpr = identity.main_key_id" + " where identity.main_key_id = ?1" + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_get_identity_without_trust_check = + "select identity.main_key_id, username, lang," + " identity.flags, is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1" + " and identity.user_id = ?2 " + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_get_identities_by_address = + "select user_id, identity.main_key_id, username, lang," + " identity.flags, is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1 " + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_get_identities_by_userid = + "select address, identity.main_key_id, username, comm_type, lang," + " identity.flags | pgp_keypair.flags," + " is_own, pEp_version_major, pEp_version_minor, enc_format" + " from identity" + " join person on id = identity.user_id" + " left join pgp_keypair on fpr = identity.main_key_id" + " left join trust on id = trust.user_id" + " and pgp_keypair_fpr = identity.main_key_id" + " where identity.user_id = ?1" + " order by is_own desc, " + " timestamp desc; "; + +static const char *sql_replace_identities_fpr = + "update identity" + " set main_key_id = ?1 " + " where main_key_id = ?2 ;"; + +static const char *sql_remove_fpr_as_identity_default = + "update identity set main_key_id = NULL where main_key_id = ?1 ;"; + +static const char *sql_remove_fpr_as_user_default = + "update person set main_key_id = NULL where main_key_id = ?1 ;"; + +// Set person, but if already exist, only update. +// if main_key_id already set, don't touch. +static const char *sql_set_person = + "insert into person (id, username, lang, main_key_id)" + " values (?1, ?2, ?3, ?4) ;"; + +static const char *sql_update_person = + "update person " + " set username = ?2, " + " lang = ?3, " + " main_key_id = " + " (select coalesce( " + " (select main_key_id from person where id = ?1), " + " upper(replace(?4,' ',''))))" + " where id = ?1 ;"; + +// Will cascade. +static const char *sql_delete_person = + "delete from person where id = ?1 ;"; + +static const char *sql_set_as_pEp_user = + "update person set is_pEp_user = 1 " + " where id = ?1 ; "; + +static const char *sql_is_pEp_user = + "select is_pEp_user from person " + " where id = ?1 ; "; + +static const char* sql_exists_person = + "select count(*) from person " + " where id = ?1 ;"; + +// This will cascade to identity and trust +static const char* sql_replace_userid = + "update person set id = ?1 " + " where id = ?2;"; + +// Hopefully this cascades and removes trust entries... +static const char *sql_delete_key = + "delete from pgp_keypair " + " where fpr = ?1 ; "; + +static const char *sql_replace_main_user_fpr = + "update person " + " set main_key_id = ?1 " + " where id = ?2 ;"; + +static const char *sql_get_main_user_fpr = + "select main_key_id from person" + " where id = ?1 ;"; + +static const char *sql_replace_main_user_fpr_if_equal = + "update person " + " set main_key_id = ?1 " + " where id = ?2 and main_key_id = ?3;"; + +static const char *sql_refresh_userid_default_key = + "update person " + " set main_key_id = " + " (select identity.main_key_id from identity " + " join trust on trust.user_id = identity.user_id " + " and trust.pgp_keypair_fpr = identity.main_key_id " + " join person on person.id = identity.user_id " + " where identity.user_id = ?1 " + " order by trust.comm_type desc " + " limit 1) " + "where id = ?1 ; "; + +static const char *sql_set_pgp_keypair = + "insert or ignore into pgp_keypair (fpr) " + "values (upper(replace(?1,' ',''))) ;"; + + + +static const char* sql_exists_identity_entry = + "select count(*) from identity " + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1" + " and user_id = ?2;"; + +static const char *sql_set_identity_entry = + "insert into identity (" + " address, main_key_id, " + " user_id, flags, is_own," + " pEp_version_major, pEp_version_minor" + " ) values (" + " ?1," + " upper(replace(?2,' ',''))," + " ?3," + " ?4," + " ?5," + " ?6," + " ?7" + " );"; + +static const char* sql_update_identity_entry = + "update identity " + " set main_key_id = upper(replace(?2,' ','')), " + " flags = ?4, " + " is_own = ?5, " + " pEp_version_major = ?6, " + " pEp_version_minor = ?7 " + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1) " + " else 0 " + " end) = 1 " + " and user_id = ?3 ;"; + +// " (select" +// " coalesce(" +// " (select flags from identity" +// " where address = ?1 and" +// " user_id = ?3)," +// " 0)" +// " ) | (?4 & 255)" +/* set_identity ignores previous flags, and doesn't filter machine flags */ + +static const char *sql_set_identity_flags = + "update identity set flags = " + " ((?1 & 65535) | (select flags from identity" + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" + " else 0 " + " end) = 1 " + " and user_id = ?3)) " + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" + " else 0" + " end) = 1" + " and user_id = ?3 ;"; + +static const char *sql_unset_identity_flags = + "update identity set flags = " + " ( ~(?1 & 65535) & (select flags from identity" + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" + " else 0 " + " end) = 1 " + " and user_id = ?3)) " + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" + " else 0" + " end) = 1" + " and user_id = ?3 ;"; + +static const char *sql_set_ident_enc_format = + "update identity " + " set enc_format = ?1 " + " where (case when (address = ?2) then (1)" + " when (lower(address) = lower(?2)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1) " + " else 0 " + " end) = 1 " + " and user_id = ?3 ;"; + +static const char *sql_set_pEp_version = + "update identity " + " set pEp_version_major = ?1, " + " pEp_version_minor = ?2 " + " where (case when (address = ?3) then (1)" + " when (lower(address) = lower(?3)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?3),'.','')) then (1) " + " else 0 " + " end) = 1 " + " and user_id = ?4 ;"; + +static const char *sql_upgrade_pEp_version_by_user_id = + "update identity " + " set pEp_version_major = ?1, " + " pEp_version_minor = ?2 " + " where user_id = ?3 " + " and (case when (pEp_version_major < ?1) then (1)" + " when (pEp_version_major > ?1) then (0)" + " when (pEp_version_minor < ?2) then (1)" + " else 0 " + " end) = 1 ;"; + +static const char *sql_set_trust = + "insert into trust (user_id, pgp_keypair_fpr, comm_type) " + "values (?1, upper(replace(?2,' ','')), ?3) ;"; + +static const char *sql_update_trust = + "update trust set comm_type = ?3 " + " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; + +static const char *sql_clear_trust_info = + "delete from trust " + " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; + +static const char *sql_update_trust_to_pEp = + "update trust set comm_type = comm_type + 71 " + " where (user_id = ?1 " + " and (case when (comm_type = 56) then (1) " + " when (comm_type = 184) then (1) " + " else 0" + " end) = 1); "; + +static const char* sql_exists_trust_entry = + "select count(*) from trust " + " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; + +static const char *sql_update_trust_for_fpr = + "update trust " + "set comm_type = ?1 " + "where pgp_keypair_fpr = upper(replace(?2,' ','')) ;"; + +static const char *sql_get_trust = + "select comm_type from trust where user_id = ?1 " + "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;"; + +static const char *sql_get_trust_by_userid = + "select pgp_keypair_fpr, comm_type from trust where user_id = ?1 "; + +static const char *sql_least_trust = + "select min(comm_type) from trust where" + " pgp_keypair_fpr = upper(replace(?1,' ',''))" + " and comm_type != 0;"; // ignores PEP_ct_unknown +// returns PEP_ct_unknown only when no known trust is recorded + +static const char *sql_mark_as_compromised = + "update trust not indexed set comm_type = 15" + " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_crashdump = + "select timestamp, title, entity, description, comment" + " from log order by timestamp desc limit ?1 ;"; + +static const char *sql_languagelist = + "select i18n_language.lang, name, phrase" + " from i18n_language join i18n_token using (lang) where i18n_token.id = 1000;" ; + +static const char *sql_i18n_token = + "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;"; + +// blacklist +static const char *sql_blacklist_add = + "insert or ignore into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;" + "delete from identity where main_key_id = upper(replace(?1,' ','')) ;" + "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_blacklist_delete = + "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_blacklist_is_listed = + "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_blacklist_retrieve = + "select * from blacklist_keys ;"; + + +// Own keys +// We only care if it's 0 or non-zero +static const char *sql_own_key_is_listed = + "select count(*) from (" + " select pgp_keypair_fpr from trust" + " join identity on trust.user_id = identity.user_id" + " where pgp_keypair_fpr = upper(replace(?1,' ',''))" + " and identity.is_own = 1" + ");"; + +static const char *sql_is_own_address = + "select count(*) from (" + " select address from identity" + " where (case when (address = ?1) then (1)" + " when (lower(address) = lower(?1)) then (1)" + " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" + " else 0" + " end) = 1 " + " and identity.is_own = 1" + ");"; + +static const char *sql_own_identities_retrieve = + "select address, identity.main_key_id, identity.user_id, username," + " lang, identity.flags | pgp_keypair.flags, pEp_version_major, pEp_version_minor" + " from identity" + " join person on id = identity.user_id" + " left join pgp_keypair on fpr = identity.main_key_id" + " left join trust on id = trust.user_id" + " and pgp_keypair_fpr = identity.main_key_id" + " where identity.is_own = 1" + " and (identity.flags & ?1) = 0;"; + +static const char *sql_own_keys_retrieve = + "select distinct pgp_keypair_fpr from trust" + " join identity on trust.user_id = identity.user_id" + " where identity.is_own = 1"; + +static const char* sql_get_user_default_key = + "select main_key_id from person" + " where id = ?1;"; + +static const char* sql_get_all_keys_for_user = + "select pgp_keypair_fpr from trust" + " where user_id = ?1; "; + +static const char* sql_get_default_own_userid = + "select id from person" + " join identity on id = identity.user_id" + " where identity.is_own = 1"; + +// Sequence +static const char *sql_sequence_value1 = + "insert or replace into sequences (name, value) " + "values (?1, " + " (select coalesce((select value + 1 from sequences " + " where name = ?1), 1 ))); "; + +static const char *sql_sequence_value2 = + "select value from sequences where name = ?1 ;"; + +// Revocation tracking +static const char *sql_set_revoked = + "insert or replace into revoked_keys (" + " revoked_fpr, replacement_fpr, revocation_date) " + "values (upper(replace(?1,' ',''))," + " upper(replace(?2,' ',''))," + " ?3) ;"; + +static const char *sql_get_revoked = + "select revoked_fpr, revocation_date from revoked_keys" + " where replacement_fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_get_replacement_fpr = + "select replacement_fpr, revocation_date from revoked_keys" + " where revoked_fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_get_userid_alias_default = + "select default_id from alternate_user_id " + " where alternate_id = ?1 ; "; + +// Revocation tracking +static const char *sql_add_mistrusted_key = + "insert or replace into mistrusted_keys (fpr) " + " values (upper(replace(?1,' ',''))) ;"; + +static const char *sql_delete_mistrusted_key = + "delete from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_is_mistrusted_key = + "select count(*) from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;"; + +static const char *sql_add_userid_alias = + "insert or replace into alternate_user_id (alternate_id, default_id) " + "values (?2, ?1) ;"; + +static const char *sql_add_into_social_graph = + "insert or replace into social_graph(own_userid, own_address, contact_userid) " + "values (?1, ?2, ?3) ;"; + +static const char *sql_get_own_address_binding_from_contact = + "select own_address from social_graph where own_userid = ?1 and contact_userid = ?2 ;"; + +static const char *sql_set_revoke_contact_as_notified = + "insert or replace into revocation_contact_list(fpr, own_address, contact_id) values (?1, ?2, ?3) ;"; + +static const char *sql_get_contacted_ids_from_revoke_fpr = + "select * from revocation_contact_list where fpr = ?1 ;"; + +static const char *sql_was_id_for_revoke_contacted = + "select count(*) from revocation_contact_list where fpr = ?1 and own_address = ?2 and contact_id = ?3 ;"; + +static const char *sql_has_id_contacted_address = + "select count(*) from social_graph where own_address = ?1 and contact_userid = ?2 ;"; + +// We only need user_id and address, since in the main usage, we'll call update_identity +// on this anyway when sending out messages. +static const char *sql_get_last_contacted = + "select user_id, address from identity where datetime('now') < datetime(timestamp, '+14 days') ; "; + +static const char *sql_create_group = + "insert into groups (group_id, group_address, manager_userid, manager_address) " + "VALUES (?1, ?2, ?3, ?4) ;"; + +static const char *sql_enable_group = + "update groups set active = 1 " + " where group_id = ?1 and group_address = ?2 ;"; + +static const char *sql_disable_group = + "update groups set active = 0 " + " where group_id = ?1 and group_address = ?2 ;"; + +static const char *sql_exists_group_entry = + "select count(*) from groups " + " where group_id = ?1 and group_address = ?2;"; +static const char *sql_group_add_member = + "insert or ignore into own_groups_members (group_id, group_address, member_id, member_address) " + " values (?1, ?2, ?3, ?4) ;"; +static const char *sql_set_group_member_status = + "update own_groups_members set active_member = ?1 " + " where group_id = ?2 and group_address = ?3 and " + " member_id = ?4 and member_address = ?5; "; +static const char *sql_join_group = + "update own_memberships set have_joined = 1 " + " where group_id = ?1 and group_address = ?2 and " + " own_id = ?3 and own_address = ?4; "; +static const char *sql_leave_group = + "update own_memberships set have_joined = 0 " + " where group_id = ?1 and group_address = ?2 and " + " own_id = ?3 and own_address = ?4; "; +static const char *sql_get_all_members = + "select member_id, member_address, active_member from own_groups_members " + " where group_id = ?1 and group_address = ?2; "; +static const char *sql_get_active_members = + "select member_id, member_address from own_groups_members " + " where group_id = ?1 and group_address = ?2 and active_member = 1; "; +static const char *sql_get_group_manager = + "select manager_userid, manager_address from groups " + " where group_id = ?1 and group_address = ?2; "; +static const char *sql_is_invited_group_member = + "select count(*) from own_groups_members " + " where group_id = ?1 and group_address = ?2 and member_id = ?3 and member_address = ?4; "; +static const char *sql_get_all_groups = + "select group_id, group_address from own_memberships; "; +static const char *sql_get_active_groups = + "select group_id, group_address from own_memberships where have_joined = 1; "; +static const char *sql_add_own_membership_entry = + "insert or replace into own_memberships (group_id, group_address, own_id, own_address, have_joined) " + " values (?1, ?2, ?3, ?4, 0) ; "; +static const char *sql_is_group_active = + "select count(*) from groups " + " where group_id = ?1 and group_address = ?2 and active = 1; "; + +// This below can return multiple entries for multiple idents in same group +// FIXME: decide what we really need here +static const char *sql_retrieve_own_membership_info_for_group = + "select own_id, own_address, have_joined " + " from own_memberships " + " inner join groups using (group_id, group_address) " + " where group_id = ?1 and group_address = ?2; "; + +static const char *sql_retrieve_own_membership_info_for_group_and_ident = + "select have_joined, manager_userid, manager_address, active " + " from own_memberships " + " inner join groups using (group_id, group_address) " + " where group_id = ?1 and group_address = ?2 and own_id = ?3 and own_address = ?4; "; + +// This will return all membership info for all identities +static const char *sql_retrieve_all_own_membership_info = + "select group_id, group_address, own_id, own_address, have_joined, manager_id, manager_address, active " + " from own_memberships " + " inner join using (group_id, group_address); "; + +static const char* sql_get_own_membership_status = + "select have_joined from own_memberships " + " where group_id = ?1 and group_address = ?2 and " + " own_id = ?3 and own_address = ?4; "; diff --git a/src/key_reset.c b/src/key_reset.c index d1a673438..e517958c9 100644 --- a/src/key_reset.c +++ b/src/key_reset.c @@ -23,21 +23,6 @@ #define KEY_RESET_MAJOR_VERSION 1L #define KEY_RESET_MINOR_VERSION 0L -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] *msg message - * - */ -static void _add_auto_consume(message* msg) { - add_opt_field(msg, "pEp-auto-consume", "yes"); - msg->in_reply_to = stringlist_add(msg->in_reply_to, "pEp-auto-consume@pEp.foundation"); -} - /** * @internal * diff --git a/src/pEpEngine.c b/src/pEpEngine.c index 7bf7afa55..4610d759a 100644 --- a/src/pEpEngine.c +++ b/src/pEpEngine.c @@ -10,6 +10,7 @@ #include "transport.h" #include "blacklist.h" #include "KeySync_fsm.h" +#include "engine_sql.h" #include #include @@ -20,2553 +21,75 @@ static volatile int init_count = -1; -// sql overloaded functions - modified from sqlite3.c -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] *ctx sqlite3_context - * @param[in] argc int - * @param[in] **argv sqlite3_value - * - */ -static void _sql_lower(sqlite3_context* ctx, int argc, sqlite3_value** argv) { - const char *z2; - int n; - z2 = (char*)sqlite3_value_text(argv[0]); - n = sqlite3_value_bytes(argv[0]); - /* Verify that the call to _bytes() does not invalidate the _text() pointer */ - assert( z2==(char*)sqlite3_value_text(argv[0]) ); - if( z2 ){ - char *z1 = (char*)sqlite3_malloc(n+1); - if( z1 ){ - for(int i=0; i 0x7a) - c_mod = c; - z1[i] = c_mod; - } - z1[n] = '\0'; - sqlite3_result_text(ctx, z1, n, sqlite3_free); - } - } -} - -#ifdef _PEP_SQLITE_DEBUG -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] trace_constant unsigned - * @param[in] *context_ptr void - * @param[in] *P void - * @param[in] *X void - * - */ -int sql_trace_callback (unsigned trace_constant, - void* context_ptr, - void* P, - void* X) { - switch (trace_constant) { - case SQLITE_TRACE_STMT: - fprintf(stderr, "SQL_DEBUG: STMT - "); - const char* X_str = (const char*) X; - if (!EMPTYSTR(X_str) && X_str[0] == '-' && X_str[1] == '-') - fprintf(stderr, "%s\n", X_str); - else - fprintf(stderr, "%s\n", sqlite3_expanded_sql((sqlite3_stmt*)P)); - break; - case SQLITE_TRACE_ROW: - fprintf(stderr, "SQL_DEBUG: ROW - "); - fprintf(stderr, "%s\n", sqlite3_expanded_sql((sqlite3_stmt*)P)); - break; - case SQLITE_TRACE_CLOSE: - fprintf(stderr, "SQL_DEBUG: CLOSE - "); - break; - default: - break; - } - return 0; -} -#endif - -// sql manipulation statements -static const char *sql_log = - "insert into log (title, entity, description, comment)" - "values (?1, ?2, ?3, ?4);"; - -static const char *sql_trustword = - "select id, word from wordlist where lang = lower(?1) " - "and id = ?2 ;"; - -// FIXME?: problems if we don't have a key for the user - we get nothing -static const char *sql_get_identity = - "select identity.main_key_id, username, comm_type, lang," - " identity.flags | pgp_keypair.flags," - " is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " left join pgp_keypair on fpr = identity.main_key_id" - " left join trust on id = trust.user_id" - " and pgp_keypair_fpr = identity.main_key_id" - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1" - " and identity.user_id = ?2" - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_get_identities_by_main_key_id = - "select address, identity.user_id, username, comm_type, lang," - " identity.flags | pgp_keypair.flags," - " is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " left join pgp_keypair on fpr = identity.main_key_id" - " left join trust on id = trust.user_id" - " and pgp_keypair_fpr = identity.main_key_id" - " where identity.main_key_id = ?1" - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_get_identity_without_trust_check = - "select identity.main_key_id, username, lang," - " identity.flags, is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1" - " and identity.user_id = ?2 " - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_get_identities_by_address = - "select user_id, identity.main_key_id, username, lang," - " identity.flags, is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1 " - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_get_identities_by_userid = - "select address, identity.main_key_id, username, comm_type, lang," - " identity.flags | pgp_keypair.flags," - " is_own, pEp_version_major, pEp_version_minor, enc_format" - " from identity" - " join person on id = identity.user_id" - " left join pgp_keypair on fpr = identity.main_key_id" - " left join trust on id = trust.user_id" - " and pgp_keypair_fpr = identity.main_key_id" - " where identity.user_id = ?1" - " order by is_own desc, " - " timestamp desc; "; - -static const char *sql_replace_identities_fpr = - "update identity" - " set main_key_id = ?1 " - " where main_key_id = ?2 ;"; - -static const char *sql_remove_fpr_as_identity_default = - "update identity set main_key_id = NULL where main_key_id = ?1 ;"; - -static const char *sql_remove_fpr_as_user_default = - "update person set main_key_id = NULL where main_key_id = ?1 ;"; - -// Set person, but if already exist, only update. -// if main_key_id already set, don't touch. -static const char *sql_set_person = - "insert into person (id, username, lang, main_key_id)" - " values (?1, ?2, ?3, ?4) ;"; - -static const char *sql_update_person = - "update person " - " set username = ?2, " - " lang = ?3, " - " main_key_id = " - " (select coalesce( " - " (select main_key_id from person where id = ?1), " - " upper(replace(?4,' ',''))))" - " where id = ?1 ;"; - -// Will cascade. -static const char *sql_delete_person = - "delete from person where id = ?1 ;"; - -static const char *sql_set_as_pEp_user = - "update person set is_pEp_user = 1 " - " where id = ?1 ; "; - -static const char *sql_is_pEp_user = - "select is_pEp_user from person " - " where id = ?1 ; "; - -static const char* sql_exists_person = - "select count(*) from person " - " where id = ?1 ;"; - -// This will cascade to identity and trust -static const char* sql_replace_userid = - "update person set id = ?1 " - " where id = ?2;"; - -// Hopefully this cascades and removes trust entries... -static const char *sql_delete_key = - "delete from pgp_keypair " - " where fpr = ?1 ; "; - -static const char *sql_replace_main_user_fpr = - "update person " - " set main_key_id = ?1 " - " where id = ?2 ;"; - -static const char *sql_get_main_user_fpr = - "select main_key_id from person" - " where id = ?1 ;"; - -static const char *sql_replace_main_user_fpr_if_equal = - "update person " - " set main_key_id = ?1 " - " where id = ?2 and main_key_id = ?3;"; - -static const char *sql_refresh_userid_default_key = - "update person " - " set main_key_id = " - " (select identity.main_key_id from identity " - " join trust on trust.user_id = identity.user_id " - " and trust.pgp_keypair_fpr = identity.main_key_id " - " join person on person.id = identity.user_id " - " where identity.user_id = ?1 " - " order by trust.comm_type desc " - " limit 1) " - "where id = ?1 ; "; - -static const char *sql_set_pgp_keypair = - "insert or ignore into pgp_keypair (fpr) " - "values (upper(replace(?1,' ',''))) ;"; - -static const char* sql_exists_identity_entry = - "select count(*) from identity " - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1" - " and user_id = ?2;"; - -static const char *sql_set_identity_entry = - "insert into identity (" - " address, main_key_id, " - " user_id, flags, is_own," - " pEp_version_major, pEp_version_minor" - " ) values (" - " ?1," - " upper(replace(?2,' ',''))," - " ?3," - " ?4," - " ?5," - " ?6," - " ?7" - " );"; - -static const char* sql_update_identity_entry = - "update identity " - " set main_key_id = upper(replace(?2,' ','')), " - " flags = ?4, " - " is_own = ?5, " - " pEp_version_major = ?6, " - " pEp_version_minor = ?7 " - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1) " - " else 0 " - " end) = 1 " - " and user_id = ?3 ;"; - - // " (select" - // " coalesce(" - // " (select flags from identity" - // " where address = ?1 and" - // " user_id = ?3)," - // " 0)" - // " ) | (?4 & 255)" - /* set_identity ignores previous flags, and doesn't filter machine flags */ - -static const char *sql_set_identity_flags = - "update identity set flags = " - " ((?1 & 65535) | (select flags from identity" - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" - " else 0 " - " end) = 1 " - " and user_id = ?3)) " - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" - " else 0" - " end) = 1" - " and user_id = ?3 ;"; - -static const char *sql_unset_identity_flags = - "update identity set flags = " - " ( ~(?1 & 65535) & (select flags from identity" - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" - " else 0 " - " end) = 1 " - " and user_id = ?3)) " - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1)" - " else 0" - " end) = 1" - " and user_id = ?3 ;"; - -static const char *sql_set_ident_enc_format = - "update identity " - " set enc_format = ?1 " - " where (case when (address = ?2) then (1)" - " when (lower(address) = lower(?2)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?2),'.','')) then (1) " - " else 0 " - " end) = 1 " - " and user_id = ?3 ;"; - -static const char *sql_set_pEp_version = - "update identity " - " set pEp_version_major = ?1, " - " pEp_version_minor = ?2 " - " where (case when (address = ?3) then (1)" - " when (lower(address) = lower(?3)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?3),'.','')) then (1) " - " else 0 " - " end) = 1 " - " and user_id = ?4 ;"; - -static const char *sql_upgrade_pEp_version_by_user_id = - "update identity " - " set pEp_version_major = ?1, " - " pEp_version_minor = ?2 " - " where user_id = ?3 " - " and (case when (pEp_version_major < ?1) then (1)" - " when (pEp_version_major > ?1) then (0)" - " when (pEp_version_minor < ?2) then (1)" - " else 0 " - " end) = 1 ;"; - -static const char *sql_set_trust = - "insert into trust (user_id, pgp_keypair_fpr, comm_type) " - "values (?1, upper(replace(?2,' ','')), ?3) ;"; - -static const char *sql_update_trust = - "update trust set comm_type = ?3 " - " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; - -static const char *sql_clear_trust_info = - "delete from trust " - " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; - -static const char *sql_update_trust_to_pEp = - "update trust set comm_type = comm_type + 71 " - " where (user_id = ?1 " - " and (case when (comm_type = 56) then (1) " - " when (comm_type = 184) then (1) " - " else 0" - " end) = 1); "; - -static const char* sql_exists_trust_entry = - "select count(*) from trust " - " where user_id = ?1 and pgp_keypair_fpr = upper(replace(?2,' ',''));"; - -static const char *sql_update_trust_for_fpr = - "update trust " - "set comm_type = ?1 " - "where pgp_keypair_fpr = upper(replace(?2,' ','')) ;"; - -static const char *sql_get_trust = - "select comm_type from trust where user_id = ?1 " - "and pgp_keypair_fpr = upper(replace(?2,' ','')) ;"; - -static const char *sql_get_trust_by_userid = - "select pgp_keypair_fpr, comm_type from trust where user_id = ?1 "; - -static const char *sql_least_trust = - "select min(comm_type) from trust where" - " pgp_keypair_fpr = upper(replace(?1,' ',''))" - " and comm_type != 0;"; // ignores PEP_ct_unknown - // returns PEP_ct_unknown only when no known trust is recorded - -static const char *sql_mark_as_compromised = - "update trust not indexed set comm_type = 15" - " where pgp_keypair_fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_crashdump = - "select timestamp, title, entity, description, comment" - " from log order by timestamp desc limit ?1 ;"; - -static const char *sql_languagelist = - "select i18n_language.lang, name, phrase" - " from i18n_language join i18n_token using (lang) where i18n_token.id = 1000;" ; - -static const char *sql_i18n_token = - "select phrase from i18n_token where lang = lower(?1) and id = ?2 ;"; - -// blacklist -static const char *sql_blacklist_add = - "insert or ignore into blacklist_keys (fpr) values (upper(replace(?1,' ',''))) ;" - "delete from identity where main_key_id = upper(replace(?1,' ','')) ;" - "delete from pgp_keypair where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_blacklist_delete = - "delete from blacklist_keys where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_blacklist_is_listed = - "select count(*) from blacklist_keys where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_blacklist_retrieve = - "select * from blacklist_keys ;"; - - -// Own keys -// We only care if it's 0 or non-zero -static const char *sql_own_key_is_listed = - "select count(*) from (" - " select pgp_keypair_fpr from trust" - " join identity on trust.user_id = identity.user_id" - " where pgp_keypair_fpr = upper(replace(?1,' ',''))" - " and identity.is_own = 1" - ");"; - -static const char *sql_is_own_address = - "select count(*) from (" - " select address from identity" - " where (case when (address = ?1) then (1)" - " when (lower(address) = lower(?1)) then (1)" - " when (replace(lower(address),'.','') = replace(lower(?1),'.','')) then (1)" - " else 0" - " end) = 1 " - " and identity.is_own = 1" - ");"; - -static const char *sql_own_identities_retrieve = - "select address, identity.main_key_id, identity.user_id, username," - " lang, identity.flags | pgp_keypair.flags, pEp_version_major, pEp_version_minor" - " from identity" - " join person on id = identity.user_id" - " left join pgp_keypair on fpr = identity.main_key_id" - " left join trust on id = trust.user_id" - " and pgp_keypair_fpr = identity.main_key_id" - " where identity.is_own = 1" - " and (identity.flags & ?1) = 0;"; - -static const char *sql_own_keys_retrieve = - "select distinct pgp_keypair_fpr from trust" - " join identity on trust.user_id = identity.user_id" - " where identity.is_own = 1"; - -static const char* sql_get_user_default_key = - "select main_key_id from person" - " where id = ?1;"; - -static const char* sql_get_all_keys_for_user = - "select pgp_keypair_fpr from trust" - " where user_id = ?1; "; - -static const char* sql_get_default_own_userid = - "select id from person" - " join identity on id = identity.user_id" - " where identity.is_own = 1"; - -// Sequence -static const char *sql_sequence_value1 = - "insert or replace into sequences (name, value) " - "values (?1, " - " (select coalesce((select value + 1 from sequences " - " where name = ?1), 1 ))); "; - -static const char *sql_sequence_value2 = - "select value from sequences where name = ?1 ;"; - -// Revocation tracking -static const char *sql_set_revoked = - "insert or replace into revoked_keys (" - " revoked_fpr, replacement_fpr, revocation_date) " - "values (upper(replace(?1,' ',''))," - " upper(replace(?2,' ',''))," - " ?3) ;"; - -static const char *sql_get_revoked = - "select revoked_fpr, revocation_date from revoked_keys" - " where replacement_fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_get_replacement_fpr = - "select replacement_fpr, revocation_date from revoked_keys" - " where revoked_fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_get_userid_alias_default = - "select default_id from alternate_user_id " - " where alternate_id = ?1 ; "; - -// Revocation tracking -static const char *sql_add_mistrusted_key = - "insert or replace into mistrusted_keys (fpr) " - " values (upper(replace(?1,' ',''))) ;"; - -static const char *sql_delete_mistrusted_key = - "delete from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_is_mistrusted_key = - "select count(*) from mistrusted_keys where fpr = upper(replace(?1,' ','')) ;"; - -static const char *sql_add_userid_alias = - "insert or replace into alternate_user_id (alternate_id, default_id) " - "values (?2, ?1) ;"; - -static const char *sql_add_into_social_graph = - "insert or replace into social_graph(own_userid, own_address, contact_userid) " - "values (?1, ?2, ?3) ;"; - -static const char *sql_get_own_address_binding_from_contact = - "select own_address from social_graph where own_userid = ?1 and contact_userid = ?2 ;"; - -static const char *sql_set_revoke_contact_as_notified = - "insert or replace into revocation_contact_list(fpr, own_address, contact_id) values (?1, ?2, ?3) ;"; - -static const char *sql_get_contacted_ids_from_revoke_fpr = - "select * from revocation_contact_list where fpr = ?1 ;"; - -static const char *sql_was_id_for_revoke_contacted = - "select count(*) from revocation_contact_list where fpr = ?1 and own_address = ?2 and contact_id = ?3 ;"; - -static const char *sql_has_id_contacted_address = - "select count(*) from social_graph where own_address = ?1 and contact_userid = ?2 ;"; - -// We only need user_id and address, since in the main usage, we'll call update_identity -// on this anyway when sending out messages. -static const char *sql_get_last_contacted = - "select user_id, address from identity where datetime('now') < datetime(timestamp, '+14 days') ; "; - -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] *_version void - * @param[in] count int - * @param[in] **text char - * @param[in] **name char - * - */ -static int user_version(void *_version, int count, char **text, char **name) -{ - if (!(_version && count == 1 && text && text[0])) - return -1; - - int *version = (int *) _version; - *version = atoi(text[0]); - return 0; -} - -// TODO: refactor and generalise these two functions if possible. -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] session PEP_SESSION - * @param[in] *table_name constchar - * - */ -static int db_contains_table(PEP_SESSION session, const char* table_name) { - if (!session || !table_name) - return -1; - - // Table names can't be SQL parameters, so we do it this way. - - // these two must be the same number. - char sql_buf[500]; - const size_t max_q_len = 500; - - size_t t_size, q_size; - - const char* q1 = "SELECT name FROM sqlite_master WHERE type='table' AND name='{"; // 61 - const char* q2 = "}';"; // 3 - - q_size = 64; - t_size = strlen(table_name); - - size_t query_len = q_size + t_size + 1; - - if (query_len > max_q_len) - return -1; - - strlcpy(sql_buf, q1, max_q_len); - strlcat(sql_buf, table_name, max_q_len); - strlcat(sql_buf, q2, max_q_len); - - sqlite3_stmt *stmt; - - sqlite3_prepare_v2(session->db, sql_buf, -1, &stmt, NULL); - - int retval = 0; - - int rc = sqlite3_step(stmt); - if (rc == SQLITE_DONE || rc == SQLITE_OK || rc == SQLITE_ROW) { - retval = 1; - } - - sqlite3_finalize(stmt); - - return retval; - -} - -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] session PEP_SESSION - * @param[in] *table_name constchar - * @param[in] *col_name constchar - * - */ -static int table_contains_column(PEP_SESSION session, const char* table_name, - const char* col_name) { - - - if (!session || !table_name || !col_name) - return -1; - - // Table names can't be SQL parameters, so we do it this way. - - // these two must be the same number. - char sql_buf[500]; - const size_t max_q_len = 500; - - size_t t_size, c_size, q_size; - - const char* q1 = "SELECT "; // 7 - const char* q2 = " from "; // 6 - const char* q3 = ";"; // 1 - - q_size = 14; - t_size = strlen(table_name); - c_size = strlen(col_name); - - size_t query_len = q_size + c_size + t_size + 1; - - if (query_len > max_q_len) - return -1; - - strlcpy(sql_buf, q1, max_q_len); - strlcat(sql_buf, col_name, max_q_len); - strlcat(sql_buf, q2, max_q_len); - strlcat(sql_buf, table_name, max_q_len); - strlcat(sql_buf, q3, max_q_len); - - sqlite3_stmt *stmt; - - sqlite3_prepare_v2(session->db, sql_buf, -1, &stmt, NULL); - - int retval = 0; - - int rc = sqlite3_step(stmt); - if (rc == SQLITE_DONE || rc == SQLITE_OK || rc == SQLITE_ROW) { - retval = 1; - } - - sqlite3_finalize(stmt); - - return retval; -} - -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] session PEP_SESSION - * - */ -#define _PEP_MAX_AFFECTED 5 -PEP_STATUS repair_altered_tables(PEP_SESSION session) { - PEP_STATUS status = PEP_STATUS_OK; - - char* table_names[_PEP_MAX_AFFECTED] = {0}; - - const char* sql_query = "select tbl_name from sqlite_master WHERE sql LIKE '%REFERENCES%' AND sql LIKE '%_old%';"; - sqlite3_stmt *stmt; - sqlite3_prepare_v2(session->db, sql_query, -1, &stmt, NULL); - int i = 0; - int int_result = 0; - while ((int_result = sqlite3_step(stmt)) == SQLITE_ROW && i < _PEP_MAX_AFFECTED) { - table_names[i++] = strdup((const char*)(sqlite3_column_text(stmt, 0))); - } - - sqlite3_finalize(stmt); - - if ((int_result != SQLITE_DONE && int_result != SQLITE_OK) || i > (_PEP_MAX_AFFECTED + 1)) { - status = PEP_UNKNOWN_DB_ERROR; - goto pEp_free; - } - - for (i = 0; i < _PEP_MAX_AFFECTED; i++) { - const char* table_name = table_names[i]; - if (!table_name) - break; - - if (strcmp(table_name, "identity") == 0) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _identity_new (\n" - " address text,\n" - " user_id text\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " comment text,\n" - " flags integer default 0,\n" - " is_own integer default 0,\n" - " timestamp integer default (datetime('now')),\n" - " primary key (address, user_id)\n" - ");\n" - "INSERT INTO _identity_new SELECT * from identity;\n" - "DROP TABLE identity;\n" - "ALTER TABLE _identity_new RENAME TO identity;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - else if (strcmp(table_name, "trust") == 0) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _trust_new (\n" - " user_id text not null\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " pgp_keypair_fpr text not null\n" - " references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " comm_type integer not null,\n" - " comment text,\n" - " primary key (user_id, pgp_keypair_fpr)\n" - ");\n" - "INSERT INTO _trust_new SELECT * from trust;\n" - "DROP TABLE trust;\n" - "ALTER TABLE _trust_new RENAME TO trust;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - else if (strcmp(table_name, "alternate_user_id") == 0) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _alternate_user_id_new (\n" - " default_id text references person (id)\n" - " on delete cascade on update cascade,\n" - " alternate_id text primary key\n" - ");\n" - "INSERT INTO _alternate_user_id_new SELECT * from alternate_user_id;\n" - "DROP TABLE alternate_user_id;\n" - "ALTER TABLE _alternate_user_id_new RENAME TO alternate_user_id;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - else if (strcmp(table_name, "revocation_contact_list") == 0) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _revocation_contact_list_new (\n" - " fpr text not null references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " contact_id text not null references person (id)\n" - " on delete cascade on update cascade,\n" - " timestamp integer default (datetime('now')),\n" - " PRIMARY KEY(fpr, contact_id)\n" - ");\n" - "INSERT INTO _revocation_contact_list_new SELECT * from revocation_contact_list;\n" - "DROP TABLE revocation_contact_list;\n" - "ALTER TABLE _revocation_contact_list_new RENAME TO revocation_contact_list;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - else if (strcmp(table_name, "social_graph")) { - int_result = sqlite3_exec(session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _social_new (\n" - " own_userid text,\n" - " own_address text,\n" - " contact_userid text,\n" - " CONSTRAINT fk_own_identity\n" - " FOREIGN KEY(own_address, own_userid)\n" - " REFERENCES identity(address, user_id)\n" - " ON DELETE CASCADE ON UPDATE CASCADE\n" - ");\n" - "INSERT INTO _social_graph_new SELECT * from social_graph;\n" - "DROP TABLE social_graph;\n" - "ALTER TABLE _social_graph_new RENAME TO social_graph;\n" - "COMMIT;\n" - "PRAGMA foreign_keys=on;" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - } - } - - int_result = sqlite3_exec( - session->db, - "PRAGMA foreign_key_check;\n" - , - NULL, - NULL, - NULL - ); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - -pEp_free: - for (i = 0; i < _PEP_MAX_AFFECTED; i++) { - free(table_names[i]); - } - return status; -} -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] *pArg void - * @param[in] iErrCode int - * @param[in] *zMsg constchar - * - */ -void errorLogCallback(void *pArg, int iErrCode, const char *zMsg){ - fprintf(stderr, "(%d) %s\n", iErrCode, zMsg); -} - -/** - * @internal - * - * - * - * @brief TODO - * - * @param[in] session PEP_SESSION - * - */ -static PEP_STATUS upgrade_revoc_contact_to_13(PEP_SESSION session) { - // I HATE SQLITE. - PEP_STATUS status = PEP_STATUS_OK; - int int_result = 0; - - // Ok, first we ADD the column so we can USE it. - // We will end up propagating the "error" this first time - // (one-to-one revoke-replace relationships), but since key reset - // hasn't been used in production, this is not a customer-facing - // issue. - - // Note: the check upfront is to deal with partially-upgraded DB issues - if (!table_contains_column(session, "revocation_contact_list", "own_address")) { - int_result = sqlite3_exec( - session->db, - "alter table revocation_contact_list\n" - " add column own_address text;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - // the best we can do here is search per address, since these - // are no longer associated with an identity. For now, if we find - // something we can't add an address to, we'll delete the record. - // this should not, in the current environment, ever happen, but - // since we need to make the address part of the primary key, it's - // the right thing to do. sqlite does support null fields in a primary - // key for a weird version compatibility reason, but that doesn't - // mean we should use it, and we should be *safe*, not relying - // on an implementation-specific quirk which might be sanely removed - // in a future sqlite version. - - identity_list* id_list = NULL; - - sqlite3_stmt* tmp_own_id_retrieve = NULL; - sqlite3_prepare_v2(session->db, sql_own_identities_retrieve, -1, &tmp_own_id_retrieve, NULL); - - // Kludgey - put the stmt in temporarily, and then remove again, so less code dup. - // FIXME LATER: refactor if possible, but... chicken and egg, and thiis case rarely happens. - session->own_identities_retrieve = tmp_own_id_retrieve; - status = own_identities_retrieve(session, &id_list); - sqlite3_finalize(tmp_own_id_retrieve); - session->own_identities_retrieve = NULL; - - if (!status || !id_list) - return PEP_STATUS_OK; // it's empty AFAIK (FIXME) - - identity_list* curr_own = id_list; - - sqlite3_stmt* update_revoked_w_addr_stmt = NULL; - const char* sql_query = "update revocation_contact_list set own_address = ?1 where fpr = ?2;"; - sqlite3_prepare_v2(session->db, sql_query, -1, &update_revoked_w_addr_stmt, NULL); - - // Ok, go through and find any keys associated with this address - for ( ; curr_own && curr_own->ident; curr_own = curr_own->next) { - if (EMPTYSTR(curr_own->ident->address)) // shouldn't happen - continue; - stringlist_t* keylist = NULL; - status = find_keys(session, curr_own->ident->address, &keylist); - stringlist_t* curr_key = keylist; - for ( ; curr_key && curr_key->value; curr_key = curr_key->next) { - if (EMPTYSTR(curr_key->value)) - continue; - - // We just do this lazily - if this isn't a revoked key, it - // won't do anything. - sqlite3_bind_text(update_revoked_w_addr_stmt, 1, curr_own->ident->address, -1, - SQLITE_STATIC); - sqlite3_bind_text(update_revoked_w_addr_stmt, 2, curr_key->value, -1, - SQLITE_STATIC); - - int_result = sqlite3_step(update_revoked_w_addr_stmt); - assert(int_result == SQLITE_DONE); - - sqlite3_reset(update_revoked_w_addr_stmt); - - if (int_result != SQLITE_DONE) - return PEP_UNKNOWN_DB_ERROR; - - } - } - sqlite3_finalize(update_revoked_w_addr_stmt); - - int_result = sqlite3_exec( - session->db, - "delete from revocation_contact_list where own_address is NULL;\n" - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table if not exists _revocation_contact_list_new (\n" - " fpr text not null references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " own_address text,\n" - " contact_id text not null references person (id)\n" - " on delete cascade on update cascade,\n" - " timestamp integer default (datetime('now')),\n" - " PRIMARY KEY(fpr, own_address, contact_id)\n" - ");\n" - "INSERT INTO _revocation_contact_list_new (fpr, " - " own_address, " - " contact_id) " - " SELECT revocation_contact_list.fpr, " - " revocation_contact_list.own_address, " - " revocation_contact_list.contact_id " - " FROM revocation_contact_list " - " WHERE 1;\n" - "DROP TABLE revocation_contact_list;\n" - "ALTER TABLE _revocation_contact_list_new RENAME TO revocation_contact_list;\n" - "COMMIT;\n" - "\n" - "PRAGMA foreign_keys=on;\n" - , - NULL, - NULL, - NULL - ); - - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - return status; -} - -DYNAMIC_API PEP_STATUS init( - PEP_SESSION *session, - messageToSend_t messageToSend, - inject_sync_event_t inject_sync_event, - ensure_passphrase_t ensure_passphrase - ) -{ - PEP_STATUS status = PEP_STATUS_OK; - int int_result; - - bool in_first = false; - bool very_first = false; - - assert(sqlite3_threadsafe()); - if (!sqlite3_threadsafe()) - return PEP_INIT_SQLITE3_WITHOUT_MUTEX; - - // a little race condition - but still a race condition - // mitigated by calling caveat (see documentation) - - // this increment is made atomic IN THE ADAPTERS by - // guarding the call to init with the appropriate mutex. - int _count = ++init_count; - if (_count == 0) - in_first = true; - - // Race condition mitigated by calling caveat starts here : - // If another call to init() preempts right now, then preemptive call - // will have in_first false, will not create SQL tables, and following - // calls relying on those tables will fail. - // - // Therefore, as above, adapters MUST guard init() with a mutex. - // - // Therefore, first session - // is to be created and last session to be deleted alone, and not - // concurently to other sessions creation or deletion. - // We expect adapters to enforce this either by implicitely creating a - // client session, or by using synchronization primitive to protect - // creation/deletion of first/last session from the app. - - if (session == NULL) - return PEP_ILLEGAL_VALUE; - - *session = NULL; - - pEpSession *_session = calloc(1, sizeof(pEpSession)); - assert(_session); - if (_session == NULL) - goto enomem; - - _session->version = PEP_ENGINE_VERSION; - _session->messageToSend = messageToSend; - _session->inject_sync_event = inject_sync_event; - _session->ensure_passphrase = ensure_passphrase; - - assert(LOCAL_DB); - if (LOCAL_DB == NULL) { - status = PEP_INIT_CANNOT_OPEN_DB; - goto pEp_error; - } - -#ifdef _PEP_SQLITE_DEBUG - sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, NULL); -#endif - - int_result = sqlite3_open_v2( - LOCAL_DB, - &_session->db, - SQLITE_OPEN_READWRITE - | SQLITE_OPEN_CREATE - | SQLITE_OPEN_FULLMUTEX - | SQLITE_OPEN_PRIVATECACHE, - NULL - ); - - if (int_result != SQLITE_OK) { - status = PEP_INIT_CANNOT_OPEN_DB; - goto pEp_error; - } - - int_result = sqlite3_exec( - _session->db, - "PRAGMA locking_mode=NORMAL;\n" - "PRAGMA journal_mode=WAL;\n", - NULL, - NULL, - NULL - ); - - - sqlite3_busy_timeout(_session->db, BUSY_WAIT_TIME); - -#ifdef _PEP_SQLITE_DEBUG - sqlite3_trace_v2(_session->db, - SQLITE_TRACE_STMT | SQLITE_TRACE_ROW | SQLITE_TRACE_CLOSE, - sql_trace_callback, - NULL); -#endif - - assert(SYSTEM_DB); - if (SYSTEM_DB == NULL) { - status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB; - goto pEp_error; - } - - int_result = sqlite3_open_v2( - SYSTEM_DB, &_session->system_db, - SQLITE_OPEN_READONLY - | SQLITE_OPEN_FULLMUTEX - | SQLITE_OPEN_SHAREDCACHE, - NULL - ); - - if (int_result != SQLITE_OK) { - status = PEP_INIT_CANNOT_OPEN_SYSTEM_DB; - goto pEp_error; - } - - sqlite3_busy_timeout(_session->system_db, 1000); - -// increment this when patching DDL -#define _DDL_USER_VERSION "14" - - if (in_first) { - - int_result = sqlite3_exec( - _session->db, - "create table if not exists version_info (\n" - " id integer primary key,\n" - " timestamp integer default (datetime('now')),\n" - " version text,\n" - " comment text\n" - ");\n", - NULL, - NULL, - NULL - ); - int_result = sqlite3_exec( - _session->db, - "PRAGMA application_id = 0x23423423;\n" - "create table if not exists log (\n" - " timestamp integer default (datetime('now')),\n" - " title text not null,\n" - " description text,\n" - " entity text not null,\n" - " comment text\n" - ");\n" - "create index if not exists log_timestamp on log (\n" - " timestamp\n" - ");\n" - "create table if not exists pgp_keypair (\n" - " fpr text primary key,\n" - " created integer,\n" - " expires integer,\n" - " comment text,\n" - " flags integer default 0\n" - ");\n" - "create index if not exists pgp_keypair_expires on pgp_keypair (\n" - " expires\n" - ");\n" - "create table if not exists person (\n" - " id text primary key,\n" - " username text not null,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " lang text,\n" - " comment text,\n" -// " device_group text,\n" - " is_pEp_user integer default 0\n" - ");\n" - "create table if not exists identity (\n" - " address text,\n" - " user_id text\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " comment text,\n" - " flags integer default 0,\n" - " is_own integer default 0,\n" - " pEp_version_major integer default 0,\n" - " pEp_version_minor integer default 0,\n" - " enc_format integer default 0,\n" - " timestamp integer default (datetime('now')),\n" - " primary key (address, user_id)\n" - ");\n" - "create index if not exists identity_userid_addr on identity(address, user_id);\n" - "create table if not exists trust (\n" - " user_id text not null\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " pgp_keypair_fpr text not null\n" - " references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " comm_type integer not null,\n" - " comment text,\n" - " primary key (user_id, pgp_keypair_fpr)\n" - ");\n" - // blacklist - "create table if not exists blacklist_keys (\n" - " fpr text primary key\n" - ");\n" - // sequences - "create table if not exists sequences(\n" - " name text primary key,\n" - " value integer default 0\n" - ");\n" - "create table if not exists revoked_keys (\n" - " revoked_fpr text primary key,\n" - " replacement_fpr text not null\n" - " references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " revocation_date integer\n" - ");\n" - // user id aliases - "create table if not exists alternate_user_id (\n" - " default_id text references person (id)\n" - " on delete cascade on update cascade,\n" - " alternate_id text primary key\n" - ");\n" - // mistrusted keys - "create table if not exists mistrusted_keys (\n" - " fpr text primary key\n" - ");\n" - // social graph for key resets - "create table if not exists social_graph (\n" - " own_userid text,\n" - " own_address text,\n" - " contact_userid text,\n" - " CONSTRAINT fk_own_identity\n" - " FOREIGN KEY(own_address, own_userid)\n" - " REFERENCES identity(address, user_id)\n" - " ON DELETE CASCADE ON UPDATE CASCADE\n" - ");\n" - // list of user_ids sent revocation - "create table if not exists revocation_contact_list (\n" - " fpr text not null references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " own_address text,\n" - " contact_id text not null references person (id)\n" - " on delete cascade on update cascade,\n" - " timestamp integer default (datetime('now')),\n" - " PRIMARY KEY(fpr, own_address, contact_id)\n" - ");\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int version; - int_result = sqlite3_exec( - _session->db, - "pragma user_version;", - user_version, - &version, - NULL - ); - - assert(int_result == SQLITE_OK); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - void (*xFunc_lower)(sqlite3_context*,int,sqlite3_value**) = &_sql_lower; - - int_result = sqlite3_create_function_v2( - _session->db, - "lower", - 1, - SQLITE_UTF8 | SQLITE_DETERMINISTIC, - NULL, - xFunc_lower, - NULL, - NULL, - NULL); - - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "pragma foreign_keys=ON;\n", - NULL, - NULL, - NULL - ); - - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - if (version > atoi(_DDL_USER_VERSION)) { - // This is *explicitly* not allowed. - return PEP_INIT_DB_DOWNGRADE_VIOLATION; - } - - // Sometimes the user_version wasn't set correctly. - if (version == 1) { - bool version_changed = true; - if (table_contains_column(_session, "identity", "enc_format")) { - version = 14; - } - else if (table_contains_column(_session, "revocation_contact_list", "own_address")) { - version = 13; - } - else if (table_contains_column(_session, "identity", "pEp_version_major")) { - version = 12; - } - else if (db_contains_table(_session, "social_graph") > 0) { - if (!table_contains_column(_session, "person", "device_group")) - version = 10; - else - version = 9; - } - else if (table_contains_column(_session, "identity", "timestamp") > 0) { - version = 8; - } - else if (table_contains_column(_session, "person", "is_pEp_user") > 0) { - version = 7; - } - else if (table_contains_column(_session, "identity", "is_own") > 0) { - version = 6; - } - else if (table_contains_column(_session, "pgp_keypair", "flags") > 0) { - version = 2; - } - else { - version_changed = false; - } - - if (version_changed) { - // set it in the DB, finally. Yeesh. - char verbuf[21]; // enough digits for a max-sized 64 bit int, cmon. - sprintf(verbuf,"%d",version); - - size_t query_size = strlen(verbuf) + 25; - char* query = calloc(query_size, 1); - - strlcpy(query, "pragma user_version = ", query_size); - strlcat(query, verbuf, query_size); - strlcat(query, ";", query_size); - - int_result = sqlite3_exec( - _session->db, - query, - user_version, - &version, - NULL - ); - free(query); - } - } - - - if(version != 0) { - // Version has been already set - - // Early mistake : version 0 shouldn't have existed. - // Numbering should have started at 1 to detect newly created DB. - // Version 0 DBs are not anymore compatible. - - // // Was version 0 compat code. - // if (version < 1) { - // int_result = sqlite3_exec( - // _session->db, - // "alter table identity\n" - // " add column flags integer default 0;\n", - // NULL, - // NULL, - // NULL - // ); - // assert(int_result == SQLITE_OK); - // } - - if (version < 2) { - // N.B. addition of device_group column removed in DDL v10 - int_result = sqlite3_exec( - _session->db, - "alter table pgp_keypair\n" - " add column flags integer default 0;\n", - // "alter table person\n" - // " add column device_group text;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - if (version < 5) { - int_result = sqlite3_exec( - _session->db, - "delete from pgp_keypair where fpr = '';", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - int_result = sqlite3_exec( - _session->db, - "delete from trust where pgp_keypair_fpr = '';", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - if (version < 6) { - int_result = sqlite3_exec( - _session->db, - "alter table identity\n" - " add column is_own integer default 0;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - int_result = sqlite3_exec( - _session->db, - "update identity\n" - " set is_own = 1\n" - " where (user_id = '" PEP_OWN_USERID "');\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // Turns out that just adding "on update cascade" in - // sqlite is a PITA. We need to be able to cascade - // person->id replacements (for temp ids like "TOFU_") - // so here we go... - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _identity_new (\n" - " address text,\n" - " user_id text\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " comment text,\n" - " flags integer default 0,\n" - " is_own integer default 0,\n" - " primary key (address, user_id)\n" - ");\n" - "INSERT INTO _identity_new SELECT * FROM identity;\n" - "DROP TABLE identity;\n" - "ALTER TABLE _identity_new RENAME TO identity;\n" - "COMMIT;\n" - "\n" - "BEGIN TRANSACTION;\n" - "create table _trust_new (\n" - " user_id text not null\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " pgp_keypair_fpr text not null\n" - " references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " comm_type integer not null,\n" - " comment text,\n" - " primary key (user_id, pgp_keypair_fpr)\n" - ");\n" - "INSERT INTO _trust_new SELECT * FROM trust;\n" - "DROP TABLE trust;\n" - "ALTER TABLE _trust_new RENAME TO trust;\n" - "COMMIT;\n" - "\n" - "PRAGMA foreign_keys=on;\n" - "create table if not exists alternate_user_id (\n" - " default_id text references person (id)\n" - " on delete cascade on update cascade,\n" - " alternate_id text primary key\n" - ");\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_key_check;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // FIXME: foreign key check here - } - if (version < 7) { - int_result = sqlite3_exec( - _session->db, - "alter table person\n" - " add column is_pEp_user integer default 0;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - int_result = sqlite3_exec( - _session->db, - "update person\n" - " set is_pEp_user = 1\n" - " where id = " - " (select distinct id from person " - " join trust on id = user_id " - " where (case when (comm_type = 127) then (id) " - " when (comm_type = 255) then (id) " - " else 0" - " end) = id );\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "create table if not exists mistrusted_keys (\n" - " fpr text primary key\n" - ");\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - if (version < 8) { - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _identity_new (\n" - " address text,\n" - " user_id text\n" - " references person (id)\n" - " on delete cascade on update cascade,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " comment text,\n" - " flags integer default 0,\n" - " is_own integer default 0,\n" - " timestamp integer default (datetime('now')),\n" - " primary key (address, user_id)\n" - ");\n" - "INSERT INTO _identity_new (address, user_id, main_key_id, " - " comment, flags, is_own) " - " SELECT identity.address, identity.user_id, " - " identity.main_key_id, identity.comment, " - " identity.flags, identity.is_own " - " FROM identity " - " WHERE 1;\n" - "DROP TABLE identity;\n" - "ALTER TABLE _identity_new RENAME TO identity;\n" - "COMMIT;\n" - "\n" - "PRAGMA foreign_keys=on;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_key_check;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // FIXME: foreign key check - } - if (version < 9) { - int_result = sqlite3_exec( - _session->db, - "create table if not exists social_graph (\n" - " own_userid text,\n" - " own_address text,\n" - " contact_userid text,\n" - " CONSTRAINT fk_own_identity\n" - " FOREIGN KEY(own_address, own_userid)\n" - " REFERENCES identity(address, user_id)\n" - " ON DELETE CASCADE ON UPDATE CASCADE\n" - ");\n" - "create table if not exists revocation_contact_list (\n" - " fpr text not null references pgp_keypair (fpr)\n" - " on delete cascade,\n" - " contact_id text not null references person (id)\n" - " on delete cascade on update cascade,\n" - " timestamp integer default (datetime('now')),\n" - " PRIMARY KEY(fpr, contact_id)\n" - ");\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - if (version < 10 && version > 1) { - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_keys=off;\n" - "BEGIN TRANSACTION;\n" - "create table _person_new (\n" - " id text primary key,\n" - " username text not null,\n" - " main_key_id text\n" - " references pgp_keypair (fpr)\n" - " on delete set null,\n" - " lang text,\n" - " comment text,\n" - " is_pEp_user integer default 0\n" - ");\n" - "INSERT INTO _person_new (id, username, main_key_id, " - " lang, comment, is_pEp_user) " - " SELECT person.id, person.username, " - " person.main_key_id, person.lang, " - " person.comment, person.is_pEp_user " - " FROM person " - " WHERE 1;\n" - "DROP TABLE person;\n" - "ALTER TABLE _person_new RENAME TO person;\n" - "COMMIT;\n" - "\n" - "PRAGMA foreign_keys=on;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - int_result = sqlite3_exec( - _session->db, - "PRAGMA foreign_key_check;\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - if (version < 11) { - status = repair_altered_tables(_session); - assert(status == PEP_STATUS_OK); - if (status != PEP_STATUS_OK) - return status; - } - if (version < 12) { - int_result = sqlite3_exec( - _session->db, - "create index if not exists identity_userid_addr on identity(address, user_id);\n" - , - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_exec( - _session->db, - "alter table identity\n" - " add column pEp_version_major integer default 0;\n" - "alter table identity\n" - " add column pEp_version_minor integer default 0;\n", - NULL, - NULL, - NULL - ); - if (status != PEP_STATUS_OK) - return status; - - int_result = sqlite3_exec( - _session->db, - "update identity\n" - " set pEp_version_major = 2\n" - " where exists (select * from person\n" - " where identity.user_id = person.id\n" - " and identity.is_own = 0\n" - " and person.is_pEp_user = 1);\n", - NULL, - NULL, - NULL - ); - if (status != PEP_STATUS_OK) - return status; - - // N.B. WE DEFINE PEP_VERSION - IF WE'RE AT 9-DIGIT MAJOR OR MINOR VERSIONS, ER, BAD. - char major_buf[10]; - char minor_buf[10]; - - // Guess we were abusing sscanf here, so we'll do it this way: - const char* cptr = PEP_VERSION; - size_t major_len = 0; - size_t minor_len = 0; - - char* bufptr = major_buf; - while (*cptr != '.' && *cptr != '\0') { - *bufptr++ = *cptr++; - major_len++; - } - *bufptr = '\0'; - bufptr = minor_buf; - - if (*cptr == '.') { - cptr++; - while (*cptr != '\0') { - *bufptr++ = *cptr++; - minor_len++; - } - } - else { - *bufptr++ = '0'; - } - *bufptr = '\0'; - - const char* _ver_12_startstr = - "update identity\n" - " set pEp_version_major = "; - const char* _ver_12_midstr = ",\n" - " pEp_version_minor = "; - const char* _ver_12_endstr = - "\n" - " where identity.is_own = 1;\n"; - - size_t new_stringlen = strlen(_ver_12_startstr) + major_len + - strlen(_ver_12_midstr) + minor_len + - strlen(_ver_12_endstr); - - char* _ver_12_stmt = calloc(new_stringlen + 1, 1); - snprintf(_ver_12_stmt, new_stringlen + 1, "%s%s%s%s%s", - _ver_12_startstr, major_buf, _ver_12_midstr, minor_buf, _ver_12_endstr); - - int_result = sqlite3_exec( - _session->db, - _ver_12_stmt, - NULL, - NULL, - NULL - ); - free(_ver_12_stmt); - if (status != PEP_STATUS_OK) - return status; - } - if (version < 13) { - status = upgrade_revoc_contact_to_13(_session); - assert(status == PEP_STATUS_OK); - if (status != PEP_STATUS_OK) - return status; - } - if (version < 14) { - int_result = sqlite3_exec( - _session->db, - "alter table identity\n" - " add column enc_format integer default 0;\n", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - } - else { - // Version from DB was 0, it means this is initial setup. - // DB has just been created, and all tables are empty. - very_first = true; - } - - if (version < atoi(_DDL_USER_VERSION)) { - int_result = sqlite3_exec( - _session->db, - "pragma user_version = "_DDL_USER_VERSION";\n" - "insert or replace into version_info (id, version)" - "values (1, '" PEP_ENGINE_VERSION "');", - NULL, - NULL, - NULL - ); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - } - - // We need to init a few globals for message id that we'd rather not - // calculate more than once. - _init_globals(); - } - - int_result = sqlite3_prepare_v2(_session->db, sql_log, - (int)strlen(sql_log), &_session->log, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->system_db, sql_trustword, - (int)strlen(sql_trustword), &_session->trustword, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identity, - (int)strlen(sql_get_identity), &_session->get_identity, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identity_without_trust_check, - (int)strlen(sql_get_identity_without_trust_check), - &_session->get_identity_without_trust_check, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_address, - (int)strlen(sql_get_identities_by_address), - &_session->get_identities_by_address, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_userid, - (int)strlen(sql_get_identities_by_userid), - &_session->get_identities_by_userid, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_identities_by_main_key_id, - (int)strlen(sql_get_identities_by_main_key_id), - &_session->get_identities_by_main_key_id, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_user_default_key, - (int)strlen(sql_get_user_default_key), &_session->get_user_default_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_all_keys_for_user, - (int)strlen(sql_get_all_keys_for_user), &_session->get_all_keys_for_user, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_default_own_userid, - (int)strlen(sql_get_default_own_userid), &_session->get_default_own_userid, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_userid_alias_default, - (int)strlen(sql_get_userid_alias_default), &_session->get_userid_alias_default, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_add_userid_alias, - (int)strlen(sql_add_userid_alias), &_session->add_userid_alias, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_replace_userid, - (int)strlen(sql_replace_userid), &_session->replace_userid, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_delete_key, - (int)strlen(sql_delete_key), &_session->delete_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_replace_main_user_fpr, - (int)strlen(sql_replace_main_user_fpr), &_session->replace_main_user_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_replace_main_user_fpr_if_equal, - (int)strlen(sql_replace_main_user_fpr_if_equal), &_session->replace_main_user_fpr_if_equal, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_main_user_fpr, - (int)strlen(sql_get_main_user_fpr), &_session->get_main_user_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_refresh_userid_default_key, - (int)strlen(sql_refresh_userid_default_key), &_session->refresh_userid_default_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_replace_identities_fpr, - (int)strlen(sql_replace_identities_fpr), - &_session->replace_identities_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_remove_fpr_as_identity_default, - (int)strlen(sql_remove_fpr_as_identity_default), - &_session->remove_fpr_as_identity_default, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_remove_fpr_as_user_default, - (int)strlen(sql_remove_fpr_as_user_default), - &_session->remove_fpr_as_user_default, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_person, - (int)strlen(sql_set_person), &_session->set_person, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_person, - (int)strlen(sql_update_person), &_session->update_person, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_delete_person, - (int)strlen(sql_delete_person), &_session->delete_person, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_exists_person, - (int)strlen(sql_exists_person), &_session->exists_person, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_as_pEp_user, - (int)strlen(sql_set_as_pEp_user), &_session->set_as_pEp_user, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_is_pEp_user, - (int)strlen(sql_is_pEp_user), &_session->is_pEp_user, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_add_into_social_graph, - (int)strlen(sql_add_into_social_graph), &_session->add_into_social_graph, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_get_own_address_binding_from_contact, - (int)strlen(sql_get_own_address_binding_from_contact), - &_session->get_own_address_binding_from_contact, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_set_revoke_contact_as_notified, - (int)strlen(sql_set_revoke_contact_as_notified), - &_session->set_revoke_contact_as_notified, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_get_contacted_ids_from_revoke_fpr, - (int)strlen(sql_get_contacted_ids_from_revoke_fpr), - &_session->get_contacted_ids_from_revoke_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_was_id_for_revoke_contacted, - (int)strlen(sql_was_id_for_revoke_contacted), - &_session->was_id_for_revoke_contacted, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_has_id_contacted_address, - (int)strlen(sql_has_id_contacted_address), - &_session->has_id_contacted_address, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_get_last_contacted, - (int)strlen(sql_get_last_contacted), - &_session->get_last_contacted, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, - sql_get_own_address_binding_from_contact, - (int)strlen(sql_get_own_address_binding_from_contact), - &_session->get_own_address_binding_from_contact, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_pgp_keypair, - (int)strlen(sql_set_pgp_keypair), &_session->set_pgp_keypair, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_identity_entry, - (int)strlen(sql_set_identity_entry), &_session->set_identity_entry, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_identity_entry, - (int)strlen(sql_update_identity_entry), &_session->update_identity_entry, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_exists_identity_entry, - (int)strlen(sql_exists_identity_entry), &_session->exists_identity_entry, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_identity_flags, - (int)strlen(sql_set_identity_flags), &_session->set_identity_flags, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_unset_identity_flags, - (int)strlen(sql_unset_identity_flags), &_session->unset_identity_flags, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_ident_enc_format, - (int)strlen(sql_set_ident_enc_format), &_session->set_ident_enc_format, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_pEp_version, - (int)strlen(sql_set_pEp_version), &_session->set_pEp_version, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_upgrade_pEp_version_by_user_id, - (int)strlen(sql_upgrade_pEp_version_by_user_id), &_session->upgrade_pEp_version_by_user_id, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_clear_trust_info, - (int)strlen(sql_clear_trust_info), &_session->clear_trust_info, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_set_trust, - (int)strlen(sql_set_trust), &_session->set_trust, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_trust, - (int)strlen(sql_update_trust), &_session->update_trust, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_trust_to_pEp, - (int)strlen(sql_update_trust_to_pEp), &_session->update_trust_to_pEp, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_exists_trust_entry, - (int)strlen(sql_exists_trust_entry), &_session->exists_trust_entry, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_update_trust_for_fpr, - (int)strlen(sql_update_trust_for_fpr), &_session->update_trust_for_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_trust, - (int)strlen(sql_get_trust), &_session->get_trust, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_trust_by_userid, - (int)strlen(sql_get_trust_by_userid), &_session->get_trust_by_userid, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_least_trust, - (int)strlen(sql_least_trust), &_session->least_trust, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_mark_as_compromised, - (int)strlen(sql_mark_as_compromised), &_session->mark_compromised, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_crashdump, - (int)strlen(sql_crashdump), &_session->crashdump, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->system_db, sql_languagelist, - (int)strlen(sql_languagelist), &_session->languagelist, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->system_db, sql_i18n_token, - (int)strlen(sql_i18n_token), &_session->i18n_token, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // blacklist - - int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_add, - (int)strlen(sql_blacklist_add), &_session->blacklist_add, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_delete, - (int)strlen(sql_blacklist_delete), &_session->blacklist_delete, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_is_listed, - (int)strlen(sql_blacklist_is_listed), - &_session->blacklist_is_listed, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - +DYNAMIC_API PEP_STATUS init( + PEP_SESSION *session, + messageToSend_t messageToSend, + inject_sync_event_t inject_sync_event, + ensure_passphrase_t ensure_passphrase + ) +{ + PEP_STATUS status = PEP_STATUS_OK; - int_result = sqlite3_prepare_v2(_session->db, sql_blacklist_retrieve, - (int)strlen(sql_blacklist_retrieve), &_session->blacklist_retrieve, - NULL); - assert(int_result == SQLITE_OK); + bool in_first = false; - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; + assert(sqlite3_threadsafe()); + if (!sqlite3_threadsafe()) + return PEP_INIT_SQLITE3_WITHOUT_MUTEX; + // a little race condition - but still a race condition + // mitigated by calling caveat (see documentation) - // Own keys + // this increment is made atomic IN THE ADAPTERS by + // guarding the call to init with the appropriate mutex. + int _count = ++init_count; + if (_count == 0) + in_first = true; - int_result = sqlite3_prepare_v2(_session->db, sql_own_key_is_listed, - (int)strlen(sql_own_key_is_listed), &_session->own_key_is_listed, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_is_own_address, - (int)strlen(sql_is_own_address), &_session->is_own_address, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_own_identities_retrieve, - (int)strlen(sql_own_identities_retrieve), - &_session->own_identities_retrieve, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_own_keys_retrieve, - (int)strlen(sql_own_keys_retrieve), - &_session->own_keys_retrieve, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - // int_result = sqlite3_prepare_v2(_session->db, sql_set_own_key, - // (int)strlen(sql_set_own_key), - // &_session->set_own_key, NULL); - // assert(int_result == SQLITE_OK); - - - // Sequence - - int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value1, - (int)strlen(sql_sequence_value1), &_session->sequence_value1, - NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - + // Race condition mitigated by calling caveat starts here : + // If another call to init() preempts right now, then preemptive call + // will have in_first false, will not create SQL tables, and following + // calls relying on those tables will fail. + // + // Therefore, as above, adapters MUST guard init() with a mutex. + // + // Therefore, first session + // is to be created and last session to be deleted alone, and not + // concurently to other sessions creation or deletion. + // We expect adapters to enforce this either by implicitely creating a + // client session, or by using synchronization primitive to protect + // creation/deletion of first/last session from the app. - int_result = sqlite3_prepare_v2(_session->db, sql_sequence_value2, - (int)strlen(sql_sequence_value2), &_session->sequence_value2, - NULL); - assert(int_result == SQLITE_OK); + if (session == NULL) + return PEP_ILLEGAL_VALUE; - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; + *session = NULL; + pEpSession *_session = calloc(1, sizeof(pEpSession)); + assert(_session); + if (_session == NULL) + goto enomem; - // Revocation tracking + _session->version = PEP_ENGINE_VERSION; + _session->messageToSend = messageToSend; + _session->inject_sync_event = inject_sync_event; + _session->ensure_passphrase = ensure_passphrase; - int_result = sqlite3_prepare_v2(_session->db, sql_set_revoked, - (int)strlen(sql_set_revoked), &_session->set_revoked, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_revoked, - (int)strlen(sql_get_revoked), &_session->get_revoked, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_get_replacement_fpr, - (int)strlen(sql_get_replacement_fpr), &_session->get_replacement_fpr, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_add_mistrusted_key, - (int)strlen(sql_add_mistrusted_key), &_session->add_mistrusted_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; - - - int_result = sqlite3_prepare_v2(_session->db, sql_delete_mistrusted_key, - (int)strlen(sql_delete_mistrusted_key), &_session->delete_mistrusted_key, NULL); - assert(int_result == SQLITE_OK); - - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; + status = init_databases(_session); + if (status != PEP_STATUS_OK) + return status; + if (in_first) { - int_result = sqlite3_prepare_v2(_session->db, sql_is_mistrusted_key, - (int)strlen(sql_is_mistrusted_key), &_session->is_mistrusted_key, NULL); - assert(int_result == SQLITE_OK); + status = pEp_sql_init(_session); - if (int_result != SQLITE_OK) - return PEP_UNKNOWN_DB_ERROR; + // We need to init a few globals for message id that we'd rather not + // calculate more than once. + _init_globals(); + } + status = pEp_prepare_sql_stmts(_session); + if (status != PEP_STATUS_OK) + goto pEp_error; status = init_cryptotech(_session, in_first); if (status != PEP_STATUS_OK) @@ -2623,151 +146,7 @@ DYNAMIC_API void release(PEP_SESSION session) free_Sync_state(session); if (session->db) { - if (session->log) - sqlite3_finalize(session->log); - if (session->trustword) - sqlite3_finalize(session->trustword); - if (session->get_identity) - sqlite3_finalize(session->get_identity); - if (session->get_identity_without_trust_check) - sqlite3_finalize(session->get_identity_without_trust_check); - if (session->get_identities_by_address) - sqlite3_finalize(session->get_identities_by_address); - if (session->get_identities_by_userid) - sqlite3_finalize(session->get_identities_by_userid); - if (session->get_identities_by_main_key_id) - sqlite3_finalize(session->get_identities_by_main_key_id); - if (session->get_user_default_key) - sqlite3_finalize(session->get_user_default_key); - if (session->get_all_keys_for_user) - sqlite3_finalize(session->get_all_keys_for_user); - if (session->get_default_own_userid) - sqlite3_finalize(session->get_default_own_userid); - if (session->get_userid_alias_default) - sqlite3_finalize(session->get_userid_alias_default); - if (session->add_userid_alias) - sqlite3_finalize(session->add_userid_alias); - if (session->replace_identities_fpr) - sqlite3_finalize(session->replace_identities_fpr); - if (session->remove_fpr_as_identity_default) - sqlite3_finalize(session->remove_fpr_as_identity_default); - if (session->remove_fpr_as_user_default) - sqlite3_finalize(session->remove_fpr_as_user_default); - if (session->set_person) - sqlite3_finalize(session->set_person); - if (session->delete_person) - sqlite3_finalize(session->delete_person); - if (session->set_as_pEp_user) - sqlite3_finalize(session->set_as_pEp_user); - if (session->upgrade_pEp_version_by_user_id) - sqlite3_finalize(session->upgrade_pEp_version_by_user_id); - if (session->is_pEp_user) - sqlite3_finalize(session->is_pEp_user); - if (session->exists_person) - sqlite3_finalize(session->exists_person); - if (session->add_into_social_graph) - sqlite3_finalize(session->add_into_social_graph); - if (session->get_own_address_binding_from_contact) - sqlite3_finalize(session->get_own_address_binding_from_contact); - if (session->set_revoke_contact_as_notified) - sqlite3_finalize(session->set_revoke_contact_as_notified); - if (session->get_contacted_ids_from_revoke_fpr) - sqlite3_finalize(session->get_contacted_ids_from_revoke_fpr); - if (session->was_id_for_revoke_contacted) - sqlite3_finalize(session->was_id_for_revoke_contacted); - if (session->has_id_contacted_address) - sqlite3_finalize(session->has_id_contacted_address); - if (session->get_last_contacted) - sqlite3_finalize(session->get_last_contacted); - if (session->set_pgp_keypair) - sqlite3_finalize(session->set_pgp_keypair); - if (session->exists_identity_entry) - sqlite3_finalize(session->exists_identity_entry); - if (session->set_identity_entry) - sqlite3_finalize(session->set_identity_entry); - if (session->update_identity_entry) - sqlite3_finalize(session->update_identity_entry); - if (session->set_identity_flags) - sqlite3_finalize(session->set_identity_flags); - if (session->unset_identity_flags) - sqlite3_finalize(session->unset_identity_flags); - if (session->set_ident_enc_format) - sqlite3_finalize(session->set_ident_enc_format); - if (session->set_pEp_version) - sqlite3_finalize(session->set_pEp_version); - if (session->exists_trust_entry) - sqlite3_finalize(session->exists_trust_entry); - if (session->clear_trust_info) - sqlite3_finalize(session->clear_trust_info); - if (session->set_trust) - sqlite3_finalize(session->set_trust); - if (session->update_trust) - sqlite3_finalize(session->update_trust); - if (session->update_trust_to_pEp) - sqlite3_finalize(session->update_trust_to_pEp); - if (session->update_trust_for_fpr) - sqlite3_finalize(session->update_trust_for_fpr); - if (session->get_trust) - sqlite3_finalize(session->get_trust); - if (session->get_trust_by_userid) - sqlite3_finalize(session->get_trust_by_userid); - if (session->least_trust) - sqlite3_finalize(session->least_trust); - if (session->mark_compromised) - sqlite3_finalize(session->mark_compromised); - if (session->crashdump) - sqlite3_finalize(session->crashdump); - if (session->languagelist) - sqlite3_finalize(session->languagelist); - if (session->i18n_token) - sqlite3_finalize(session->i18n_token); - if (session->replace_userid) - sqlite3_finalize(session->replace_userid); - if (session->delete_key) - sqlite3_finalize(session->delete_key); - if (session->replace_main_user_fpr) - sqlite3_finalize(session->replace_main_user_fpr); - if (session->replace_main_user_fpr_if_equal) - sqlite3_finalize(session->replace_main_user_fpr_if_equal); - if (session->get_main_user_fpr) - sqlite3_finalize(session->get_main_user_fpr); - if (session->refresh_userid_default_key) - sqlite3_finalize(session->refresh_userid_default_key); - if (session->blacklist_add) - sqlite3_finalize(session->blacklist_add); - if (session->blacklist_delete) - sqlite3_finalize(session->blacklist_delete); - if (session->blacklist_is_listed) - sqlite3_finalize(session->blacklist_is_listed); - if (session->blacklist_retrieve) - sqlite3_finalize(session->blacklist_retrieve); - if (session->own_key_is_listed) - sqlite3_finalize(session->own_key_is_listed); - if (session->is_own_address) - sqlite3_finalize(session->is_own_address); - if (session->own_identities_retrieve) - sqlite3_finalize(session->own_identities_retrieve); - if (session->own_keys_retrieve) - sqlite3_finalize(session->own_keys_retrieve); - // if (session->set_own_key) - // sqlite3_finalize(session->set_own_key); - if (session->sequence_value1) - sqlite3_finalize(session->sequence_value1); - if (session->sequence_value2) - sqlite3_finalize(session->sequence_value2); - if (session->set_revoked) - sqlite3_finalize(session->set_revoked); - if (session->get_revoked) - sqlite3_finalize(session->get_revoked); - if (session->get_replacement_fpr) - sqlite3_finalize(session->get_replacement_fpr); - if (session->add_mistrusted_key) - sqlite3_finalize(session->add_mistrusted_key); - if (session->delete_mistrusted_key) - sqlite3_finalize(session->delete_mistrusted_key); - if (session->is_mistrusted_key) - sqlite3_finalize(session->is_mistrusted_key); - + pEp_finalize_sql_stmts(session); if (session->db) { if (out_last) { sqlite3_exec( diff --git a/src/pEp_internal.h b/src/pEp_internal.h index 7be2446ac..8deb97898 100644 --- a/src/pEp_internal.h +++ b/src/pEp_internal.h @@ -22,6 +22,7 @@ #include "commit_hash.h" // We need this everywhere. So. + // maximum attachment size to import as key 25MB, maximum of 20 attachments #define MAX_KEY_SIZE (25 * 1024 * 1024) #define MAX_KEYS_TO_IMPORT 20 @@ -121,6 +122,9 @@ #include "pgp_sequoia_internal.h" #endif +#include "../asn.1/Distribution.h" +#include "../asn.1/Sync.h" + #include "keymanagement.h" #include "cryptotech.h" #include "transport.h" @@ -250,6 +254,26 @@ struct _pEpSession { sqlite3_stmt *get_default_own_userid; + // groups + sqlite3_stmt *create_group; + sqlite3_stmt *enable_group; + sqlite3_stmt *disable_group; + sqlite3_stmt *exists_group_entry; + sqlite3_stmt *group_add_member; + sqlite3_stmt *join_group; + sqlite3_stmt *leave_group; + sqlite3_stmt *set_group_member_status; + sqlite3_stmt *get_all_members; + sqlite3_stmt *get_active_members; + sqlite3_stmt *get_active_groups; + sqlite3_stmt *get_all_groups; + sqlite3_stmt *add_own_membership_entry; + sqlite3_stmt *get_own_membership_status; + sqlite3_stmt *retrieve_own_membership_info_for_group_and_ident; + sqlite3_stmt *retrieve_own_membership_info_for_group; + sqlite3_stmt *get_group_manager; + sqlite3_stmt *is_invited_group_member; + sqlite3_stmt *is_group_active; // sqlite3_stmt *set_own_key; @@ -749,16 +773,20 @@ extern double _pEp_log2_36; /** * - * + * + * @internal + * * @brief TODO * - * + * Please leave _patch_asn1_codec COMMENTED OUT unless you're working + * in a branch or patching the asn1 is a solution */ static inline void _init_globals() { _pEp_rand_max_bits = (int) ceil(log2((double) RAND_MAX)); _pEp_log2_36 = log2(36); } + // spinlock implementation /** @@ -778,4 +806,20 @@ static inline int Sqlite3_step(sqlite3_stmt* stmt) return rc; } +/** + * @internal + * + * + * + * @brief TODO + * + * @param[in] *msg message + * + */ +static inline void _add_auto_consume(message* msg) { + add_opt_field(msg, "pEp-auto-consume", "yes"); + msg->in_reply_to = stringlist_add(msg->in_reply_to, "pEp-auto-consume@pEp.foundation"); +} + + #endif