diff options
author | aunsane <aunsane@gmail.com> | 2018-05-20 21:10:10 +0300 |
---|---|---|
committer | aunsane <aunsane@gmail.com> | 2018-05-20 21:34:31 +0300 |
commit | a955d18f62f335f84e0926f351eb85d78224cba6 (patch) | |
tree | 7bd4d30040ec32bba5949dd2245cb68617fb4192 /plugins/MirLua/src/Modules | |
parent | 46363eef857b69761f1d6d28da5a53a954f76900 (diff) |
MirLua: project reordering
Diffstat (limited to 'plugins/MirLua/src/Modules')
-rw-r--r-- | plugins/MirLua/src/Modules/m_chat.cpp | 25 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_clist.cpp | 140 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_core.cpp | 433 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_database.cpp | 691 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_genmenu.cpp | 95 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_hotkeys.cpp | 103 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_http.cpp | 443 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_icolib.cpp | 150 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_json.cpp | 243 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_message.cpp | 73 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_options.cpp | 117 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_protocols.cpp | 281 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_sounds.cpp | 54 | ||||
-rw-r--r-- | plugins/MirLua/src/Modules/m_srmm.cpp | 138 |
14 files changed, 2986 insertions, 0 deletions
diff --git a/plugins/MirLua/src/Modules/m_chat.cpp b/plugins/MirLua/src/Modules/m_chat.cpp new file mode 100644 index 0000000000..c1a2a65d9b --- /dev/null +++ b/plugins/MirLua/src/Modules/m_chat.cpp @@ -0,0 +1,25 @@ +#include "../stdafx.h" + +static luaL_Reg chatApi[] = +{ + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_chat(lua_State *L) +{ + luaL_newlib(L, chatApi); + + MT<GCEVENT>(L, "GCEVENT") + .Field(&GCEVENT::pszModule, "Module", LUA_TSTRINGA) + .Field(&GCEVENT::ptszID, "Id", LUA_TSTRINGW) + .Field(&GCEVENT::iType, "Type", LUA_TINTEGER) + .Field(&GCEVENT::time, "Timestamp", LUA_TINTEGER) + .Field(&GCEVENT::time, "IsMe", LUA_TINTEGER) + .Field(&GCEVENT::time, "Flags", LUA_TINTEGER) + .Field(&GCEVENT::ptszNick, "Nick", LUA_TSTRINGW) + .Field(&GCEVENT::ptszUID, "Uid", LUA_TSTRINGW) + .Field(&GCEVENT::ptszStatus, "Status", LUA_TSTRINGW) + .Field(&GCEVENT::ptszText, "Text", LUA_TSTRINGW); + + return 1; +} diff --git a/plugins/MirLua/src/Modules/m_clist.cpp b/plugins/MirLua/src/Modules/m_clist.cpp new file mode 100644 index 0000000000..5e5b7475b8 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_clist.cpp @@ -0,0 +1,140 @@ +#include "../stdafx.h" + + + +void MakeMenuItem(lua_State *L, CMenuItem &mi) +{ + mi.langId = CMLuaEnvironment::GetEnvironmentId(L); + + lua_getfield(L, -1, "Flags"); + mi.flags = lua_tointeger(L, -1); + lua_pop(L, 1); + + if (!(mi.flags & CMIF_UNICODE)) + mi.flags |= CMIF_UNICODE; + + lua_getfield(L, -1, "Uid"); + const char* uuid = lua_tostring(L, -1); + if (UuidFromStringA((RPC_CSTR)uuid, (UUID*)&mi.uid)) + UNSET_UID(mi); + lua_pop(L, 1); + + lua_getfield(L, -1, "Name"); + mi.name.w = mir_utf8decodeW(luaL_checkstring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Position"); + mi.position = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "Icon"); + mi.hIcolibItem = (HANDLE)lua_touserdata(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "Service"); + mi.pszService = lua_tostring(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "Parent"); + mi.root = (HGENMENU)lua_touserdata(L, -1); + lua_pop(L, 1); +} + +static int clist_AddMainMenuRoot(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + int position = lua_tointeger(L, 2); + HANDLE hIcon = (HANDLE)lua_touserdata(L, 3); + + HGENMENU res = Menu_CreateRoot(MO_MAIN, ptrW(Utf8DecodeW(name)), position, hIcon); + if (res != nullptr) + lua_pushlightuserdata(L, res); + else + lua_pushnil(L); + + return 1; +} + +static int clist_AddMainMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + CMenuItem mi; + MakeMenuItem(L, mi); + + HGENMENU res = Menu_AddMainMenuItem(&mi); + if (res != nullptr) + lua_pushlightuserdata(L, res); + else + lua_pushnil(L); + + return 1; +} + +static int clist_AddContactMenuRoot(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + int position = lua_tointeger(L, 2); + HANDLE hIcon = (HANDLE)lua_touserdata(L, 3); + + HGENMENU res = Menu_CreateRoot(MO_MAIN, ptrW(Utf8DecodeW(name)), position, hIcon); + if (res != nullptr) + lua_pushlightuserdata(L, res); + else + lua_pushnil(L); + + return 1; +} + +static int clist_AddContactMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + CMenuItem mi; + MakeMenuItem(L, mi); + + ptrA szProto(mir_utf8decodeA(lua_tostring(L, 2))); + HGENMENU res = Menu_AddContactMenuItem(&mi, szProto); + if (res != nullptr) + lua_pushlightuserdata(L, res); + else + lua_pushnil(L); + + return 1; +} + +static int clist_AddTrayMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + CMenuItem mi; + MakeMenuItem(L, mi); + + HGENMENU res = Menu_AddTrayMenuItem(&mi); + if (res != nullptr) + lua_pushlightuserdata(L, res); + else + lua_pushnil(L); + + return 1; +} + +static luaL_Reg clistApi[] = +{ + { "AddMainMenuRoot", clist_AddMainMenuRoot }, + { "AddMainMenuItem", clist_AddMainMenuItem }, + + { "AddContactMenuRoot", clist_AddContactMenuRoot }, + { "AddContactMenuItem", clist_AddContactMenuItem }, + + { "AddTrayMenuItem", clist_AddTrayMenuItem }, + + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_clist(lua_State *L) +{ + luaL_newlib(L, clistApi); + + return 1; +} diff --git a/plugins/MirLua/src/Modules/m_core.cpp b/plugins/MirLua/src/Modules/m_core.cpp new file mode 100644 index 0000000000..027ff163ed --- /dev/null +++ b/plugins/MirLua/src/Modules/m_core.cpp @@ -0,0 +1,433 @@ +#include "../stdafx.h" + +static int core_CreateHookableEvent(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + + HANDLE res = CreateHookableEvent(name); + if (res != nullptr) + lua_pushlightuserdata(L, res); + else + lua_pushnil(L); + + return 1; +} + +int HookEventLuaParam(void *obj, WPARAM wParam, LPARAM lParam, LPARAM param) +{ + lua_State *L = (lua_State*)obj; + + int ref = param; + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + + if (wParam) + lua_pushlightuserdata(L, (void*)wParam); + else + lua_pushnil(L); + + if (lParam) + lua_pushlightuserdata(L, (void*)lParam); + else + lua_pushnil(L); + + luaM_pcall(L, 2, 1); + + return lua_tointeger(L, -1); +} + +int HookEventEnvParam(void *obj, WPARAM wParam, LPARAM lParam, LPARAM param) +{ + CMLuaEnvironment *env = (CMLuaEnvironment*)obj; + + int ref = param; + lua_rawgeti(env->L, LUA_REGISTRYINDEX, ref); + + if (wParam) + lua_pushlightuserdata(env->L, (void*)wParam); + else + lua_pushnil(env->L); + + if (lParam) + lua_pushlightuserdata(env->L, (void*)lParam); + else + lua_pushnil(env->L); + + luaM_pcall(env->L, 2, 1); + + return lua_tointeger(env->L, -1); +} + +static int core_HookEvent(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + + lua_pushvalue(L, 2); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + HANDLE res = nullptr; + CMLuaEnvironment *env = CMLuaEnvironment::GetEnvironment(L); + if (env) { + res = HookEventObjParam(name, HookEventEnvParam, env, ref); + if (res) + env->AddHookRef(res, ref); + } + else + res = HookEventObjParam(name, HookEventLuaParam, L, ref); + + if (res == nullptr) { + luaL_unref(L, LUA_REGISTRYINDEX, ref); + lua_pushnil(L); + + return 1; + } + + lua_pushlightuserdata(L, res); + + return 1; +} + +static int core_HookTemporaryEvent(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + + lua_pushvalue(L, 2); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + HANDLE res = nullptr; + CMLuaEnvironment *env = CMLuaEnvironment::GetEnvironment(L); + if (env) { + res = HookEventObjParam(name, HookEventEnvParam, env, ref); + if (res) + env->AddHookRef(res, ref); + } + else + res = HookEventObjParam(name, HookEventLuaParam, L, ref); + + // event does not exists, call hook immideatelly + if (res == nullptr) { + luaL_unref(L, LUA_REGISTRYINDEX, ref); + lua_pushnil(L); + lua_pushnil(L); + luaM_pcall(L, 2, 1); + return lua_tointeger(env->L, -1); + } + + lua_pushlightuserdata(L, res); + + return 1; +} + +static int core_UnhookEvent(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HANDLE hEvent = lua_touserdata(L, 1); + + int res = UnhookEvent(hEvent); + if (!res) { + CMLuaEnvironment *env = CMLuaEnvironment::GetEnvironment(L); + if (env) + env->ReleaseHookRef(hEvent); + } + lua_pushboolean(L, !res); + + return 1; +} + +static int core_NotifyEventHooks(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HANDLE hEvent = lua_touserdata(L, 1); + WPARAM wParam = (WPARAM)luaM_tomparam(L, 2); + LPARAM lParam = (LPARAM)luaM_tomparam(L, 3); + + int res = NotifyEventHooks(hEvent, wParam, lParam); + lua_pushboolean(L, res != -1); + + return 1; +} + +/***********************************************/ + +INT_PTR CreateServiceFunctionLuaStateParam(void *obj, WPARAM wParam, LPARAM lParam, LPARAM param) +{ + lua_State *L = (lua_State*)obj; + + int ref = param; + lua_rawgeti(L, LUA_REGISTRYINDEX, ref); + + lua_pushlightuserdata(L, (void*)wParam); + lua_pushlightuserdata(L, (void*)lParam); + luaM_pcall(L, 2, 1); + + INT_PTR res = lua_tointeger(L, 1); + lua_pushinteger(L, res); + + return res; +} + +INT_PTR CreateServiceFunctionEnvParam(void *obj, WPARAM wParam, LPARAM lParam, LPARAM param) +{ + CMLuaEnvironment *env = (CMLuaEnvironment*)obj; + + int ref = param; + lua_rawgeti(env->L, LUA_REGISTRYINDEX, ref); + + lua_pushlightuserdata(env->L, (void*)wParam); + lua_pushlightuserdata(env->L, (void*)lParam); + luaM_pcall(env->L, 2, 1); + + INT_PTR res = lua_tointeger(env->L, 1); + lua_pushinteger(env->L, res); + + return res; +} + +static int core_CreateServiceFunction(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + luaL_checktype(L, 2, LUA_TFUNCTION); + + lua_pushvalue(L, 2); + int ref = luaL_ref(L, LUA_REGISTRYINDEX); + + HANDLE res = nullptr; + CMLuaEnvironment *env = CMLuaEnvironment::GetEnvironment(L); + if (env) { + res = CreateServiceFunctionObjParam(name, CreateServiceFunctionEnvParam, env, ref); + if (res) + env->AddServiceRef(res, ref); + } + else + res = CreateServiceFunctionObjParam(name, CreateServiceFunctionLuaStateParam, L, ref); + + if (!res) { + luaL_unref(L, LUA_REGISTRYINDEX, ref); + lua_pushnil(L); + return 1; + } + + lua_pushlightuserdata(L, res); + + return 1; +} + +static int core_CallService(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + WPARAM wParam = (WPARAM)luaM_tomparam(L, 2); + LPARAM lParam = (LPARAM)luaM_tomparam(L, 3); + + INT_PTR res = CallService(name, wParam, lParam); + lua_pushinteger(L, res); + + return 1; +} + +static int core_ServiceExists(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + + int res = ServiceExists(name); + lua_pushboolean(L, res); + + return 1; +} + +static int core_DestroyServiceFunction(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HANDLE hService = lua_touserdata(L, 1); + + CMLuaEnvironment *env = CMLuaEnvironment::GetEnvironment(L); + if (env) + env->ReleaseHookRef(hService); + + DestroyServiceFunction(hService); + + return 0; +} + +/***********************************************/ + +static int core_IsPluginLoaded(lua_State *L) +{ + const char *value = lua_tostring(L, 1); + + MUUID uuid = { 0 }; + bool res = UuidFromStringA((RPC_CSTR)value, (UUID*)&uuid) == RPC_S_OK; + if (res) + res = IsPluginLoaded(uuid) > 0; + lua_pushboolean(L, res); + + return 1; +} + +static int core_Free(lua_State *L) +{ + if (lua_islightuserdata(L, 1)) + { + void *ptr = lua_touserdata(L, 1); + mir_free(ptr); + } + + return 0; +} + +static int core_Translate(lua_State *L) +{ + char *what = (char*)luaL_checkstring(L, 1); + + ptrW value(mir_utf8decodeW(what)); + lua_pushstring(L, T2Utf(TranslateW_LP(value, hLangpack))); + + return 1; +} + +static int core_Parse(lua_State *L) +{ + char *what = (char*)luaL_checkstring(L, 1); + + ptrW value(mir_utf8decodeW(what)); + lua_pushstring(L, T2Utf(VARSW(value))); + + return 1; +} + +static int core_GetFullPath(lua_State *L) +{ + wchar_t path[MAX_PATH]; + GetModuleFileName(nullptr, path, MAX_PATH); + + lua_pushstring(L, ptrA(mir_utf8encodeW(path))); + + return 1; +} + +/***********************************************/ + +struct core_ForkThreadParam +{ + lua_State *L; + int threadRef; + int functionRef; + HANDLE hThread; +}; + +std::map<HANDLE, core_ForkThreadParam*> lstThreads; + +void DestroyThread(core_ForkThreadParam *ftp) +{ + luaL_unref(ftp->L, LUA_REGISTRYINDEX, ftp->functionRef); + luaL_unref(ftp->L, LUA_REGISTRYINDEX, ftp->threadRef); + lstThreads.erase(ftp->hThread); + + delete ftp; +} + +void __cdecl ThreadFunc(void *p) +{ + core_ForkThreadParam *ftp = (core_ForkThreadParam*)p; + + lua_rawgeti(ftp->L, LUA_REGISTRYINDEX, ftp->functionRef); + luaM_pcall(ftp->L, 0, 1); + DestroyThread(ftp); +} + +static int core_ForkThread(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TFUNCTION); + + core_ForkThreadParam *p = new core_ForkThreadParam(); + + p->L = lua_newthread(L); + p->threadRef = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, 1); + p->functionRef = luaL_ref(L, LUA_REGISTRYINDEX); + + p->hThread = mir_forkthread(ThreadFunc, p); + lstThreads[p->hThread] = p; + lua_pushlightuserdata(L, p->hThread); + + return 1; +} + +static int core_TerminateThread(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HANDLE hThread = (HANDLE)lua_touserdata(L, 1); + + auto it = lstThreads.find(hThread); + if (it != lstThreads.end()) { + DestroyThread(it->second); + lua_pushboolean(L, TerminateThread(hThread, 0)); + } + else lua_pushboolean(L, 0); + + return 1; +} + +/***********************************************/ + +luaL_Reg coreApi[] = +{ + { "CreateHookableEvent", core_CreateHookableEvent }, + + { "NotifyEventHooks", core_NotifyEventHooks }, + + { "HookEvent", core_HookEvent }, + { "HookTemporaryEvent", core_HookTemporaryEvent }, + { "UnhookEvent", core_UnhookEvent }, + + { "CreateServiceFunction", core_CreateServiceFunction }, + { "DestroyServiceFunction", core_DestroyServiceFunction }, + + { "ServiceExists", core_ServiceExists }, + { "CallService", core_CallService }, + + { "IsPluginLoaded", core_IsPluginLoaded }, + + { "Free", core_Free }, + + { "Translate", core_Translate }, + + { "Parse", core_Parse }, + + { "GetFullPath", core_GetFullPath }, + + { "ForkThread", core_ForkThread }, + { "TerminateThread", core_TerminateThread }, + + { "Version", nullptr }, + + { "NULL", nullptr }, + { "INVALID_HANDLE_VALUE", nullptr }, + { "CALLSERVICE_NOTFOUND", nullptr }, + + { nullptr, nullptr } +}; + +/***********************************************/ + +LUAMOD_API int luaopen_m_core(lua_State *L) +{ + luaL_newlib(L, coreApi); + lua_pushlightuserdata(L, nullptr); + lua_setfield(L, -2, "NULL"); + lua_pushlightuserdata(L, INVALID_HANDLE_VALUE); + lua_setfield(L, -2, "INVALID_HANDLE_VALUE"); + lua_pushinteger(L, CALLSERVICE_NOTFOUND); + lua_setfield(L, -2, "CALLSERVICE_NOTFOUND"); + + char version[128]; + Miranda_GetVersionText(version, _countof(version)); + lua_pushstring(L, ptrA(mir_utf8encode(version))); + lua_setfield(L, -2, "Version"); + + // set copy to global variable m + lua_pushvalue(L, -1); + lua_setglobal(L, "m"); + + return 1; +}
\ No newline at end of file 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; +} diff --git a/plugins/MirLua/src/Modules/m_genmenu.cpp b/plugins/MirLua/src/Modules/m_genmenu.cpp new file mode 100644 index 0000000000..0c2d0ab492 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_genmenu.cpp @@ -0,0 +1,95 @@ +#include "../stdafx.h" + +static int genmenu_ModifyMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HGENMENU hMenuItem = (HGENMENU)lua_touserdata(L, 1); + ptrW name(mir_utf8decodeW(lua_tostring(L, 2))); + HANDLE hIcolibItem = luaL_opt(L, lua_touserdata, 3, INVALID_HANDLE_VALUE); + int flags = luaL_optinteger(L, 4, -1); + + if (!(flags & CMIF_UNICODE)) + flags |= CMIF_UNICODE; + + INT_PTR res = Menu_ModifyItem(hMenuItem, name, hIcolibItem, flags); + lua_pushboolean(L, res == 0); + + return 1; +} + +static int genmenu_ConfigureMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HGENMENU hMenuItem = (HGENMENU)lua_touserdata(L, 1); + int option = luaL_checkinteger(L, 2); + luaL_checktype(L, 3, LUA_TLIGHTUSERDATA); + INT_PTR value = (INT_PTR)lua_touserdata(L, 3); + + int res = Menu_ConfigureItem(hMenuItem, option, value); + lua_pushboolean(L, res >= 0); + + return 1; +} + +static int genmenu_ShowMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HGENMENU hMenuItem = (HGENMENU)lua_touserdata(L, 1); + bool isShow = luaM_toboolean(L, 2); + + Menu_ShowItem(hMenuItem, isShow); + + return 0; +} + +static int genmenu_EnableMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HGENMENU hMenuItem = (HGENMENU)lua_touserdata(L, 1); + bool isEnable = luaM_toboolean(L, 2); + + Menu_EnableItem(hMenuItem, isEnable); + + return 0; +} + +static int genmenu_CheckMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HGENMENU hMenuItem = (HGENMENU)lua_touserdata(L, 1); + bool isChecked = luaM_toboolean(L, 2); + + Menu_SetChecked(hMenuItem, isChecked); + + return 0; +} + +static int genmenu_RemoveMenuItem(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + HGENMENU hMenuItem = (HGENMENU)lua_touserdata(L, 1); + + INT_PTR res = Menu_RemoveItem(hMenuItem); + lua_pushboolean(L, res == 0); + + return 1; +} + +static luaL_Reg genmenuApi[] = +{ + { "ModifyMenuItem", genmenu_ModifyMenuItem }, + { "ConfigureMenuItem", genmenu_ConfigureMenuItem }, + { "ShowMenuItem", genmenu_ShowMenuItem }, + { "EnableMenuItem", genmenu_EnableMenuItem }, + { "CheckMenuItem", genmenu_CheckMenuItem }, + { "RemoveMenuItem", genmenu_RemoveMenuItem }, + + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_genmenu(lua_State *L) +{ + luaL_newlib(L, genmenuApi); + + return 1; +} diff --git a/plugins/MirLua/src/Modules/m_hotkeys.cpp b/plugins/MirLua/src/Modules/m_hotkeys.cpp new file mode 100644 index 0000000000..1245d2348f --- /dev/null +++ b/plugins/MirLua/src/Modules/m_hotkeys.cpp @@ -0,0 +1,103 @@ +#include "../stdafx.h" + +void MakeHotkey(lua_State *L, HOTKEYDESC &hk) +{ + lua_getfield(L, -1, "Flags"); + hk.dwFlags = lua_tointeger(L, -1); + lua_pop(L, 1); + + if (!(hk.dwFlags & HKD_UNICODE)) + hk.dwFlags |= HKD_UNICODE; + + lua_getfield(L, -1, "Name"); + hk.pszName = mir_utf8decodeA(luaL_checkstring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Description"); + hk.szDescription.w = mir_utf8decodeW(lua_tostring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Section"); + hk.szSection.w = mir_utf8decodeW(luaL_optstring(L, -1, MODULENAME)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Hotkey"); + hk.DefHotKey = lua_tointeger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "Service"); + hk.pszService = mir_utf8decodeA(luaL_checkstring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "lParam"); + hk.lParam = (LPARAM)lua_touserdata(L, -1); + lua_pop(L, 1); +} + +static int hotkeys_Register(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + HOTKEYDESC hk; + MakeHotkey(L, hk); + + int hScriptLangpack = CMLuaEnvironment::GetEnvironmentId(L); + + INT_PTR res = Hotkey_Register(&hk, hScriptLangpack); + lua_pushboolean(L, res); + + return 1; +} + +static int hotkeys_Unregister(lua_State *L) +{ + const char *name = luaL_checkstring(L, 1); + + Hotkey_Unregister(name); + + return 0; +} + +static const char *mods[] = { "shift", "ctrl", "alt", "ext", nullptr }; + +static int hotkeys_MakeHotkey(lua_State *L) +{ + int mod = 0; + switch (lua_type(L, 1)) + { + case LUA_TNUMBER: + mod = luaL_checkinteger(L, 1); + break; + case LUA_TSTRING: + mod = (1 << (luaL_checkoption(L, 1, nullptr, mods) - 1)); + break; + case LUA_TTABLE: + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) + mod |= (1 << (luaL_checkoption(L, -1, nullptr, mods) - 1)); + break; + default: + luaL_argerror(L, 1, luaL_typename(L, 1)); + } + int vk = luaL_checknumber(L, 2); + + WORD res = HOTKEYCODE(mod, vk); + lua_pushinteger(L, res); + + return 1; +} + +static luaL_Reg hotkeysApi[] = +{ + { "MakeHotkey", hotkeys_MakeHotkey }, + { "Register", hotkeys_Register }, + { "Unregister", hotkeys_Unregister }, + + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_hotkeys(lua_State *L) +{ + luaL_newlib(L, hotkeysApi); + + return 1; +} diff --git a/plugins/MirLua/src/Modules/m_http.cpp b/plugins/MirLua/src/Modules/m_http.cpp new file mode 100644 index 0000000000..31def57a9a --- /dev/null +++ b/plugins/MirLua/src/Modules/m_http.cpp @@ -0,0 +1,443 @@ +#include "../stdafx.h" + +/***********************************************/ + +#define MT_NETLIBHTTPHEADERS "NETLIBHTTPHEADERS" + +struct NETLIBHTTPHEADERS +{ + const NETLIBHTTPHEADER *headers; + int count; +}; + +static void AddHeader(NETLIBHTTPREQUEST *request, const char *name, const char *value) +{ + request->headers = (NETLIBHTTPHEADER*)mir_realloc(request->headers, + sizeof(NETLIBHTTPHEADER)*(request->headersCount + 1)); + NETLIBHTTPHEADER &header = request->headers[request->headersCount]; + header.szName = mir_strdup(name); + header.szValue = mir_strdup(value); + request->headersCount++; +} + +static void SetHeader(NETLIBHTTPREQUEST *request, const char *name, const char *value) +{ + for (int i = 0; i < request->headersCount; i++) { + if (mir_strcmp(request->headers[i].szName, name) == 0) { + mir_free(request->headers[i].szValue); + request->headers[i].szValue = mir_strdup(value); + return; + } + } + AddHeader(request, name, value); +} + +static int headers_Iterator(lua_State *L) +{ + NETLIBHTTPHEADER *headers = (NETLIBHTTPHEADER*)lua_touserdata(L, lua_upvalueindex(1)); + int count = lua_tointeger(L, lua_upvalueindex(2)); + int idx = lua_tointeger(L, lua_upvalueindex(3)); + + if (idx < count) { + lua_pushstring(L, headers[idx].szName); + lua_pushstring(L, headers[idx].szValue); + lua_pushinteger(L, idx + 1); + lua_replace(L, lua_upvalueindex(3)); + return 2; + } + + lua_pushnil(L); + + return 1; +} + +static int headers__call(lua_State *L) +{ + NETLIBHTTPHEADERS *headers = (NETLIBHTTPHEADERS*)luaL_checkudata(L, 1, MT_NETLIBHTTPHEADERS); + + lua_pushlightuserdata(L, (void*)headers->headers); + lua_pushinteger(L, headers->count); + lua_pushinteger(L, 0); + lua_pushcclosure(L, headers_Iterator, 3); + + return 1; +} + +static int headers__index(lua_State *L) +{ + NETLIBHTTPHEADERS *headers = (NETLIBHTTPHEADERS*)luaL_checkudata(L, 1, MT_NETLIBHTTPHEADERS); + + if (lua_isinteger(L, 2)) { + int idx = lua_tointeger(L, 2); + if (idx > 0 && idx <= headers->count) { + lua_pushstring(L, headers->headers[idx - 1].szValue); + return 1; + } + } + + const char *key = lua_tostring(L, 2); + for (int i = 0; i < headers->count; i++) { + if (mir_strcmp(headers->headers[i].szName, key) == 0) { + lua_pushstring(L, headers->headers[i].szValue); + return 1; + } + } + + lua_pushnil(L); + + return 1; +} + +static int headers__len(lua_State *L) +{ + NETLIBHTTPHEADERS *headers = (NETLIBHTTPHEADERS*)luaL_checkudata(L, 1, MT_NETLIBHTTPHEADERS); + + lua_pushinteger(L, headers->count); + + return 1; +} + +static const luaL_Reg headersApi[] = +{ + { "__call", headers__call }, + { "__index", headers__index }, + { "__len", headers__len }, + + { nullptr, nullptr } +}; + +/***********************************************/ + +#define MT_NETLIBHTTPCONTENT "NETLIBHTTPCONTENT" + +struct NETLIBHTTPCONTENT +{ + const char *data; + int length; +}; + +static int content__index(lua_State *L) +{ + NETLIBHTTPCONTENT *content = (NETLIBHTTPCONTENT*)luaL_checkudata(L, 1, MT_NETLIBHTTPCONTENT); + + int idx = luaL_checkinteger(L, 2); + if (idx > 0 && idx <= content->length) { + lua_pushinteger(L, content->data[idx - 1]); + return 1; + } + + lua_pushnil(L); + + return 1; +} + +static int content__len(lua_State *L) +{ + NETLIBHTTPCONTENT *content = (NETLIBHTTPCONTENT*)luaL_checkudata(L, 1, MT_NETLIBHTTPCONTENT); + + lua_pushinteger(L, content->length); + + return 1; +} + +static int content__tostring(lua_State *L) +{ + NETLIBHTTPCONTENT *content = (NETLIBHTTPCONTENT*)luaL_checkudata(L, 1, MT_NETLIBHTTPCONTENT); + + lua_pushlstring(L, content->data, content->length); + + return 1; +} + +static const luaL_Reg contentApi[] = +{ + { "__index", content__index }, + { "__len", content__len }, + { "__tostring", content__tostring }, + + { nullptr, nullptr } +}; + +/***********************************************/ + +#define MT_NETLIBHTTPRESPONSE "NETLIBHTTPRESPONSE" + +static NETLIBHTTPREQUEST* response_Create(lua_State *L, NETLIBHTTPREQUEST *request) +{ + NETLIBHTTPREQUEST **response = (NETLIBHTTPREQUEST**)lua_newuserdata(L, sizeof(NETLIBHTTPREQUEST*)); + *response = Netlib_HttpTransaction(hNetlib, request); + luaL_setmetatable(L, MT_NETLIBHTTPRESPONSE); + + return *response; +} + +static int response__index(lua_State *L) +{ + NETLIBHTTPREQUEST *response = *(NETLIBHTTPREQUEST**)luaL_checkudata(L, 1, MT_NETLIBHTTPRESPONSE); + const char *key = lua_tostring(L, 2); + + if (mir_strcmpi(key, "Headers") == 0) { + NETLIBHTTPHEADERS *headers = (NETLIBHTTPHEADERS*)lua_newuserdata(L, sizeof(NETLIBHTTPHEADERS)); + headers->headers = response->headers; + headers->count = response->headersCount; + luaL_setmetatable(L, MT_NETLIBHTTPHEADERS); + } + else if (mir_strcmpi(key, "Content") == 0) { + NETLIBHTTPCONTENT *content = (NETLIBHTTPCONTENT*)lua_newuserdata(L, sizeof(NETLIBHTTPCONTENT)); + content->data = response->pData; + content->length = response->dataLength; + luaL_setmetatable(L, MT_NETLIBHTTPCONTENT); + } + else if (mir_strcmpi(key, "StatusCode") == 0) + lua_pushinteger(L, response->resultCode); + else if (mir_strcmpi(key, "IsSuccess") == 0) { + lua_pushboolean(L, HTTP_CODE_SUCCESS(response->resultCode)); + } + else + lua_pushnil(L); + + return 1; +} + +static int response__gc(lua_State *L) +{ + NETLIBHTTPREQUEST **response = (NETLIBHTTPREQUEST**)luaL_checkudata(L, 1, MT_NETLIBHTTPRESPONSE); + + Netlib_FreeHttpRequest(*response); + + return 0; +} + +static const luaL_Reg responseApi[] = +{ + { "__index", response__index }, + { "__gc", response__gc }, + + { nullptr, nullptr } +}; + +/***********************************************/ + +#define MT_NETLIBHTTPREQUEST "NETLIBHTTPREQUEST" + +static NETLIBHTTPREQUEST* CreateRequest(lua_State *L) +{ + NETLIBHTTPREQUEST **request = (NETLIBHTTPREQUEST**)lua_newuserdata(L, sizeof(NETLIBHTTPREQUEST*)); + *request = (NETLIBHTTPREQUEST*)mir_calloc(sizeof(NETLIBHTTPREQUEST)); + (*request)->cbSize = sizeof(NETLIBHTTPREQUEST); + (*request)->flags = NLHRF_HTTP11 | NLHRF_NODUMP; + + luaL_setmetatable(L, MT_NETLIBHTTPREQUEST); + + return *request; +} + +static void request_SetUrl(lua_State *L, int idx, NETLIBHTTPREQUEST *request) +{ + const char *url = luaL_checkstring(L, idx); + request->szUrl = mir_strdup(url); + if (mir_strncmpi(request->szUrl, "https", 5) == 0) + request->flags |= NLHRF_SSL; + else + request->flags &= ~(NLHRF_SSL); +} + +static void request_SetHeaders(lua_State *L, int idx, NETLIBHTTPREQUEST *request) +{ + if (lua_isnoneornil(L, idx)) + return; + + luaL_checktype(L, idx, LUA_TTABLE); + + idx = lua_absindex(L, idx); + for (lua_pushnil(L); lua_next(L, idx); lua_pop(L, 2)) { + lua_pushvalue(L, -2); + const char *name = lua_tostring(L, -1); + const char *value = lua_tostring(L, -2); + AddHeader(request, name, value); + } +} + +static void request_SetContent(lua_State *L, int idx, NETLIBHTTPREQUEST *request) +{ + CMStringA data; + + switch (lua_type(L, idx)) + { + case LUA_TNONE: + case LUA_TNIL: + return; + case LUA_TSTRING: + data = lua_tostring(L, idx); + SetHeader(request, "Content-Type", "text/plain"); + break; + case LUA_TTABLE: + { + idx = lua_absindex(L, idx); + for (lua_pushnil(L); lua_next(L, idx); lua_pop(L, 2)) { + lua_pushvalue(L, -2); + const char *name = lua_tostring(L, -1); + const char *value = lua_tostring(L, -2); + data.AppendFormat("&%s=%s", name, value); + } + data.Delete(0); + SetHeader(request, "Content-Type", "application/x-www-form-urlencoded"); + break; + } + default: + luaL_argerror(L, idx, luaL_typename(L, idx)); + } + + request->pData = mir_strdup(data); + request->dataLength = data.GetLength(); +} + +static void request_SetContentType(lua_State *L, int idx, NETLIBHTTPREQUEST *request) +{ + if (!lua_isstring(L, idx)) + return; + + const char *type = lua_tostring(L, idx); + SetHeader(request, "Content-Type", type); +} + +static const char *httpMethods[] = { "GET", "POST", "PUT", "DELETE", nullptr }; + +static int request_Send(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + NETLIBHTTPREQUEST *request = CreateRequest(L); + + lua_getfield(L, 1, "Method"); + request->requestType = (1 << (luaL_checkoption(L, -1, nullptr, httpMethods))); + lua_pop(L, 1); + + lua_getfield(L, 1, "Url"); + request_SetUrl(L, -1, request); + lua_pop(L, 1); + + lua_getfield(L, 1, "Headers"); + request_SetHeaders(L, -1, request); + lua_pop(L, 1); + + lua_getfield(L, 1, "Content"); + request_SetContent(L, -1, request); + lua_pop(L, 1); + + lua_getfield(L, 1, "Timeout"); + request->timeout = luaL_optinteger(L, -1, 0); + lua_pop(L, 1); + + response_Create(L, request); + + return 1; +} + +static int request_Get(lua_State *L) +{ + NETLIBHTTPREQUEST *request = CreateRequest(L); + request->requestType = REQUEST_GET; + request_SetUrl(L, 1, request); + + response_Create(L, request); + + return 1; +} + +static int request_Post(lua_State *L) +{ + NETLIBHTTPREQUEST *request = CreateRequest(L); + request->requestType = REQUEST_POST; + request_SetUrl(L, 1, request); + request_SetContent(L, 2, request); + request_SetContentType(L, 3, request); + + response_Create(L, request); + + return 1; +} + +static int request_Put(lua_State *L) +{ + NETLIBHTTPREQUEST *request = CreateRequest(L); + request->requestType = REQUEST_PUT; + request_SetUrl(L, 1, request); + request_SetContent(L, 2, request); + request_SetContentType(L, 3, request); + + response_Create(L, request); + + return 1; +} + +static int request_Delete(lua_State *L) +{ + NETLIBHTTPREQUEST *request = CreateRequest(L); + request->requestType = REQUEST_DELETE; + request_SetUrl(L, 1, request); + request_SetContent(L, 2, request); + request_SetContentType(L, 2, request); + + response_Create(L, request); + + return 1; +} + +static int request__gc(lua_State *L) +{ + NETLIBHTTPREQUEST **request = (NETLIBHTTPREQUEST**)luaL_checkudata(L, 1, MT_NETLIBHTTPREQUEST); + + mir_free((*request)->szUrl); + for (int i = 0; i < (*request)->headersCount; i++) { + mir_free((*request)->headers[i].szName); + mir_free((*request)->headers[i].szValue); + } + mir_free((*request)->headers); + mir_free((*request)->pData); + + return 0; +} + +static const luaL_Reg requestApi[] = +{ + { "__gc", request__gc }, + + { nullptr, nullptr } +}; + +/***********************************************/ + +static const luaL_Reg httpApi[] = +{ + { "Send", request_Send }, + { "Get", request_Get }, + { "Post", request_Post }, + { "Put", request_Put }, + { "Delete", request_Delete }, + + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_http(lua_State *L) +{ + luaL_newlib(L, httpApi); + + luaL_newmetatable(L, MT_NETLIBHTTPREQUEST); + luaL_setfuncs(L, requestApi, 0); + lua_pop(L, 1); + + luaL_newmetatable(L, MT_NETLIBHTTPRESPONSE); + luaL_setfuncs(L, responseApi, 0); + lua_pop(L, 1); + + luaL_newmetatable(L, MT_NETLIBHTTPHEADERS); + luaL_setfuncs(L, headersApi, 0); + lua_pop(L, 1); + + luaL_newmetatable(L, MT_NETLIBHTTPCONTENT); + luaL_setfuncs(L, contentApi, 0); + lua_pop(L, 1); + + return 1; +} diff --git a/plugins/MirLua/src/Modules/m_icolib.cpp b/plugins/MirLua/src/Modules/m_icolib.cpp new file mode 100644 index 0000000000..86b5163290 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_icolib.cpp @@ -0,0 +1,150 @@ +#include "../stdafx.h"
+
+static void MakeSKINICONDESC(lua_State *L, SKINICONDESC &sid)
+{
+ lua_getfield(L, -1, "Flags");
+ sid.flags = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ if (!(sid.flags & SIDF_ALL_UNICODE))
+ sid.flags |= SIDF_ALL_UNICODE;
+
+ lua_getfield(L, -1, "Name");
+ sid.pszName = mir_utf8decodeA(luaL_checkstring(L, -1));
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "Description");
+ sid.description.w = mir_utf8decodeW(luaL_checkstring(L, -1));
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "Section");
+ sid.section.w = mir_utf8decodeW(luaL_optstring(L, 3, MODULENAME));
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "DefaultFile");
+ sid.defaultFile.w = mir_utf8decodeW(lua_tostring(L, -1));
+ lua_pop(L, 1);
+
+ if (sid.defaultFile.w == nullptr) {
+ sid.defaultFile.w = (wchar_t*)mir_calloc(MAX_PATH + 1);
+ GetModuleFileName(g_plugin.getInst(), sid.defaultFile.w, MAX_PATH);
+ }
+
+ lua_getfield(L, -1, "DefaultIndex");
+ sid.iDefaultIndex = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "DefaultIcon");
+ sid.hDefaultIcon = (HICON)lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "SizeX");
+ sid.iDefaultIndex = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ lua_getfield(L, -1, "SizeY");
+ sid.iDefaultIndex = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+}
+
+static int lua_AddIcon(lua_State *L)
+{
+ SKINICONDESC sid = { };
+
+ if (lua_type(L, 1) == LUA_TSTRING) {
+ sid.flags = SIDF_ALL_UNICODE;
+ sid.pszName = mir_utf8decodeA(luaL_checkstring(L, 1));
+ sid.description.w = mir_utf8decodeW(luaL_checkstring(L, 2));
+ sid.section.w = mir_utf8decodeW(luaL_optstring(L, 3, MODULENAME));
+ sid.defaultFile.w = mir_utf8decodeW(lua_tostring(L, 4));
+ sid.hDefaultIcon = GetIcon(IDI_SCRIPT);
+
+ if (sid.defaultFile.w == nullptr) {
+ sid.defaultFile.w = (wchar_t*)mir_calloc(MAX_PATH + 1);
+ GetModuleFileName(g_plugin.getInst(), sid.defaultFile.w, MAX_PATH);
+ }
+ }
+ else if (lua_type(L, 1) == LUA_TTABLE)
+ MakeSKINICONDESC(L, sid);
+ else
+ luaL_argerror(L, 1, luaL_typename(L, 1));
+
+ int hScriptLangpack = CMLuaEnvironment::GetEnvironmentId(L);
+ HANDLE res = IcoLib_AddIcon(&sid, hScriptLangpack);
+ lua_pushlightuserdata(L, res);
+
+ mir_free((void*)sid.pszName);
+ mir_free((void*)sid.description.w);
+ mir_free((void*)sid.section.w);
+ mir_free((void*)sid.defaultFile.w);
+
+ return 1;
+}
+
+static int lua_GetIcon(lua_State *L)
+{
+ bool big = luaM_toboolean(L, 2);
+
+ HICON hIcon = nullptr;
+ switch (lua_type(L, 1)) {
+ case LUA_TLIGHTUSERDATA:
+ hIcon = IcoLib_GetIconByHandle(lua_touserdata(L, 1), big);
+ break;
+ case LUA_TSTRING:
+ hIcon = IcoLib_GetIcon(lua_tostring(L, 1), big);
+ break;
+ default:
+ luaL_argerror(L, 1, luaL_typename(L, 1));
+ }
+
+ if (hIcon)
+ lua_pushlightuserdata(L, hIcon);
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int lua_GetIconHandle(lua_State *L)
+{
+ const char *name = luaL_checkstring(L, 1);
+
+ HANDLE res = IcoLib_GetIconHandle(name);
+ lua_pushlightuserdata(L, res);
+
+ return 1;
+}
+
+static int lua_RemoveIcon(lua_State *L)
+{
+ switch (lua_type(L, 1)) {
+ case LUA_TLIGHTUSERDATA:
+ IcoLib_RemoveIconByHandle(lua_touserdata(L, 1));
+ break;
+ case LUA_TSTRING:
+ IcoLib_RemoveIcon(luaL_checkstring(L, 1));
+ break;
+ default:
+ luaL_argerror(L, 1, luaL_typename(L, 1));
+ }
+
+ return 0;
+}
+
+static luaL_Reg icolibApi[] =
+{
+ { "AddIcon", lua_AddIcon },
+ { "GetIcon", lua_GetIcon },
+ { "GetHandle", lua_GetIconHandle },
+ { "GetIconHandle", lua_GetIconHandle },
+ { "RemoveIcon", lua_RemoveIcon },
+
+ { nullptr, nullptr }
+};
+
+LUAMOD_API int luaopen_m_icolib(lua_State *L)
+{
+ luaL_newlib(L, icolibApi);
+
+ return 1;
+}
diff --git a/plugins/MirLua/src/Modules/m_json.cpp b/plugins/MirLua/src/Modules/m_json.cpp new file mode 100644 index 0000000000..24e32cab09 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_json.cpp @@ -0,0 +1,243 @@ +#include "../stdafx.h" + +#define MT_JSON "JSON" + +static void lua2json(lua_State *L, JSONNode &node) +{ + switch (lua_type(L, -1)) { + case LUA_TNIL: + node.nullify(); + break; + case LUA_TSTRING: + node = lua_tostring(L, -1); + break; + case LUA_TBOOLEAN: + node = lua_toboolean(L, -1) != 0; + break; + case LUA_TNUMBER: + { + lua_Integer val = lua_tointeger(L, -1); + if (lua_isinteger(L, -1) && val >= LONG_MIN && val <= LONG_MIN) + node = (long)val; + else + node = lua_tonumber(L, -1); + break; + } + case LUA_TTABLE: + { + ptrA name(mir_strdup(node.name())); + node.cast(JSON_ARRAY); + node.set_name((char*)name); + + lua_pushnil(L); + while (lua_next(L, -2) != 0) { + JSONNode child; + if (!lua_isnumber(L, -2)) { + if (node.type() == JSON_ARRAY) { + node.cast(JSON_NODE); + node.set_name((char*)name); + } + const char *key = lua_tostring(L, -2); + child.set_name(key); + } + lua2json(L, child); + node << child; + + lua_pop(L, 1); + } + + break; + } + } +} + +/***********************************************/ + +static int json__index(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + + JSONNode *child; + if (node->type() == JSON_ARRAY) { + int idx = lua_tointeger(L, 2); + child = &node->at(idx - 1); + } + else { + const char *key = lua_tostring(L, 2); + child = &node->at(key); + } + + switch (child->type()) + { + case JSON_NULL: + lua_pushnil(L); + break; + case JSON_STRING: + lua_pushstring(L, child->as_string().c_str()); + break; + case JSON_NUMBER: + lua_pushnumber(L, child->as_int()); + break; + case JSON_BOOL: + lua_pushboolean(L, child->as_bool()); + break; + case JSON_ARRAY: + case JSON_NODE: + JSONNode **udata = (JSONNode**)lua_newuserdata(L, sizeof(JSONNode*)); + *udata = child; + luaL_setmetatable(L, MT_JSON); + } + + return 1; +} + +static int json__newindex(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + const char *key = lua_tostring(L, 2); + + if (json_type(node) == JSON_ARRAY) { + int idx = lua_tointeger(L, 2); + JSONNode *child = json_at(node, idx - 1); + lua2json(L, *child); + return 0; + } + + JSONNode *child = json_get(node, key); + if (json_type(child) == JSON_NULL) { + json_set_name(child, key); + lua2json(L, *child); + json_push_back(node, child); + return 0; + } + + lua2json(L, *child); + + return 0; +} + +static int json__len(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + lua_pushnumber(L, json_size(node)); + + return 1; +} + +static int json__tostring(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + + lua_pushstring(L, node->write().c_str()); + + return 1; +} + +static int json__gc(lua_State *L) +{ + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + + json_delete(node); + + return 0; +} + +const struct luaL_Reg jsonApi[] = +{ + { "__index", json__index }, + { "__newindex", json__newindex }, + { "__len", json__len }, + { "__tostring", json__tostring }, + { "__gc", json__gc }, + + { nullptr, nullptr } +}; + + +/***********************************************/ + +static int lua_Decode(lua_State *L) +{ + const char *string = luaL_checkstring(L, 1); + + JSONNode **udata = (JSONNode**)lua_newuserdata(L, sizeof(JSONNode*)); + *udata = json_parse(string); + luaL_setmetatable(L, MT_JSON); + + return 1; +} + +static int lua_Encode(lua_State *L) +{ + switch (lua_type(L, 1)) { + case LUA_TNIL: + lua_pushliteral(L, "null"); + break; + case LUA_TBOOLEAN: + lua_pushstring(L, lua_toboolean(L, 1) ? "true" : "false"); + break; + case LUA_TNUMBER: + { + if (lua_isinteger(L, 1)) { + lua_pushfstring(L, "%I", lua_tointeger(L, 1)); + break; + } + char decpoint = lua_getlocaledecpoint(); + if (decpoint != '.') { + char p[2] = { decpoint }; + luaL_gsub(L, lua_tostring(L, 1), p, "."); + } + else + lua_pushfstring(L, "%f", lua_tonumber(L, 1)); + break; + } + case LUA_TSTRING: + lua_pushfstring(L, "\"%s\"", lua_tostring(L, 1)); + break; + case LUA_TTABLE: + { + JSONNode node; + lua_pushnil(L); + lua_pushvalue(L, 1); + lua2json(L, node); + lua_pop(L, 2); + lua_pushstring(L, node.write().c_str()); + break; + } + case LUA_TUSERDATA: + { + JSONNode *node = *(JSONNode**)luaL_checkudata(L, 1, MT_JSON); + lua_pushstring(L, node->write().c_str()); + break; + } + case LUA_TLIGHTUSERDATA: + if (lua_touserdata(L, 1) == nullptr) + { + lua_pushliteral(L, "null"); + break; + } + default: + luaL_argerror(L, 1, luaL_typename(L, 1)); + } + + return 1; +} + +static const luaL_Reg methods[] = +{ + { "Decode", lua_Decode }, + { "Encode", lua_Encode }, + + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_json(lua_State *L) +{ + luaL_newlib(L, methods); + + luaL_newmetatable(L, MT_JSON); + luaL_setfuncs(L, jsonApi, 0); + lua_pop(L, 1); + + return 1; +}
\ No newline at end of file diff --git a/plugins/MirLua/src/Modules/m_message.cpp b/plugins/MirLua/src/Modules/m_message.cpp new file mode 100644 index 0000000000..c369237796 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_message.cpp @@ -0,0 +1,73 @@ +#include "../stdafx.h" + +static int message_Paste(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + ptrW text(mir_utf8decodeW(luaL_checkstring(L, 2))); + + MessageWindowData mwd; + INT_PTR res = Srmm_GetWindowData(hContact, mwd); + lua_pushinteger(L, res); + if (res) + return 1; + + HWND hEdit = GetDlgItem(mwd.hwndWindow, 1002 /*IDC_MESSAGE*/); + if (!hEdit) hEdit = GetDlgItem(mwd.hwndWindow, 1009 /*IDC_CHATMESSAGE*/); + + SendMessage(hEdit, EM_REPLACESEL, TRUE, (LPARAM)text); + + return 1; +} + +static int message_Send(lua_State *L) +{ + MCONTACT hContact = luaL_checkinteger(L, 1); + const char *message = luaL_checkstring(L, 2); + + INT_PTR res = 1; + + const char *szProto = GetContactProto(hContact); + if (db_get_b(hContact, szProto, "ChatRoom", 0) == TRUE) { + ptrW wszChatRoom(db_get_wsa(hContact, szProto, "ChatRoomID")); + ptrW wszMessage(mir_utf8decodeW(message)); + res = Chat_SendUserMessage(szProto, wszChatRoom, wszMessage); + lua_pushinteger(L, res); + } + else if ((res = ProtoChainSend(hContact, PSS_MESSAGE, 0, (LPARAM)message)) != ACKRESULT_FAILED) { + DBEVENTINFO dbei = {}; + dbei.szModule = MODULENAME; + dbei.timestamp = time(0); + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = (DWORD)mir_strlen(message); + dbei.pBlob = (PBYTE)mir_strdup(message); + dbei.flags = DBEF_UTF | DBEF_SENT; + db_event_add(hContact, &dbei); + + lua_pushinteger(L, res); + return 1; + } + + lua_pushinteger(L, res); + + return 1; +} + +static luaL_Reg messageApi[] = +{ + { "Paste", message_Paste }, + { "Send", message_Send }, + + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_message(lua_State *L) +{ + luaL_newlib(L, messageApi); + + MT<MessageWindowEventData>(L, "MessageWindowEventData") + .Field(&MessageWindowEventData::uType, "Type", LUA_TINTEGER) + .Field(&MessageWindowEventData::hContact, "hContact", LUA_TINTEGER) + .Field(&MessageWindowEventData::uFlags, "Flags", LUA_TINTEGER); + + return 1; +} diff --git a/plugins/MirLua/src/Modules/m_options.cpp b/plugins/MirLua/src/Modules/m_options.cpp new file mode 100644 index 0000000000..babcfe3909 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_options.cpp @@ -0,0 +1,117 @@ +#include "../stdafx.h" + +class CMLuaScriptOptionPage : public CDlgBase +{ +private: + int m_onInitDialogRef; + int m_onApplyRef; + lua_State *L; + +public: + CMLuaScriptOptionPage(lua_State *_L, int onInitDialogRef, int onApplyRef) + : CDlgBase(g_plugin, IDD_SCRIPTOPTIONSPAGE), L(_L), + m_onInitDialogRef(onInitDialogRef), m_onApplyRef(onApplyRef) + { + } + + void OnInitDialog() override + { + if (m_onInitDialogRef) + { + lua_rawgeti(L, LUA_REGISTRYINDEX, m_onInitDialogRef); + lua_pushlightuserdata(L, m_hwnd); + luaM_pcall(L, 1, 0); + } + } + + void OnApply() override + { + if (m_onApplyRef) + { + lua_rawgeti(L, LUA_REGISTRYINDEX, m_onApplyRef); + lua_pushlightuserdata(L, m_hwnd); + luaM_pcall(L, 1, 0); + } + } + + void OnDestroy() override + { + lua_pushnil(L); + lua_rawsetp(L, LUA_REGISTRYINDEX, this); + } +}; + +void MakeOptionDialogPage(lua_State *L, OPTIONSDIALOGPAGE &odp) +{ + odp.hInstance = g_plugin.getInst(); + odp.langId = CMLuaEnvironment::GetEnvironmentId(L); + + lua_getfield(L, -1, "Flags"); + odp.flags = luaL_optinteger(L, -1, ODPF_BOLDGROUPS | ODPF_UNICODE | ODPF_DONTTRANSLATE); + lua_pop(L, 1); + + if (!(odp.flags & ODPF_UNICODE)) + odp.flags |= ODPF_UNICODE; + + lua_getfield(L, -1, "Group"); + odp.szGroup.w = mir_utf8decodeW(lua_tostring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Title"); + odp.szTitle.w = mir_utf8decodeW(luaL_checkstring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Tab"); + odp.szTab.w = mir_utf8decodeW(lua_tostring(L, -1)); + lua_pop(L, 1); + + int onInitDialogRef = LUA_NOREF; + lua_getfield(L, -1, "OnInitDialog"); + if (lua_isfunction(L, -1)) + onInitDialogRef = luaL_ref(L, LUA_REGISTRYINDEX); + else + lua_pop(L, 1); + + int onApplyRef = LUA_NOREF; + lua_getfield(L, -1, "OnApply"); + if (lua_isfunction(L, -1)) + onApplyRef = luaL_ref(L, LUA_REGISTRYINDEX); + else + lua_pop(L, 1); + + lua_State *T = lua_newthread(L); + lua_rawsetp(L, LUA_REGISTRYINDEX, T); + odp.pDialog = new CMLuaScriptOptionPage(T, onInitDialogRef, onApplyRef); +} + +int opt_AddPage(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TLIGHTUSERDATA); + WPARAM wParam = (WPARAM)lua_touserdata(L, 1); + + OPTIONSDIALOGPAGE odp = { 0 }; + MakeOptionDialogPage(L, odp); + + INT_PTR res = Options_AddPage(wParam, &odp); + lua_pushboolean(L, !res); + + mir_free(odp.szGroup.w); + mir_free(odp.szTitle.w); + mir_free(odp.szTab.w); + + return 1; +} + +static luaL_Reg optionsApi[] = +{ + { "AddPage", opt_AddPage }, + + { nullptr, nullptr } +}; + +LUAMOD_API int luaopen_m_options(lua_State *L) +{ + luaL_newlib(L, optionsApi); + + return 1; +}
\ No newline at end of file diff --git a/plugins/MirLua/src/Modules/m_protocols.cpp b/plugins/MirLua/src/Modules/m_protocols.cpp new file mode 100644 index 0000000000..1dac3e3ea6 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_protocols.cpp @@ -0,0 +1,281 @@ +#include "../stdafx.h"
+
+#define MT_PROTOCOLDESCRIPTOR "PROTOCOLDESCRIPTOR"
+
+HANDLE hRecvMessage = nullptr;
+
+static int lua_GetProtocol(lua_State *L)
+{
+ const char *szProto = nullptr;
+
+ switch (lua_type(L, 1)) {
+ case LUA_TNUMBER:
+ {
+ const char *szModule = GetContactProto(lua_tonumber(L, 1));
+ PROTOACCOUNT *pa = Proto_GetAccount(szModule);
+ if (pa)
+ szProto = pa->szProtoName;
+ break;
+ }
+ case LUA_TSTRING:
+ szProto = lua_tostring(L, 1);
+ break;
+ default:
+ luaL_argerror(L, 1, luaL_typename(L, 1));
+ }
+
+ PROTOCOLDESCRIPTOR *pd = Proto_IsProtocolLoaded(szProto);
+ if (pd)
+ MT<PROTOCOLDESCRIPTOR>::Apply(L, pd);
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int lua_ProtocolIterator(lua_State *L)
+{
+ int i = lua_tointeger(L, lua_upvalueindex(1));
+ int count = lua_tointeger(L, lua_upvalueindex(2));
+ PROTOCOLDESCRIPTOR **protos = (PROTOCOLDESCRIPTOR**)lua_touserdata(L, lua_upvalueindex(3));
+
+ if (i < count) {
+ lua_pushinteger(L, (i + 1));
+ lua_replace(L, lua_upvalueindex(1));
+ MT<PROTOCOLDESCRIPTOR>::Apply(L, protos[i]);
+ }
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int lua_Protocols(lua_State *L)
+{
+ int count;
+ PROTOCOLDESCRIPTOR **protos;
+ Proto_EnumProtocols(&count, &protos);
+
+ lua_pushinteger(L, 0);
+ lua_pushinteger(L, count);
+ lua_pushlightuserdata(L, protos);
+ lua_pushcclosure(L, lua_ProtocolIterator, 3);
+
+ return 1;
+}
+
+static int lua_ChainSend(lua_State *L)
+{
+ MCONTACT hContact = luaL_checknumber(L, 1);
+ const char *service = luaL_checkstring(L, 2);
+ WPARAM wParam = (WPARAM)luaM_tomparam(L, 3);
+ LPARAM lParam = (LPARAM)luaM_tomparam(L, 4);
+
+ INT_PTR res = ProtoChainSend(hContact, service, wParam, lParam);
+ lua_pushinteger(L, res);
+
+ return 1;
+}
+
+static int lua_ChainRecv(lua_State *L)
+{
+ MCONTACT hContact = luaL_checknumber(L, 1);
+ const char *service = luaL_checkstring(L, 2);
+ WPARAM wParam = (WPARAM)luaM_tomparam(L, 3);
+ LPARAM lParam = (LPARAM)luaM_tomparam(L, 4);
+
+ INT_PTR res = ProtoChainRecv(hContact, service, wParam, lParam);
+ lua_pushinteger(L, res);
+
+ return 1;
+}
+
+/***********************************************/
+
+static int lua_GetAccount(lua_State *L)
+{
+ const char *name = nullptr;
+
+ switch (lua_type(L, 1))
+ {
+ case LUA_TNUMBER:
+ name = GetContactProto(lua_tonumber(L, 1));
+ break;
+ case LUA_TSTRING:
+ name = lua_tostring(L, 1);
+ break;
+ default:
+ luaL_argerror(L, 1, luaL_typename(L, 1));
+ }
+
+ PROTOACCOUNT *pa = Proto_GetAccount(name);
+ if (pa)
+ MT<PROTOACCOUNT>::Apply(L, pa);
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int lua_AccountIterator(lua_State *L)
+{
+ int i = lua_tointeger(L, lua_upvalueindex(1));
+ int count = lua_tointeger(L, lua_upvalueindex(2));
+ PROTOACCOUNT **accounts = (PROTOACCOUNT**)lua_touserdata(L, lua_upvalueindex(3));
+ const char *szProto = lua_tostring(L, lua_upvalueindex(4));
+
+ if (szProto)
+ while (i < count && mir_strcmp(szProto, accounts[i]->szProtoName))
+ i++;
+
+ if (i < count)
+ {
+ lua_pushinteger(L, (i + 1));
+ lua_replace(L, lua_upvalueindex(1));
+ MT<PROTOACCOUNT>::Apply(L, accounts[i]);
+ }
+ else
+ lua_pushnil(L);
+
+ return 1;
+}
+
+static int lua_Accounts(lua_State *L)
+{
+ const char *szProto = nullptr;
+
+ switch (lua_type(L, 1))
+ {
+ case LUA_TNONE:
+ break;
+ case LUA_TSTRING:
+ szProto = lua_tostring(L, 1);
+ break;
+ case LUA_TUSERDATA:
+ {
+ PROTOCOLDESCRIPTOR *pd = *(PROTOCOLDESCRIPTOR**)luaL_checkudata(L, 1, MT_PROTOCOLDESCRIPTOR);
+ szProto = pd->szName;
+ break;
+ }
+ default:
+ luaL_argerror(L, 1, luaL_typename(L, 1));
+ }
+
+ int count;
+ PROTOACCOUNT **accounts;
+ Proto_EnumAccounts(&count, &accounts);
+
+ lua_pushinteger(L, 0);
+ lua_pushinteger(L, count);
+ lua_pushlightuserdata(L, accounts);
+ lua_pushstring(L, szProto);
+ lua_pushcclosure(L, lua_AccountIterator, 4);
+
+ return 1;
+}
+
+static int lua_CallService(lua_State *L)
+{
+ const char *szModule = nullptr;
+
+ switch (lua_type(L, 1))
+ {
+ case LUA_TNUMBER:
+ szModule = GetContactProto(lua_tonumber(L, 1));
+ 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));
+ }
+
+ const char *service = luaL_checkstring(L, 2);
+ WPARAM wParam = (WPARAM)luaM_tomparam(L, 3);
+ LPARAM lParam = (LPARAM)luaM_tomparam(L, 4);
+
+ INT_PTR res = CallProtoService(szModule, service, wParam, lParam);
+ lua_pushinteger(L, res);
+
+ return 1;
+}
+
+/***********************************************/
+
+INT_PTR FilterRecvMessage(WPARAM wParam, LPARAM lParam)
+{
+ int res = NotifyEventHooks(hRecvMessage, wParam, lParam);
+ if (res) return res;
+ Proto_ChainRecv(wParam, (CCSDATA*)lParam);
+ return 0;
+}
+
+/***********************************************/
+
+static luaL_Reg protocolsApi[] =
+{
+ { "GetProtocol", lua_GetProtocol },
+ { "Protocols", lua_Protocols },
+
+ { "CallSendChain", lua_ChainSend },
+ { "CallReceiveChain", lua_ChainRecv },
+
+ { "GetAccount", lua_GetAccount },
+ { "Accounts", lua_Accounts },
+
+ { "CallService", lua_CallService },
+
+ { nullptr, nullptr }
+};
+
+/***********************************************/
+
+LUAMOD_API int luaopen_m_protocols(lua_State *L)
+{
+ hRecvMessage = CreateHookableEvent(MODULENAME PSR_MESSAGE);
+ CreateProtoServiceFunction(MODULENAME, PSR_MESSAGE, FilterRecvMessage);
+
+ luaL_newlib(L, protocolsApi);
+
+ MT<PROTOCOLDESCRIPTOR>(L, MT_PROTOCOLDESCRIPTOR)
+ .Field(&PROTOCOLDESCRIPTOR::szName, "Name", LUA_TSTRINGA)
+ .Field(&PROTOCOLDESCRIPTOR::type, "Type", LUA_TINTEGER)
+ .Field(lua_Accounts, "Accounts");
+
+ MT<PROTOACCOUNT>(L, MT_PROTOACCOUNT)
+ .Field(&PROTOACCOUNT::szModuleName, "ModuleName", LUA_TSTRINGA)
+ .Field(&PROTOACCOUNT::tszAccountName, "AccountName", LUA_TSTRINGW)
+ .Field(&PROTOACCOUNT::szProtoName, "ProtoName", LUA_TSTRINGA)
+ .Field(&PROTOACCOUNT::bIsEnabled, "IsEnabled", LUA_TBOOLEAN)
+ .Field(&PROTOACCOUNT::bIsVisible, "IsVisible", LUA_TBOOLEAN)
+ .Field(&PROTOACCOUNT::bIsVirtual, "IsVirtual", LUA_TBOOLEAN)
+ .Field(&PROTOACCOUNT::bOldProto, "IsOldProto", LUA_TBOOLEAN)
+ .Field(lua_CallService, "CallService");
+
+ MT<ACKDATA>(L, "ACKDATA")
+ .Field(&ACKDATA::szModule, "Module", LUA_TSTRINGA)
+ .Field(&ACKDATA::hContact, "hContact", LUA_TINTEGER)
+ .Field(&ACKDATA::type, "Type", LUA_TINTEGER)
+ .Field(&ACKDATA::result, "Result", LUA_TINTEGER)
+ .Field(&ACKDATA::hProcess, "hProcess", LUA_TLIGHTUSERDATA)
+ .Field(&ACKDATA::lParam, "lParam", LUA_TLIGHTUSERDATA);
+
+ MT<CCSDATA>(L, "CCSDATA")
+ .Field(&CCSDATA::hContact, "hContact", LUA_TINTEGER)
+ .Field(&CCSDATA::szProtoService, "Service", LUA_TSTRINGA)
+ .Field(&CCSDATA::wParam, "wParam", LUA_TLIGHTUSERDATA)
+ .Field(&CCSDATA::lParam, "lParam", LUA_TLIGHTUSERDATA);
+
+ MT<PROTORECVEVENT>(L, "PROTORECVEVENT")
+ .Field(&PROTORECVEVENT::timestamp, "Timestamp", LUA_TINTEGER)
+ .Field(&PROTORECVEVENT::flags, "Flags", LUA_TINTEGER)
+ .Field(&PROTORECVEVENT::szMessage, "Message", LUA_TSTRING);
+
+ return 1;
+}
diff --git a/plugins/MirLua/src/Modules/m_sounds.cpp b/plugins/MirLua/src/Modules/m_sounds.cpp new file mode 100644 index 0000000000..74b17f12cd --- /dev/null +++ b/plugins/MirLua/src/Modules/m_sounds.cpp @@ -0,0 +1,54 @@ +#include "../stdafx.h"
+
+static int lua_AddSound(lua_State *L)
+{
+ ptrA name(mir_utf8decodeA(luaL_checkstring(L, 1)));
+ ptrW description(mir_utf8decodeW(luaL_checkstring(L, 2)));
+ ptrW section(mir_utf8decodeW(luaL_optstring(L, 3, MODULENAME)));
+ ptrW filePath(mir_utf8decodeW(lua_tostring(L, 4)));
+
+ int res = 1;
+ CMPluginBase *pPlugin = CMLuaEnvironment::GetEnvironment(L);
+ if (pPlugin != nullptr)
+ res = pPlugin->addSound(name, section, description, filePath);
+ lua_pushboolean(L, res == 0);
+
+ return 1;
+}
+
+static int lua_PlaySound(lua_State *L)
+{
+ const char *name = luaL_checkstring(L, 1);
+
+ INT_PTR res = Skin_PlaySound(name);
+ lua_pushboolean(L, res == 0);
+
+ return 1;
+}
+
+static int lua_PlayFile(lua_State *L)
+{
+ ptrW filePath(mir_utf8decodeW(luaL_checkstring(L, 1)));
+
+ INT_PTR res = Skin_PlaySoundFile(filePath);
+ lua_pushboolean(L, res == 0);
+
+ return 1;
+}
+
+static luaL_Reg soundApi[] =
+{
+ { "AddSound", lua_AddSound },
+
+ { "PlaySound", lua_PlaySound },
+ { "PlayFile", lua_PlayFile },
+
+ { nullptr, nullptr }
+};
+
+LUAMOD_API int luaopen_m_sounds(lua_State *L)
+{
+ luaL_newlib(L, soundApi);
+
+ return 1;
+}
diff --git a/plugins/MirLua/src/Modules/m_srmm.cpp b/plugins/MirLua/src/Modules/m_srmm.cpp new file mode 100644 index 0000000000..f7296d1d70 --- /dev/null +++ b/plugins/MirLua/src/Modules/m_srmm.cpp @@ -0,0 +1,138 @@ +#include "../stdafx.h" + +#define MT_BBBUTTON "BBButton" + +static void MakeBBButton(lua_State *L, BBButton &bbb) +{ + bbb.dwDefPos = 100; + + lua_getfield(L, -1, "Module"); + bbb.pszModuleName = mir_utf8decodeA(luaL_checkstring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "ButtonId"); + bbb.dwButtonID = luaL_checkinteger(L, -1); + lua_pop(L, 1); + + lua_getfield(L, -1, "Flags"); + bbb.bbbFlags = luaL_optinteger(L, -1, BBBF_ISIMBUTTON); + lua_pop(L, 1); + + lua_getfield(L, -1, "Text"); + bbb.pwszText = mir_utf8decodeW(lua_tostring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Tooltip"); + bbb.pwszTooltip = mir_utf8decodeW(lua_tostring(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, -1, "Icon"); + bbb.hIcon = (HANDLE)lua_touserdata(L, -1); + lua_pop(L, 1); +} + +static void CleanBBButton(BBButton &bbb) +{ + mir_free((void*)bbb.pszModuleName); + mir_free((void*)bbb.pwszText); + mir_free((void*)bbb.pwszTooltip); +} + +/***********************************************/ + +static int lua_AddButton(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + BBButton bbb = {}; + MakeBBButton(L, bbb); + + int hScriptLangpack = CMLuaEnvironment::GetEnvironmentId(L); + HANDLE res = Srmm_AddButton(&bbb, hScriptLangpack); + CleanBBButton(bbb); + + if (!res) + { + lua_pushnil(L); + return 1; + } + + lua_pushvalue(L, 1); + luaL_setmetatable(L, MT_BBBUTTON); + + return 1; +} + +static int lua_ModifyButton(lua_State *L) +{ + luaL_checktype(L, 1, LUA_TTABLE); + + lua_pushvalue(L, 1); + + BBButton bbb = {}; + MakeBBButton(L, bbb); + INT_PTR res = Srmm_ModifyButton(&bbb); + CleanBBButton(bbb); + lua_pushboolean(L, !res); + + return 2; +} + +static int lua_RemoveButton(lua_State *L) +{ + BBButton bbb = {}; + + switch (lua_type(L, 1)) + { + case LUA_TSTRING: + bbb.pszModuleName = mir_utf8decodeA(lua_tostring(L, 1)); + bbb.dwButtonID = luaL_checkinteger(L, 2); + break; + case LUA_TTABLE: + MakeBBButton(L, bbb); + break; + default: + luaL_argerror(L, 1, luaL_typename(L, 1)); + } + + INT_PTR res = Srmm_RemoveButton(&bbb); + CleanBBButton(bbb); + lua_pushboolean(L, !res); + + return 1; +} + +static luaL_Reg srmmApi[] = +{ + { "AddButton", lua_AddButton }, + { "ModifyButton", lua_ModifyButton }, + { "RemoveButton", lua_RemoveButton }, + + { nullptr, nullptr } +}; + +/***********************************************/ + +LUAMOD_API int luaopen_m_srmm(lua_State *L) +{ + luaL_newlib(L, srmmApi); + + luaL_newmetatable(L, MT_BBBUTTON); + lua_pushvalue(L, -1); + lua_setfield(L, -2, "__index"); + lua_pushliteral(L, MT_BBBUTTON); + lua_setfield(L, -2, "__metatable"); + lua_pushcfunction(L, lua_ModifyButton); + lua_setfield(L, -2, "Modify"); + lua_pushcfunction(L, lua_RemoveButton); + lua_setfield(L, -2, "Remove"); + lua_pop(L, 1); + + MT<CustomButtonClickData>(L, "CustomButtonClickData") + .Field(&CustomButtonClickData::pszModule, "Module", LUA_TSTRINGA) + .Field(&CustomButtonClickData::dwButtonId, "ButtonId", LUA_TINTEGER) + .Field(&CustomButtonClickData::hContact, "hContact", LUA_TINTEGER) + .Field(&CustomButtonClickData::flags, "Flags", LUA_TINTEGER); + + return 1; +} |