diff options
Diffstat (limited to 'plugins/MirLua/src/Modules/m_database.cpp')
-rw-r--r-- | plugins/MirLua/src/Modules/m_database.cpp | 691 |
1 files changed, 691 insertions, 0 deletions
diff --git a/plugins/MirLua/src/Modules/m_database.cpp b/plugins/MirLua/src/Modules/m_database.cpp new file mode 100644 index 0000000000..3d0d53ba48 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_database.cpp @@ -0,0 +1,691 @@ +#include "../stdafx.h" + +void luaM_pushdbvt(lua_State *L, const DBVARIANT &value) +{ + switch (value.type) { + case DBVT_BYTE: + lua_pushinteger(L, value.bVal); + break; + case DBVT_WORD: + lua_pushinteger(L,value.wVal); + break; + case DBVT_DWORD: + lua_pushnumber(L, value.dVal); + break; + case DBVT_ASCIIZ: + lua_pushstring(L, ptrA(mir_utf8encode(value.pszVal))); + break; + case DBVT_UTF8: + lua_pushstring(L, value.pszVal); + break; + case DBVT_WCHAR: + lua_pushstring(L, ptrA(mir_utf8encodeW(value.pwszVal))); + break; + case DBVT_BLOB: + { + lua_createtable(L, value.cpbVal, 0); + for (int i = 0; i < value.cpbVal; i++) { + lua_pushinteger(L, value.pbVal[i]); + lua_rawseti(L, -2, i + 1); + } + } + break; + default: + lua_pushnil(L); + } +} + +/***********************************************/ + +static int db_ContactIterator(lua_State *L) +{ + MCONTACT hContact = lua_tointeger(L, lua_upvalueindex(1)); + const char *szModule = lua_tostring(L, lua_upvalueindex(2)); + + hContact = hContact == NULL + ? db_find_first(szModule) + : db_find_next(hContact, szModule); + + if (hContact) { + lua_pushinteger(L, hContact); + lua_pushvalue(L, -1); + lua_replace(L, lua_upvalueindex(1)); + } + else + lua_pushnil(L); + + return 1; +} + +static int db_Contacts(lua_State *L) +{ + const char *szModule = nullptr; + + switch (lua_type(L, 1)) { + case LUA_TNONE: + break; + case LUA_TSTRING: + szModule = lua_tostring(L, 1); + break; + case LUA_TUSERDATA: + { + PROTOACCOUNT **pa = (PROTOACCOUNT**)luaL_checkudata(L, 1, MT_PROTOACCOUNT); + szModule = (*pa)->szModuleName; + break; + } + default: + luaL_argerror(L, 1, luaL_typename(L, 1)); + } + + lua_pushinteger(L, 0); + lua_pushstring(L, szModule); + lua_pushcclosure(L, db_ContactIterator, 2); + + return 1; +} + +static const char *mods[] = +{ + "FirstName", + "LastName", + "Nick", + "CustomNick", + "Email", + "City", + "State", + "Country", + "Phone", + "Homepage", + "About", + "Gender", + "Age", + "FullName", + "Uid", + "DisplayName", + nullptr +}; + +static int db_GetContactInfo(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + int type = 0; + switch (lua_type(L, 2)) { + case LUA_TNUMBER: + type = luaL_checkinteger(L, 2); + break; + case LUA_TSTRING: + type = luaL_checkoption(L, 2, nullptr, mods) + 1; + break; + default: + luaL_argerror(L, 2, luaL_typename(L, 2)); + } + + ptrW value(Contact_GetInfo(type, hContact)); + if (value) + lua_pushstring(L, ptrA(mir_utf8encodeW(value))); + else + lua_pushnil(L); + + return 1; +} + +/***********************************************/ + +static int db_GetEventCount(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + int res = db_event_count(hContact); + lua_pushinteger(L, res); + + return 1; +} + +static int db_GetFirstEvent(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + MEVENT res = db_event_first(hContact); + lua_pushinteger(L, res); + + return 1; +} + +static int db_GetPrevEvent(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + MEVENT hDbEvent = luaL_checkinteger(L, 2); + + MEVENT res = db_event_prev(hContact, hDbEvent); + lua_pushinteger(L, res); + + return 1; +} + +static int db_GetNextEvent(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + MEVENT hDbEvent = luaL_checkinteger(L, 2); + + MEVENT res = db_event_next(hContact, hDbEvent); + lua_pushinteger(L, res); + + return 1; +} + +static int db_GetLastEvent(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + MEVENT res = db_event_last(hContact); + lua_pushinteger(L, res); + + return 1; +} + +static int db_GetFirstUnreadEvent(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + MEVENT res = db_event_firstUnread(hContact); + lua_pushinteger(L, res); + + return 1; +} + +static int db_EventIterator(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, lua_upvalueindex(1)); + MEVENT hDbEvent = luaL_checkinteger(L, lua_upvalueindex(2)); + + hDbEvent = hDbEvent == NULL + ? db_event_first(hContact) + : db_event_next(hContact, hDbEvent); + + if (hDbEvent) { + lua_pushinteger(L, hDbEvent); + lua_pushvalue(L, -1); + lua_replace(L, lua_upvalueindex(2)); + } + else + lua_pushnil(L); + + return 1; +} + +static int db_Events(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + lua_pushinteger(L, hContact); + lua_pushinteger(L, NULL); + lua_pushcclosure(L, db_EventIterator, 2); + + return 1; +} + +static int db_EventReverseIterator(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, lua_upvalueindex(1)); + MEVENT hDbEvent = luaL_checkinteger(L, lua_upvalueindex(2)); + + hDbEvent = hDbEvent == NULL + ? db_event_last(hContact) + : db_event_prev(hContact, hDbEvent); + + if (hDbEvent) { + lua_pushinteger(L, hDbEvent); + lua_pushvalue(L, -1); + lua_replace(L, lua_upvalueindex(2)); + } + else + lua_pushnil(L); + + return 1; +} + +static int db_EventsFromEnd(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + lua_pushinteger(L, hContact); + lua_pushinteger(L, NULL); + lua_pushcclosure(L, db_EventReverseIterator, 2); + + return 1; +} + +static int db_UnreadEventIterator(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, lua_upvalueindex(1)); + MEVENT hDbEvent = luaL_checkinteger(L, lua_upvalueindex(2)); + + hDbEvent = db_event_firstUnread(hContact); + + if (hDbEvent) { + lua_pushinteger(L, hDbEvent); + lua_pushvalue(L, -1); + lua_replace(L, lua_upvalueindex(2)); + } + else + lua_pushnil(L); + + return 1; +} + +static int db_UnreadEvents(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + lua_pushinteger(L, hContact); + lua_pushinteger(L, NULL); + lua_pushcclosure(L, db_UnreadEventIterator, 2); + + return 1; +} + +void MakeDbEvent(lua_State *L, DBEVENTINFO &dbei) +{ + lua_getfield(L, -1, "Module"); + dbei.szModule = mir_strdup(lua_tostring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Type"); + dbei.eventType = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "Timestamp"); + dbei.timestamp = lua_tonumber(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "Flags"); + dbei.flags = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "Blob"); + switch (lua_type(L, -1)) { + case LUA_TTABLE: + dbei.cbBlob = (DWORD)lua_rawlen(L, 4); + dbei.pBlob = (BYTE*)mir_calloc(dbei.cbBlob); + for (DWORD i = 0; i < dbei.cbBlob; i++) { + lua_geti(L, 4, i + 1); + dbei.pBlob[i] = lua_tointeger(L, -1); + lua_pop(L, 1); + } + break; + case LUA_TSTRING: + size_t nLen; + const char *str = lua_tolstring(L, -1, &nLen); + dbei.cbBlob = (DWORD)nLen; + dbei.pBlob = (BYTE*)mir_alloc(nLen); + memcpy(dbei.pBlob, str, nLen); + break; + } + lua_pop(L, 1); +} + +static int db_AddEvent(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + + DBEVENTINFO dbei; + MakeDbEvent(L, dbei); + MEVENT hDbEvent = db_event_add(hContact, &dbei); + + if (hDbEvent) + lua_pushnumber(L, hDbEvent); + else + lua_pushnil(L); + + return 1; +} + +static int db_MarkReadEvent(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + MEVENT hDbEvent = luaL_checkinteger(L, 2); + + int res = db_event_markRead(hContact, hDbEvent); + lua_pushnumber(L, res); + + return 1; +} + +/***********************************************/ + +static int ModulesEnumProc(const char *szModuleName, void *lParam) +{ + if (szModuleName) { + LIST<char>* p = (LIST<char>*)lParam; + p->insert(mir_strdup(szModuleName)); + } + + return 0; +} + +static int db_ModulesIterator(lua_State *L) +{ + int i = lua_tointeger(L, lua_upvalueindex(1)); + LIST<char> ¶m = *(LIST<char>*)lua_touserdata(L, lua_upvalueindex(2)); + + if (i < param.getCount()) { + lua_pushinteger(L, (i + 1)); + lua_replace(L, lua_upvalueindex(1)); + lua_pushstring(L, ptrA(mir_utf8encode(param[i]))); + mir_free(param[i]); + } + else { + lua_pushnil(L); + delete ¶m; + } + + return 1; +} + +static int db_Modules(lua_State *L) +{ + LIST<char> *param = new LIST<char>(5, PtrKeySortT); + + db_enum_modules(ModulesEnumProc, param); + + lua_pushinteger(L, 0); + lua_pushlightuserdata(L, param); + lua_pushcclosure(L, db_ModulesIterator, 2); + + return 1; +} + +static int db_DeleteModule(lua_State *L) +{ + MCONTACT hContact = lua_tointeger(L, 1); + const char *szModule = luaL_checkstring(L, 2); + + INT_PTR res = db_delete_module(hContact, szModule); + lua_pushboolean(L, !res); + + return 1; +} + +static int SettingsEnumProc(const char* szSetting, void *lParam) +{ + if (szSetting ) { + LIST<char>* p = (LIST<char>*)lParam; + p->insert(mir_strdup(szSetting)); + } + return 0; +} + +static int db_SettingIterator(lua_State *L) +{ + int i = lua_tointeger(L, lua_upvalueindex(1)); + LIST<char> ¶m = *(LIST<char>*)lua_touserdata(L, lua_upvalueindex(2)); + + if (i < param.getCount()) { + lua_pushinteger(L, (i + 1)); + lua_replace(L, lua_upvalueindex(1)); + lua_pushstring(L, ptrA(mir_utf8encode(param[i]))); + mir_free(param[i]); + } + else { + lua_pushnil(L); + delete ¶m; + } + + return 1; +} + +static int db_Settings(lua_State *L) +{ + MCONTACT hContact = lua_tointeger(L, 1); + const char* szModule = luaL_checkstring(L, 2); + + LIST<char> *param = new LIST<char>(5, PtrKeySortT); + db_enum_settings(hContact, SettingsEnumProc, szModule, param); + + lua_pushinteger(L, 0); + lua_pushlightuserdata(L, param); + lua_pushcclosure(L, db_SettingIterator, 2); + + return 1; +} + +static int db_GetSetting(lua_State *L) +{ + MCONTACT hContact = lua_tointeger(L, 1); + const char *szModule = luaL_checkstring(L, 2); + const char *szSetting = luaL_checkstring(L, 3); + + DBVARIANT dbv; + if (db_get(hContact, szModule, szSetting, &dbv)) { + lua_pushvalue(L, 4); + return 1; + } + + luaM_pushdbvt(L, dbv); + db_free(&dbv); + + if (lua_isnil(L, -1) && !lua_isnoneornil(L, 4)) { + lua_pop(L, 1); + lua_pushvalue(L, 4); + } + + return 1; +} + +static int db_WriteSetting(lua_State *L) +{ + MCONTACT hContact = lua_tointeger(L, 1); + const char *szModule = luaL_checkstring(L, 2); + const char *szSetting = luaL_checkstring(L, 3); + luaL_checkany(L, 4); + + DBVARIANT dbv; + if (lua_isnoneornil(L, 5)) { + int type = lua_type(L, 4); + switch (type) { + case LUA_TBOOLEAN: + dbv.type = DBVT_BYTE; + break; + case LUA_TNUMBER: + dbv.type = DBVT_DWORD; + break; + case LUA_TSTRING: + dbv.type = DBVT_UTF8; + break; + case LUA_TTABLE: + dbv.type = DBVT_BLOB; + break; + default: + lua_pushboolean(L, false); + return 1; + } + } + else + dbv.type = luaL_checkinteger(L, 5); + + switch (dbv.type) { + case DBVT_BYTE: + dbv.bVal = lua_isboolean(L, 4) + ? lua_toboolean(L, 4) + : luaL_checknumber(L, 4); + break; + case DBVT_WORD: + dbv.wVal = luaL_checknumber(L, 4); + break; + case DBVT_DWORD: + dbv.dVal = luaL_checknumber(L, 4); + break; + case DBVT_UTF8: + dbv.pszVal = mir_strdup(luaL_checkstring(L, 4)); + break; + case DBVT_ASCIIZ: + dbv.pszVal = mir_utf8decodeA(luaL_checkstring(L, 4)); + break; + case DBVT_WCHAR: + dbv.pwszVal = mir_utf8decodeW(luaL_checkstring(L, 4)); + break; + case DBVT_BLOB: + { + dbv.cpbVal = (WORD)lua_rawlen(L, 4); + dbv.pbVal = (BYTE*)mir_calloc(dbv.cpbVal); + for (int i = 0; i < dbv.cpbVal; i++) { + lua_geti(L, 4, i + 1); + dbv.pbVal[i] = lua_tointeger(L, -1); + lua_pop(L, 1); + } + } + break; + default: + lua_pushboolean(L, false); + return 1; + } + + INT_PTR res = db_set(hContact, szModule, szSetting, &dbv); + lua_pushboolean(L, !res); + + return 1; +} + +static int db_DeleteSetting(lua_State *L) +{ + MCONTACT hContact = lua_tointeger(L, 1); + LPCSTR szModule = luaL_checkstring(L, 2); + LPCSTR szSetting = luaL_checkstring(L, 3); + + INT_PTR res = db_unset(hContact, szModule, szSetting); + lua_pushboolean(L, !res); + + return 1; +} + +/***********************************************/ + +static luaL_Reg databaseApi[] = +{ + { "Contacts", db_Contacts }, + { "GetContactInfo", db_GetContactInfo }, + + { "GetEventCount", db_GetEventCount }, + + { "GetFirstEvent", db_GetFirstEvent }, + { "GetPrevEvent", db_GetPrevEvent }, + { "GetNextEvent", db_GetNextEvent }, + { "GetLastEvent", db_GetLastEvent }, + { "GetFirstUnreadEvent", db_GetFirstUnreadEvent }, + { "Events", db_Events }, + { "EventsFromEnd", db_EventsFromEnd }, + { "UnreadEvents", db_UnreadEvents }, + { "AddEvent", db_AddEvent }, + { "MarkReadEvent", db_MarkReadEvent }, + + { "Settings", db_Settings }, + { "Modules", db_Modules }, + + { "DeleteModule", db_DeleteModule }, + + { "GetSetting", db_GetSetting }, + { "WriteSetting", db_WriteSetting }, + { "SetSetting", db_WriteSetting }, + { "DeleteSetting", db_DeleteSetting }, + + { "DBVT_BYTE", nullptr }, + { "DBVT_WORD", nullptr }, + { "DBVT_DWORD", nullptr }, + { "DBVT_ASCIIZ", nullptr }, + { "DBVT_UTF8", nullptr }, + { "DBVT_WCHAR", nullptr }, + + { nullptr, nullptr } +}; + +/***********************************************/ + +#define MT_DBCONTACTWRITESETTING "DBCONTACTWRITESETTING" + +template <> +int MT<DBCONTACTWRITESETTING>::Get(lua_State *L, DBCONTACTWRITESETTING *dbcw) +{ + const char *key = luaL_checkstring(L, 2); + + if (mir_strcmpi(key, "Value") == 0) + luaM_pushdbvt(L, dbcw->value); + else + lua_pushnil(L); + + return 1; +} + +/***********************************************/ + +#define MT_DBEVENTINFO "DBEVENTINFO" + +template <> +DBEVENTINFO* MT<DBEVENTINFO>::Init(lua_State *L) +{ + MEVENT hDbEvent = luaL_checkinteger(L, 1); + + DBEVENTINFO* dbei = (DBEVENTINFO*)mir_calloc(sizeof(DBEVENTINFO)); + dbei->cbBlob = db_event_getBlobSize((MEVENT)hDbEvent); + dbei->pBlob = (PBYTE)mir_calloc(dbei->cbBlob); + db_event_get((MEVENT)hDbEvent, dbei); + + return dbei; +} + +template <> +int MT<DBEVENTINFO>::Get(lua_State *L, DBEVENTINFO *dbei) +{ + const char *key = luaL_checkstring(L, 2); + + if (mir_strcmpi(key, "Blob") == 0) { + lua_createtable(L, dbei->cbBlob, 0); + for (DWORD i = 0; i < dbei->cbBlob; i++) { + lua_pushinteger(L, dbei->pBlob[i]); + lua_rawseti(L, -2, i + 1); + } + } + else + lua_pushnil(L); + + return 1; +} + +template <> +void MT<DBEVENTINFO>::Free(lua_State*, DBEVENTINFO **dbei) +{ + mir_free((*dbei)->pBlob); + mir_free(*dbei); +} + +/***********************************************/ + +LUAMOD_API int luaopen_m_database(lua_State *L) +{ + luaL_newlib(L, databaseApi); + + lua_pushnumber(L, DBVT_BYTE); + lua_setfield(L, -2, "DBVT_BYTE"); + lua_pushnumber(L, DBVT_WORD); + lua_setfield(L, -2, "DBVT_WORD"); + lua_pushnumber(L, DBVT_DWORD); + lua_setfield(L, -2, "DBVT_DWORD"); + lua_pushnumber(L, DBVT_ASCIIZ); + lua_setfield(L, -2, "DBVT_ASCIIZ"); + lua_pushnumber(L, DBVT_UTF8); + lua_setfield(L, -2, "DBVT_UTF8"); + lua_pushnumber(L, DBVT_WCHAR); + lua_setfield(L, -2, "DBVT_WCHAR"); + + MT<DBCONTACTWRITESETTING>(L, MT_DBCONTACTWRITESETTING) + .Field(&DBCONTACTWRITESETTING::szModule, "Module", LUA_TSTRINGA) + .Field(&DBCONTACTWRITESETTING::szSetting, "Setting", LUA_TSTRINGA); + + MT<DBEVENTINFO>(L, MT_DBEVENTINFO) + .Field(&DBEVENTINFO::szModule, "Module", LUA_TSTRINGA) + .Field(&DBEVENTINFO::timestamp, "Timestamp", LUA_TINTEGER) + .Field(&DBEVENTINFO::eventType, "Type", LUA_TINTEGER) + .Field(&DBEVENTINFO::flags, "Flags", LUA_TINTEGER); + + return 1; +} |