23 #include "mrmailbox_internal.h" 47 void mrsqlite3_log_error(mrsqlite3_t* ths,
const char* msg_format, ...)
50 const char* notSetUp =
"SQLite object not set up.";
53 va_start(va, msg_format);
54 msg = sqlite3_vmprintf(msg_format, va);
if( msg == NULL ) { mrmailbox_log_error(ths->m_mailbox, 0,
"Bad log format string \"%s\".", msg_format); }
55 mrmailbox_log_error(ths->m_mailbox, 0,
"%s SQLite says: %s", msg, ths->m_cobj? sqlite3_errmsg(ths->m_cobj) : notSetUp);
61 sqlite3_stmt* mrsqlite3_prepare_v2_(mrsqlite3_t* ths,
const char* querystr)
63 sqlite3_stmt* retStmt = NULL;
65 if( ths == NULL || querystr == NULL || ths->m_cobj == NULL ) {
69 if( sqlite3_prepare_v2(ths->m_cobj,
74 mrsqlite3_log_error(ths,
"Query failed: %s", querystr);
83 int mrsqlite3_execute__(mrsqlite3_t* ths,
const char* querystr)
86 sqlite3_stmt* stmt = NULL;
89 stmt = mrsqlite3_prepare_v2_(ths, querystr);
94 sqlState = sqlite3_step(stmt);
95 if( sqlState != SQLITE_DONE && sqlState != SQLITE_ROW ) {
96 mrsqlite3_log_error(ths,
"Cannot excecute \"%s\".", querystr);
104 sqlite3_finalize(stmt);
117 mrsqlite3_t* ths = NULL;
120 if( (ths=calloc(1,
sizeof(mrsqlite3_t)))==NULL ) {
124 ths->m_mailbox = mailbox;
126 for( i = 0; i < PREDEFINED_CNT; i++ ) {
130 pthread_mutex_init(&ths->m_critical_, NULL);
136 void mrsqlite3_unref(mrsqlite3_t* ths)
143 pthread_mutex_lock(&ths->m_critical_);
144 mrsqlite3_close__(ths);
145 pthread_mutex_unlock(&ths->m_critical_);
148 pthread_mutex_destroy(&ths->m_critical_);
153 int mrsqlite3_open__(mrsqlite3_t* ths,
const char* dbfile,
int flags)
155 if( ths == NULL || dbfile == NULL ) {
160 mrmailbox_log_error(ths->m_mailbox, 0,
"Cannot open, database \"%s\" already opend.", dbfile);
164 if( sqlite3_open(dbfile, &ths->m_cobj) != SQLITE_OK ) {
165 mrsqlite3_log_error(ths,
"Cannot open database \"%s\".", dbfile);
169 if( !(flags&MR_OPEN_READONLY) )
172 if( !mrsqlite3_table_exists__(ths,
"config") )
174 mrmailbox_log_info(ths->m_mailbox, 0,
"First time init: creating tables in \"%s\".", dbfile);
176 mrsqlite3_execute__(ths,
"CREATE TABLE config (id INTEGER PRIMARY KEY, keyname TEXT, value TEXT);");
177 mrsqlite3_execute__(ths,
"CREATE INDEX config_index1 ON config (keyname);");
179 mrsqlite3_execute__(ths,
"CREATE TABLE contacts (id INTEGER PRIMARY KEY," 180 " name TEXT DEFAULT ''," 181 " addr TEXT DEFAULT '' COLLATE NOCASE," 182 " origin INTEGER DEFAULT 0," 183 " blocked INTEGER DEFAULT 0," 184 " last_seen INTEGER DEFAULT 0," 185 " param TEXT DEFAULT '');");
186 mrsqlite3_execute__(ths,
"CREATE INDEX contacts_index1 ON contacts (name COLLATE NOCASE);");
187 mrsqlite3_execute__(ths,
"CREATE INDEX contacts_index2 ON contacts (addr COLLATE NOCASE);");
188 mrsqlite3_execute__(ths,
"INSERT INTO contacts (id,name,origin) VALUES (1,'self',262144), (2,'system',262144), (3,'rsvd',262144), (4,'rsvd',262144), (5,'rsvd',262144), (6,'rsvd',262144), (7,'rsvd',262144), (8,'rsvd',262144), (9,'rsvd',262144);");
189 #if !defined(MR_ORIGIN_INTERNAL) || MR_ORIGIN_INTERNAL!=262144 193 mrsqlite3_execute__(ths,
"CREATE TABLE chats (id INTEGER PRIMARY KEY, " 194 " type INTEGER DEFAULT 0," 195 " name TEXT DEFAULT ''," 196 " draft_timestamp INTEGER DEFAULT 0," 197 " draft_txt TEXT DEFAULT ''," 198 " blocked INTEGER DEFAULT 0," 199 " grpid TEXT DEFAULT ''," 200 " param TEXT DEFAULT '');");
201 mrsqlite3_execute__(ths,
"CREATE INDEX chats_index1 ON chats (grpid);");
202 mrsqlite3_execute__(ths,
"CREATE TABLE chats_contacts (chat_id INTEGER, contact_id INTEGER);");
203 mrsqlite3_execute__(ths,
"CREATE INDEX chats_contacts_index1 ON chats_contacts (chat_id);");
204 #if !defined(MR_CHAT_TYPE_NORMAL) || MR_CHAT_TYPE_NORMAL!=100 || MR_CHAT_TYPE_GROUP!=120 || MR_CHAT_ID_DEADDROP!=1 || MR_CHAT_ID_TO_DEADDROP!=2 || MR_CHAT_ID_TRASH!=3 || MR_CHAT_ID_MSGS_IN_CREATION!=4 || MR_CHAT_ID_STARRED!=5 || MR_CHAT_ID_ARCHIVED_LINK!=6 205 mrsqlite3_execute__(ths,
"INSERT INTO chats (id,type,name) VALUES (1,120,'deaddrop'), (2,120,'to_deaddrop'), (3,120,'trash'), (4,120,'msgs_in_creation'), (5,120,'starred'), (6,120,'archivedlink'), (7,100,'rsvd'), (8,100,'rsvd'), (9,100,'rsvd');");
209 mrsqlite3_execute__(ths,
"CREATE TABLE msgs (id INTEGER PRIMARY KEY," 210 " rfc724_mid TEXT DEFAULT ''," 211 " server_folder TEXT DEFAULT ''," 212 " server_uid INTEGER DEFAULT 0," 213 " chat_id INTEGER DEFAULT 0," 214 " from_id INTEGER DEFAULT 0," 215 " to_id INTEGER DEFAULT 0," 216 " timestamp INTEGER DEFAULT 0," 217 " type INTEGER DEFAULT 0," 218 " state INTEGER DEFAULT 0," 219 " msgrmsg INTEGER DEFAULT 1," 220 " bytes INTEGER DEFAULT 0," 221 " txt TEXT DEFAULT ''," 222 " txt_raw TEXT DEFAULT ''," 223 " param TEXT DEFAULT '');");
224 mrsqlite3_execute__(ths,
"CREATE INDEX msgs_index1 ON msgs (rfc724_mid);");
225 mrsqlite3_execute__(ths,
"CREATE INDEX msgs_index2 ON msgs (chat_id);");
226 mrsqlite3_execute__(ths,
"CREATE INDEX msgs_index3 ON msgs (timestamp);");
227 mrsqlite3_execute__(ths,
"CREATE INDEX msgs_index4 ON msgs (state);");
228 mrsqlite3_execute__(ths,
"INSERT INTO msgs (id,msgrmsg,txt) VALUES (1,0,'marker1'), (2,0,'rsvd'), (3,0,'rsvd'), (4,0,'rsvd'), (5,0,'rsvd'), (6,0,'rsvd'), (7,0,'rsvd'), (8,0,'rsvd'), (9,0,'daymarker');");
230 mrsqlite3_execute__(ths,
"CREATE TABLE jobs (id INTEGER PRIMARY KEY," 231 " added_timestamp INTEGER," 232 " desired_timestamp INTEGER DEFAULT 0," 234 " foreign_id INTEGER," 235 " param TEXT DEFAULT '');");
236 mrsqlite3_execute__(ths,
"CREATE INDEX jobs_index1 ON jobs (desired_timestamp);");
238 if( !mrsqlite3_table_exists__(ths,
"config") || !mrsqlite3_table_exists__(ths,
"contacts")
239 || !mrsqlite3_table_exists__(ths,
"chats") || !mrsqlite3_table_exists__(ths,
"chats_contacts")
240 || !mrsqlite3_table_exists__(ths,
"msgs") || !mrsqlite3_table_exists__(ths,
"jobs") )
242 mrsqlite3_log_error(ths,
"Cannot create tables in new database \"%s\".", dbfile);
246 mrsqlite3_set_config_int__(ths,
"dbversion", 0);
250 int dbversion = mrsqlite3_get_config_int__(ths,
"dbversion", 0);
251 #define NEW_DB_VERSION 1 252 if( dbversion < NEW_DB_VERSION )
254 mrsqlite3_execute__(ths,
"CREATE TABLE leftgrps (" 255 " id INTEGER PRIMARY KEY," 256 " grpid TEXT DEFAULT '');");
257 mrsqlite3_execute__(ths,
"CREATE INDEX leftgrps_index1 ON leftgrps (grpid);");
259 dbversion = NEW_DB_VERSION;
260 mrsqlite3_set_config_int__(ths,
"dbversion", NEW_DB_VERSION);
262 #undef NEW_DB_VERSION 264 #define NEW_DB_VERSION 2 265 if( dbversion < NEW_DB_VERSION )
267 mrsqlite3_execute__(ths,
"ALTER TABLE contacts ADD COLUMN authname TEXT DEFAULT '';");
269 dbversion = NEW_DB_VERSION;
270 mrsqlite3_set_config_int__(ths,
"dbversion", NEW_DB_VERSION);
272 #undef NEW_DB_VERSION 274 #define NEW_DB_VERSION 7 275 if( dbversion < NEW_DB_VERSION )
277 mrsqlite3_execute__(ths,
"CREATE TABLE keypairs (" 278 " id INTEGER PRIMARY KEY," 279 " addr TEXT DEFAULT '' COLLATE NOCASE," 280 " is_default INTEGER DEFAULT 0," 283 " created INTEGER DEFAULT 0);");
285 dbversion = NEW_DB_VERSION;
286 mrsqlite3_set_config_int__(ths,
"dbversion", NEW_DB_VERSION);
288 #undef NEW_DB_VERSION 290 #define NEW_DB_VERSION 10 291 if( dbversion < NEW_DB_VERSION )
293 mrsqlite3_execute__(ths,
"CREATE TABLE acpeerstates (" 294 " id INTEGER PRIMARY KEY," 295 " addr TEXT DEFAULT '' COLLATE NOCASE," 296 " last_seen INTEGER DEFAULT 0," 297 " last_seen_autocrypt INTEGER DEFAULT 0," 299 " prefer_encrypted INTEGER DEFAULT 0);");
300 mrsqlite3_execute__(ths,
"CREATE INDEX acpeerstates_index1 ON acpeerstates (addr);");
302 dbversion = NEW_DB_VERSION;
303 mrsqlite3_set_config_int__(ths,
"dbversion", NEW_DB_VERSION);
305 #undef NEW_DB_VERSION 307 #define NEW_DB_VERSION 12 308 if( dbversion < NEW_DB_VERSION )
310 mrsqlite3_execute__(ths,
"CREATE TABLE msgs_mdns (" 312 " contact_id INTEGER);");
313 mrsqlite3_execute__(ths,
"CREATE INDEX msgs_mdns_index1 ON msgs_mdns (msg_id);");
315 dbversion = NEW_DB_VERSION;
316 mrsqlite3_set_config_int__(ths,
"dbversion", NEW_DB_VERSION);
318 #undef NEW_DB_VERSION 320 #define NEW_DB_VERSION 17 321 if( dbversion < NEW_DB_VERSION )
323 mrsqlite3_execute__(ths,
"ALTER TABLE chats ADD COLUMN archived INTEGER DEFAULT 0;");
324 mrsqlite3_execute__(ths,
"CREATE INDEX chats_index2 ON chats (archived);");
325 mrsqlite3_execute__(ths,
"ALTER TABLE msgs ADD COLUMN starred INTEGER DEFAULT 0;");
326 mrsqlite3_execute__(ths,
"CREATE INDEX msgs_index5 ON msgs (starred);");
328 dbversion = NEW_DB_VERSION;
329 mrsqlite3_set_config_int__(ths,
"dbversion", NEW_DB_VERSION);
331 #undef NEW_DB_VERSION 334 mrmailbox_log_info(ths->m_mailbox, 0,
"Opened \"%s\" successfully.", dbfile);
338 mrsqlite3_close__(ths);
343 void mrsqlite3_close__(mrsqlite3_t* ths)
353 for( i = 0; i < PREDEFINED_CNT; i++ ) {
355 sqlite3_finalize(ths->m_pd[i]);
360 sqlite3_close(ths->m_cobj);
364 mrmailbox_log_info(ths->m_mailbox, 0,
"Database closed.");
368 int mrsqlite3_is_open(
const mrsqlite3_t* ths)
370 if( ths == NULL || ths->m_cobj == NULL ) {
377 sqlite3_stmt* mrsqlite3_predefine__(mrsqlite3_t* ths,
size_t idx,
const char* querystr)
383 if( ths == NULL || ths->m_cobj == NULL || idx >= PREDEFINED_CNT ) {
387 if( ths->m_pd[idx] ) {
388 sqlite3_reset(ths->m_pd[idx]);
389 return ths->m_pd[idx];
393 if( querystr == NULL ) {
397 if( sqlite3_prepare_v2(ths->m_cobj,
400 NULL ) != SQLITE_OK )
402 mrsqlite3_log_error(ths,
"Preparing statement \"%s\" failed.", querystr);
406 return ths->m_pd[idx];
410 void mrsqlite3_reset_all_predefinitions(mrsqlite3_t* ths)
413 for( i = 0; i < PREDEFINED_CNT; i++ ) {
415 sqlite3_reset(ths->m_pd[i]);
421 int mrsqlite3_table_exists__(mrsqlite3_t* ths,
const char* name)
424 char* querystr = NULL;
425 sqlite3_stmt* stmt = NULL;
428 if( (querystr=sqlite3_mprintf(
"PRAGMA table_info(%s)", name)) == NULL ) {
429 mrmailbox_log_error(ths->m_mailbox, 0,
"mrsqlite3_table_exists_(): Out of memory.");
433 if( (stmt=mrsqlite3_prepare_v2_(ths, querystr)) == NULL ) {
437 sqlState = sqlite3_step(stmt);
438 if( sqlState == SQLITE_ROW ) {
448 sqlite3_finalize(stmt);
452 sqlite3_free(querystr);
464 int mrsqlite3_set_config__(mrsqlite3_t* ths,
const char* key,
const char* value)
470 mrmailbox_log_error(ths->m_mailbox, 0,
"mrsqlite3_set_config(): Bad parameter.");
474 if( !mrsqlite3_is_open(ths) ) {
475 mrmailbox_log_error(ths->m_mailbox, 0,
"mrsqlite3_set_config(): Database not ready.");
482 #define SELECT_v_FROM_config_k_STATEMENT "SELECT value FROM config WHERE keyname=?;" 483 stmt = mrsqlite3_predefine__(ths, SELECT_v_FROM_config_k, SELECT_v_FROM_config_k_STATEMENT);
484 sqlite3_bind_text (stmt, 1, key, -1, SQLITE_STATIC);
485 state=sqlite3_step(stmt);
486 if( state == SQLITE_DONE ) {
487 stmt = mrsqlite3_predefine__(ths, INSERT_INTO_config_kv,
"INSERT INTO config (keyname, value) VALUES (?, ?);");
488 sqlite3_bind_text (stmt, 1, key, -1, SQLITE_STATIC);
489 sqlite3_bind_text (stmt, 2, value, -1, SQLITE_STATIC);
490 state=sqlite3_step(stmt);
493 else if( state == SQLITE_ROW ) {
494 stmt = mrsqlite3_predefine__(ths, UPDATE_config_vk,
"UPDATE config SET value=? WHERE keyname=?;");
495 sqlite3_bind_text (stmt, 1, value, -1, SQLITE_STATIC);
496 sqlite3_bind_text (stmt, 2, key, -1, SQLITE_STATIC);
497 state=sqlite3_step(stmt);
500 mrmailbox_log_error(ths->m_mailbox, 0,
"mrsqlite3_set_config(): Cannot read value.");
507 stmt = mrsqlite3_predefine__(ths, DELETE_FROM_config_k,
"DELETE FROM config WHERE keyname=?;");
508 sqlite3_bind_text (stmt, 1, key, -1, SQLITE_STATIC);
509 state=sqlite3_step(stmt);
512 if( state != SQLITE_DONE ) {
513 mrmailbox_log_error(ths->m_mailbox, 0,
"mrsqlite3_set_config(): Cannot change value.");
521 char* mrsqlite3_get_config__(mrsqlite3_t* ths,
const char* key,
const char* def)
525 if( !mrsqlite3_is_open(ths) || key == NULL ) {
526 return strdup_keep_null(def);
529 stmt = mrsqlite3_predefine__(ths, SELECT_v_FROM_config_k, SELECT_v_FROM_config_k_STATEMENT);
530 sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC);
531 if( sqlite3_step(stmt) == SQLITE_ROW )
533 const unsigned char* ptr = sqlite3_column_text(stmt, 0);
537 return safe_strdup((
const char*)ptr);
542 return strdup_keep_null(def);
546 int32_t mrsqlite3_get_config_int__(mrsqlite3_t* ths,
const char* key, int32_t def)
548 char* str = mrsqlite3_get_config__(ths, key, NULL);
552 int32_t ret = atol(str);
558 int mrsqlite3_set_config_int__(mrsqlite3_t* ths,
const char* key, int32_t value)
560 char* value_str = mr_mprintf(
"%i", (
int)value);
561 if( value_str == NULL ) {
564 int ret = mrsqlite3_set_config__(ths, key, value_str);
575 void mrsqlite3_lock(mrsqlite3_t* ths)
577 pthread_mutex_lock(&ths->m_critical_);
579 mrmailbox_wake_lock(ths->m_mailbox);
583 void mrsqlite3_unlock(mrsqlite3_t* ths)
585 mrmailbox_wake_unlock(ths->m_mailbox);
587 pthread_mutex_unlock(&ths->m_critical_);
596 void mrsqlite3_begin_transaction__(mrsqlite3_t* ths)
600 ths->m_transactionCount++;
602 if( ths->m_transactionCount == 1 )
604 stmt = mrsqlite3_predefine__(ths, BEGIN_transaction,
"BEGIN;");
605 if( sqlite3_step(stmt) != SQLITE_DONE ) {
606 mrsqlite3_log_error(ths,
"Cannot begin transaction.");
612 void mrsqlite3_rollback__(mrsqlite3_t* ths)
616 if( ths->m_transactionCount >= 1 )
618 if( ths->m_transactionCount == 1 )
620 stmt = mrsqlite3_predefine__(ths, ROLLBACK_transaction,
"ROLLBACK;");
621 if( sqlite3_step(stmt) != SQLITE_DONE ) {
622 mrsqlite3_log_error(ths,
"Cannot rollback transaction.");
626 ths->m_transactionCount--;
631 void mrsqlite3_commit__(mrsqlite3_t* ths)
635 if( ths->m_transactionCount >= 1 )
637 if( ths->m_transactionCount == 1 )
639 stmt = mrsqlite3_predefine__(ths, COMMIT_transaction,
"COMMIT;");
640 if( sqlite3_step(stmt) != SQLITE_DONE ) {
641 mrsqlite3_log_error(ths,
"Cannot commit transaction.");
645 ths->m_transactionCount--;
An object representing a single mailbox.