/* dbRW Copyright 2000-2017 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdafx.h" PLUGININFOEX pluginInfo = { sizeof(PLUGININFOEX), __PLUGIN_NAME, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), __DESCRIPTION, __AUTHOR, __COPYRIGHT, __AUTHORWEB, UNICODE_AWARE, // {F3CA0E5E-249A-40f0-8D74-80A80EF0C83D} {0xf3ca0e5e, 0x249a, 0x40f0, {0x8d, 0x74, 0x80, 0xa8, 0xe, 0xf0, 0xc8, 0x3d}} }; HINSTANCE g_hInst; sqlite3 *g_sqlite; char g_szDbPath[MAX_PATH]; HANDLE hSettingChangeEvent; HANDLE hContactDeletedEvent; HANDLE hContactAddedEvent; HANDLE hEventFilterAddedEvent; HANDLE hEventAddedEvent; HANDLE hEventDeletedEvent; enum { DBRW_TABLE_SETTINGS = 0, DBRW_TABLE_CONTACTS, DBRW_TABLE_EVENTS, DBRW_TABLE_CORE, DBRW_TABLE_COUNT }; char *dbrw_tables[DBRW_TABLE_COUNT] = { "create table dbrw_settings (id integer, module varchar(255), setting varchar(255), type integer, val any, primary key(id,module,setting));", "create table dbrw_contacts (id integer primary key,createtime integer);", "create table dbrw_events (id integer primary key,eventtime integer,flags integer,eventtype integer, blob any, blobsize integer, contactid integer,modulename varchar(255),inserttime integer);", "create table dbrw_core (setting varchar(255) primary key not null, val any);" }; char* utf8_encode(const char* src) { size_t len; char* result; wchar_t* tempBuf; if (src == NULL) return NULL; len = strlen(src); result = (char*)malloc(len * 3 + 1); if (result == NULL) return NULL; tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t)); MultiByteToWideChar(CP_ACP, 0, src, -1, tempBuf, (int)len); tempBuf[len] = 0; { wchar_t* s = tempBuf; BYTE* d = (BYTE*)result; while (*s) { int U = *s++; if (U < 0x80) { *d++ = (BYTE)U; } else if (U < 0x800) { *d++ = 0xC0 + ((U >> 6) & 0x3F); *d++ = 0x80 + (U & 0x003F); } else { *d++ = 0xE0 + (U >> 12); *d++ = 0x80 + ((U >> 6) & 0x3F); *d++ = 0x80 + (U & 0x3F); } } *d = 0; } return result; } static int dbrw_makeDatabase(char *profile, int *error) { sqlite3 *sql = NULL; int rc; char *szPath = utf8_encode(profile); rc = sqlite3_open(szPath, &sql); free(szPath); if (rc == SQLITE_OK) { int x; sqlite3_exec(sql, "PRAGMA page_size = 8192;", NULL, NULL, NULL); for (x = 0; x < DBRW_TABLE_COUNT; x++) { rc = sqlite3_exec(sql, dbrw_tables[x], NULL, NULL, NULL); if (rc != SQLITE_OK) break; } if (rc == SQLITE_OK) { sqlite3_exec(sql, "CREATE INDEX idx_settings1 ON dbrw_settings(id, module, setting);", NULL, NULL, NULL); sqlite3_exec(sql, "CREATE INDEX idx_settings2 ON dbrw_settings(id, module);", NULL, NULL, NULL); sqlite3_exec(sql, "CREATE INDEX idx_settings3 ON dbrw_settings(module);", NULL, NULL, NULL); sqlite3_exec(sql, "CREATE INDEX idx_events1 ON dbrw_events(contactid);", NULL, NULL, NULL); sqlite3_exec(sql, "CREATE INDEX idx_events2 ON dbrw_events(id,contactid);", NULL, NULL, NULL); sqlite3_exec(sql, "INSERT INTO dbrw_core VALUES(\"SchemaVersion\",\"" DBRW_SCHEMA_VERSION "\");", NULL, NULL, NULL); } } sqlite3_close(sql); rc = (rc == SQLITE_OK) ? 0 : 1; if (error != NULL) *error = rc; return rc; } static int dbrw_grokHeader(char *profile, int *error) { HANDLE hFile = CreateFileA(profile, GENERIC_READ, 0, NULL, OPEN_ALWAYS, 0, NULL); int rc = 1; int err = EGROKPRF_CANTREAD; if (hFile != INVALID_HANDLE_VALUE) { BOOL r; char buf[64]; DWORD dwRead; ZeroMemory(buf, sizeof(buf)); r = ReadFile(hFile, buf, sizeof(buf), &dwRead, NULL); CloseHandle(hFile); if (r && memcmp(buf, DBRW_HEADER_STR, strlen(DBRW_HEADER_STR)) == 0) { sqlite3 *sqlcheck = NULL; char *szPath = utf8_encode(profile); rc = sqlite3_open(szPath, &sqlcheck); free(szPath); if (rc == SQLITE_OK) { sqlite3_stmt *stmt; err = EGROKPRF_UNKHEADER; sqlite3_prepare_v2(sqlcheck, "select * from sqlite_master where type = 'table' and name = 'dbrw_core';", -1, &stmt, NULL); if (sqlite3_step(stmt) == SQLITE_ROW) { sqlite3_finalize(stmt); sqlite3_prepare_v2(sqlcheck, "select val from dbrw_core where setting = 'SchemaVersion';", -1, &stmt, NULL); if (sqlite3_step(stmt) == SQLITE_ROW) { int sVersion; sVersion = sqlite3_column_int(stmt, 0); if (sVersion == atoi(DBRW_SCHEMA_VERSION)) rc = 0; else { // TODO: Return as valid and upgrade in // dbrw_Load() if schema version is upgradable } } } sqlite3_finalize(stmt); sqlite3_close(sqlcheck); } } else err = r ? EGROKPRF_UNKHEADER : EGROKPRF_CANTREAD; } if (error != NULL) *error = err; return rc; } static int dbrw_Load(char *profile, void *link) { { char *szLocalPath = mir_utf8encode(profile); mir_snprintf(g_szDbPath, sizeof(g_szDbPath), "%s", szLocalPath); mir_free(szLocalPath); } sql_init(); // intialize sqlite library routines if (sql_open(g_szDbPath, &g_sqlite) != SQLITE_OK) return 1; #ifdef DBRW_LOGGING utils_log_init(); #endif log2("Loading SQLite Driver v%s (SQLite v%s)", DBRW_VER_STRING, SQLITE_VERSION); utils_vacuum_check(); { sql_exec(g_sqlite, "BEGIN TRANSACTION;"); sql_exec(g_sqlite, "PRAGMA locking_mode = EXCLUSIVE;"); sql_exec(g_sqlite, "PRAGMA synchronous = NORMAL;"); sql_exec(g_sqlite, "PRAGMA cache_size = 6000;"); sql_exec(g_sqlite, "PRAGMA temp_store = MEMORY;"); sql_exec(g_sqlite, "COMMIT;"); } // Create Services /*CreateServiceFunction(MS_DB_SETSAFETYMODE, utils_setSafetyMode); CreateServiceFunction(MS_DB_CONTACT_GETSETTING, setting_getSetting); CreateServiceFunction(MS_DB_CONTACT_GETSETTING_STR, setting_getSettingStr); CreateServiceFunction(MS_DB_CONTACT_GETSETTINGSTATIC, setting_getSettingStatic); CreateServiceFunction(MS_DB_CONTACT_FREEVARIANT, setting_freeVariant); CreateServiceFunction(MS_DB_CONTACT_WRITESETTING, setting_writeSetting); CreateServiceFunction(MS_DB_CONTACT_DELETESETTING, setting_deleteSetting); CreateServiceFunction(MS_DB_CONTACT_ENUMSETTINGS, setting_enumSettings); CreateServiceFunction(MS_DB_SETSETTINGRESIDENT, settings_setResident); CreateServiceFunction(MS_DB_CONTACT_GETCOUNT, contacts_getCount); CreateServiceFunction(MS_DB_CONTACT_FINDFIRST, contacts_findFirst); CreateServiceFunction(MS_DB_CONTACT_FINDNEXT, contacts_findNext); CreateServiceFunction(MS_DB_CONTACT_DELETE, contacts_delete); CreateServiceFunction(MS_DB_CONTACT_ADD, contacts_add); CreateServiceFunction(MS_DB_CONTACT_IS, contacts_isContact); CreateServiceFunction(MS_DB_EVENT_GETCOUNT, events_getCount); CreateServiceFunction(MS_DB_EVENT_ADD, events_add); CreateServiceFunction(MS_DB_EVENT_DELETE, events_delete); CreateServiceFunction(MS_DB_EVENT_GETBLOBSIZE, events_getBlobSize); CreateServiceFunction(MS_DB_EVENT_GET, events_get); CreateServiceFunction(MS_DB_EVENT_MARKREAD, events_markRead); CreateServiceFunction(MS_DB_EVENT_GETCONTACT, events_getContact); CreateServiceFunction(MS_DB_EVENT_FINDFIRST, events_findFirst); CreateServiceFunction(MS_DB_EVENT_FINDFIRSTUNREAD, events_findFirstUnread); CreateServiceFunction(MS_DB_EVENT_FINDLAST, events_findLast); CreateServiceFunction(MS_DB_EVENT_FINDNEXT, events_findNext); CreateServiceFunction(MS_DB_EVENT_FINDPREV, events_findPrev); CreateServiceFunction(MS_DB_CRYPT_ENCODESTRING, utils_encodeString); CreateServiceFunction(MS_DB_CRYPT_DECODESTRING, utils_decodeString); CreateServiceFunction(MS_DB_MODULES_ENUM, setting_modulesEnum);*/ // Events Hooks hSettingChangeEvent = CreateHookableEvent(ME_DB_CONTACT_SETTINGCHANGED); hContactDeletedEvent = CreateHookableEvent(ME_DB_CONTACT_DELETED); hContactAddedEvent = CreateHookableEvent(ME_DB_CONTACT_ADDED); hEventFilterAddedEvent = CreateHookableEvent(ME_DB_EVENT_FILTER_ADD); hEventAddedEvent = CreateHookableEvent(ME_DB_EVENT_ADDED); hEventDeletedEvent = CreateHookableEvent(ME_DB_EVENT_DELETED); // Initialize modules contacts_init(); settings_init(); events_init(); // Prepare SQL statements sql_prepare_statements(); return 0; } static int dbrw_Unload(int wasLoaded) { if (!wasLoaded) return 0; events_destroy(); settings_destroy(); contacts_destroy(); sql_close(g_sqlite); sql_destroy(); log0("SQLite Driver unloaded sucessfully"); #ifdef DBRW_LOGGING utils_log_destroy(); #endif return 0; } static DATABASELINK dblink = { sizeof(DATABASELINK), "dbrw", L"dbx SQLite driver", dbrw_makeDatabase, dbrw_grokHeader, dbrw_Load, dbrw_Unload }; ///////////////////////////////////////////////////////////////////////////////////////// BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD, LPVOID) { g_hInst = hInstDLL; return TRUE; } extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) { return &pluginInfo; } extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_DATABASE, MIID_LAST }; extern "C" __declspec(dllexport) int Load(void) { RegisterDatabasePlugin(&dblink); return 1; } extern "C" __declspec(dllexport) int Unload(void) { return 0; }