/*
* PtokaX - hub server for Direct Connect peer to peer network.
* Copyright (C) 2004-2022 Petr Kozelka, PPK at PtokaX dot org
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3
* as published by the Free Software Foundation.
* 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, see <http://www.gnu.org/licenses/>.
*/
//------------------------------------------------------------------------------
#include "stdinc.h"
//------------------------------------------------------------------------------
#include "LuaInc.h"
//------------------------------------------------------------------------------
#include "LuaScriptManager.h"
//------------------------------------------------------------------------------
#include "ServerManager.h"
#include "SettingManager.h"
#include "User.h"
#include "utility.h"
#include "tinyxml.h"
#include "GlobalDataQueue.h"
//------------------------------------------------------------------------------
#ifdef _WIN32
#pragma hdrstop
#endif
//------------------------------------------------------------------------------
#include "LuaScript.h"
//------------------------------------------------------------------------------
#ifdef _BUILD_GUI
#include "../gui.win/MainWindowPageScripts.h"
#endif
//------------------------------------------------------------------------------
ScriptManager * ScriptManager::m_Ptr = NULL;
//------------------------------------------------------------------------------
void ScriptManager::LoadXML()
{
// PPK ... first start all script in order from xml file
#ifdef _WIN32
TiXmlDocument doc((ServerManager::m_sPath + "\\cfg\\Scripts.xml").c_str());
#else
TiXmlDocument doc((ServerManager::m_sPath + "/cfg/Scripts.xml").c_str());
#endif
if (doc.LoadFile() == false)
{
if (doc.ErrorId() != TiXmlBase::TIXML_ERROR_OPENING_FILE && doc.ErrorId() != TiXmlBase::TIXML_ERROR_DOCUMENT_EMPTY)
{
int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "Error loading file Scripts.xml. %s (Col: %d, Row: %d)", doc.ErrorDesc(), doc.Column(), doc.Row());
if (iMsgLen > 0)
{
#ifdef _BUILD_GUI
::MessageBox(NULL, ServerManager::m_pGlobalBuffer, g_sPtokaXTitle, MB_OK | MB_ICONERROR);
#else
AppendLog(ServerManager::m_pGlobalBuffer);
#endif
}
exit(EXIT_FAILURE);
}
}
else
{
TiXmlHandle cfg(&doc);
TiXmlNode *scripts = cfg.FirstChild("Scripts").Node();
if (scripts != NULL)
{
TiXmlNode *child = NULL;
while ((child = scripts->IterateChildren(child)) != NULL)
{
TiXmlNode *script = child->FirstChild("Name");
if (script == NULL || (script = script->FirstChild()) == NULL)
{
continue;
}
char *name = (char *)script->Value();
if (FileExist((ServerManager::m_sScriptPath + string(name)).c_str()) == false)
{
continue;
}
if ((script = child->FirstChild("Enabled")) == NULL ||
(script = script->FirstChild()) == NULL)
{
continue;
}
bool enabled = atoi(script->Value()) == 0 ? false : true;
if (FindScript(name) != NULL)
{
continue;
}
AddScript(name, enabled, false);
}
}
}
}
//------------------------------------------------------------------------------
ScriptManager::ScriptManager() : m_pRunningScriptE(NULL), m_pRunningScriptS(NULL), m_ppScriptTable(NULL), m_pActualUser(NULL), m_pTimerListS(NULL), m_pTimerListE(NULL), m_ui8ScriptCount(0), m_ui8BotsCount(0), m_bMoved(false)
{
#ifdef _WIN32
if (FileExist((ServerManager::m_sPath + "\\cfg\\Scripts.pxt").c_str()) == false)
{
#else
if (FileExist((ServerManager::m_sPath + "/cfg/Scripts.pxt").c_str()) == false)
{
#endif
LoadXML();
return;
}
#ifdef _WIN32
FILE * fScriptsFile = fopen((ServerManager::m_sPath + "\\cfg\\Scripts.pxt").c_str(), "rt");
#else
FILE * fScriptsFile = fopen((ServerManager::m_sPath + "/cfg/Scripts.pxt").c_str(), "rt");
#endif
if (fScriptsFile == NULL)
{
int iMsgLen = snprintf(ServerManager::m_pGlobalBuffer, ServerManager::m_szGlobalBufferSize, "Error loading file Scripts.pxt %s (%d)",
#ifdef _WIN32
WSErrorStr(errno), errno);
#else
ErrnoStr(errno), errno);
#endif
if (iMsgLen > 0)
{
#ifdef _BUILD_GUI
::MessageBox(NULL, ServerManager::m_pGlobalBuffer, g_sPtokaXTitle, MB_OK | MB_ICONERROR);
#else
AppendLog(ServerManager::m_pGlobalBuffer);
#endif
}
exit(EXIT_FAILURE);
}
size_t szLen = 0;
while (fgets(ServerManager::m_pGlobalBuffer, (int)ServerManager::m_szGlobalBufferSize, fScriptsFile) != NULL)
{
if (ServerManager::m_pGlobalBuffer[0] == '#' || ServerManager::m_pGlobalBuffer[0] == '\n')
{
continue;
}
szLen = strlen(ServerManager::m_pGlobalBuffer) - 1;
if (szLen < 7)
{
continue;
}
ServerManager::m_pGlobalBuffer[szLen] = '\0';
for (size_t szi = szLen - 1; szi != 0; szi--)
{
if (isspace(ServerManager::m_pGlobalBuffer[szi - 1]) != 0 || ServerManager::m_pGlobalBuffer[szi - 1] == '=')
{
ServerManager::m_pGlobalBuffer[szi - 1] = '\0';
continue;
}
break;
}
if (ServerManager::m_pGlobalBuffer[0] == '\0' || (ServerManager::m_pGlobalBuffer[szLen - 1] != '1' && ServerManager::m_pGlobalBuffer[szLen - 1] != '0'))
{
continue;
}
if (FileExist((ServerManager::m_sScriptPath + string(ServerManager::m_pGlobalBuffer)).c_str()) == false || FindScript(ServerManager::m_pGlobalBuffer) != NULL)
{
continue;
}
AddScript(ServerManager::m_pGlobalBuffer, ServerManager::m_pGlobalBuffer[szLen - 1] == '1' ? true : false, false);
}
fclose(fScriptsFile);
}
//------------------------------------------------------------------------------
ScriptManager::~ScriptManager()
{
m_pRunningScriptS = NULL;
m_pRunningScriptE = NULL;
for (uint8_t ui8i = 0; ui8i < m_ui8ScriptCount; ui8i++)
{
delete m_ppScriptTable[ui8i];
}
safe_free(m_ppScriptTable);
m_ui8ScriptCount = 0;
m_pActualUser = NULL;
m_ui8BotsCount = 0;
}
//------------------------------------------------------------------------------
void ScriptManager::Start()
{
m_ui8BotsCount = 0;
m_pActualUser = NULL;
// PPK ... first look for deleted and new scripts
CheckForDeletedScripts();
CheckForNewScripts();
// PPK ... second start all enabled scripts
for (uint8_t ui8i = 0; ui8i < m_ui8ScriptCount; ui8i++)
{
if (m_ppScriptTable[ui8i]->m_bEnabled == true)
{
if (ScriptStart(m_ppScriptTable[ui8i]) == true)
{
AddRunningScript(m_ppScriptTable[ui8i]);
}
else
{
m_ppScriptTable[ui8i]->m_bEnabled = false;
}
}
}
#ifdef _BUILD_GUI
MainWindowPageScripts::m_Ptr->AddScriptsToList(true);
#endif
}
//------------------------------------------------------------------------------
#ifdef _BUILD_GUI
bool ScriptManager::AddScript(const char * sName, const bool bEnabled, const bool bNew)
{
#else
bool ScriptManager::AddScript(const char * sName, const bool bEnabled, const bool /*bNew*/)
{
#endif
if (m_ui8ScriptCount == 254)
{
return false;
}
Script ** oldbuf = m_ppScriptTable;
m_ppScriptTable = (Script **)realloc(oldbuf, (m_ui8ScriptCount + 1) * sizeof(Script *));
if (m_ppScriptTable == NULL)
{
m_ppScriptTable = oldbuf;
AppendDebugLog("%s - [MEM] Cannot (re)allocate m_ppScriptTable in ScriptManager::AddScript\n");
return false;
}
m_ppScriptTable[m_ui8ScriptCount] = Script::CreateScript(sName, bEnabled);
if (m_ppScriptTable[m_ui8ScriptCount] == NULL)
{
AppendDebugLog("%s - [MEM] Cannot allocate new Script in ScriptManager::AddScript\n");
return false;
}
m_ui8ScriptCount++;
#ifdef _BUILD_GUI
if (bNew == true)
{
MainWindowPageScripts::m_Ptr->ScriptToList(m_ui8ScriptCount - 1, true, false);
}
#endif
return true;
}
//------------------------------------------------------------------------------
void ScriptManager::Stop()
{
Script * S = NULL,
* next = m_pRunningScriptS;
m_pRunningScriptS = NULL;
m_pRunningScriptE = NULL;
while (next != NULL)
{
S = next;
next = S->m_pNext;
ScriptStop(S);
}
m_pActualUser = NULL;
#ifdef _BUILD_GUI
MainWindowPageScripts::m_Ptr->ClearMemUsageAll();
#endif
}
//------------------------------------------------------------------------------
void ScriptManager::AddRunningScript(Script * pScript)
{
if (m_pRunningScriptS == NULL)
{
m_pRunningScriptS = pScript;
m_pRunningScriptE = pScript;
return;
}
pScript->m_pPrev = m_pRunningScriptE;
m_pRunningScriptE->m_pNext = pScript;
m_pRunningScriptE = pScript;
}
//------------------------------------------------------------------------------
void ScriptManager::RemoveRunningScript(Script * pScript)
{
// single entry
if (pScript->m_pPrev == NULL && pScript->m_pNext == NULL)
{
m_pRunningScriptS = NULL;
m_pRunningScriptE = NULL;
return;
}
// first in list
if (pScript->m_pPrev == NULL)
{
m_pRunningScriptS = pScript->m_pNext;
m_pRunningScriptS->m_pPrev = NULL;
return;
}
// last in list
if (pScript->m_pNext == NULL)
{
m_pRunningScriptE = pScript->m_pPrev;
m_pRunningScriptE->m_pNext = NULL;
return;
}
// in the middle
pScript->m_pPrev->m_pNext = pScript->m_pNext;
pScript->m_pNext->m_pPrev = pScript->m_pPrev;
}
//------------------------------------------------------------------------------
void ScriptManager::SaveScripts()
{
#ifdef _WIN32
FILE * fScriptsFile = fopen((ServerManager::m_sPath + "\\cfg\\Scripts.pxt").c_str(), "wb");
#else
FILE * fScriptsFile = fopen((ServerManager::m_sPath + "/cfg/Scripts.pxt").c_str(), "wb");
#endif
if (fScriptsFile == NULL)
{
return;
}
static const char sPtokaXScriptsFile[] = "#\n# PtokaX scripts settings file\n#\n\n";
fwrite(sPtokaXScriptsFile, 1, sizeof(sPtokaXScriptsFile) - 1, fScriptsFile);
for (uint8_t ui8i = 0; ui8i < m_ui8ScriptCount; ui8i++)
{
if (FileExist((ServerManager::m_sScriptPath + string(m_ppScriptTable[ui8i]->m_sName)).c_str()) == false)
{
continue;
}
fprintf(fScriptsFile, "%s\t=\t%c\n", m_ppScriptTable[ui8i]->m_sName, m_ppScriptTable[ui8i]->m_bEnabled == true ? '1' : '0');
}
fclose(fScriptsFile);
}
//------------------------------------------------------------------------------
void ScriptManager::CheckForDeletedScripts()
{
uint8_t ui8i = 0;
while (ui8i < m_ui8ScriptCount)
{
if (FileExist((ServerManager::m_sScriptPath + string(m_ppScriptTable[ui8i]->m_sName)).c_str()) == true || m_ppScriptTable[ui8i]->m_pLua != NULL)
{
ui8i++;
continue;
}
delete m_ppScriptTable[ui8i];
for (uint8_t ui8j = ui8i; ui8j + 1 < m_ui8ScriptCount; ui8j++)
{
m_ppScriptTable[ui8j] = m_ppScriptTable[ui8j + 1];
}
m_ppScriptTable[m_ui8ScriptCount - 1] = NULL;
m_ui8ScriptCount--;
}
}
//------------------------------------------------------------------------------
void ScriptManager::CheckForNewScripts()
{
#ifdef _WIN32
struct _finddata_t luafile;
intptr_t hFile = _findfirst((ServerManager::m_sScriptPath + "\\*.lua").c_str(), &luafile);
if (hFile != -1)
{
do
{
if ((luafile.attrib & _A_SUBDIR) != 0 ||
stricmp(luafile.name + (strlen(luafile.name) - 4), ".lua") != 0)
{
continue;
}
if (FindScript(luafile.name) != NULL)
{
continue;
}
AddScript(luafile.name, false, false);
}
while (_findnext(hFile, &luafile) == 0);
_findclose(hFile);
}
#else
DIR * p_scriptdir = opendir(ServerManager::m_sScriptPath.c_str());
if (p_scriptdir == NULL)
{
return;
}
struct dirent * p_dirent;
struct stat s_buf;
while ((p_dirent = readdir(p_scriptdir)) != NULL)
{
if (stat((ServerManager::m_sScriptPath + p_dirent->d_name).c_str(), &s_buf) != 0 ||
(s_buf.st_mode & S_IFDIR) != 0 ||
strcasecmp(p_dirent->d_name + (strlen(p_dirent->d_name) - 4), ".lua") != 0)
{
continue;
}
if (FindScript(p_dirent->d_name) != NULL)
{
continue;
}
AddScript(p_dirent->d_name, false, false);
}
closedir(p_scriptdir);
#endif
}
//------------------------------------------------------------------------------
void ScriptManager::Restart()
{
OnExit();
Stop();
CheckForDeletedScripts();
Start();
OnStartup();
#ifdef _BUILD_GUI
MainWindowPageScripts::m_Ptr->AddScriptsToList(true);
#endif
}
//------------------------------------------------------------------------------
Script * ScriptManager::FindScript(const char * sName)
{
for (uint8_t ui8i = 0; ui8i < m_ui8ScriptCount; ui8i++)
{
if (strcasecmp(m_ppScriptTable[ui8i]->m_sName, sName) == 0)
{
return m_ppScriptTable[ui8i];
}
}
return NULL;
}
//------------------------------------------------------------------------------
Script * ScriptManager::FindScript(const lua_State * pLua)
{
Script * cur = NULL,
* next = m_pRunningScriptS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
if (cur->m_pLua == pLua)
{
return cur;
}
}
return NULL;
}
//------------------------------------------------------------------------------
uint8_t ScriptManager::FindScriptIdx(const char * sName)
{
for (uint8_t ui8i = 0; ui8i < m_ui8ScriptCount; ui8i++)
{
if (strcasecmp(m_ppScriptTable[ui8i]->m_sName, sName) == 0)
{
return ui8i;
}
}
return m_ui8ScriptCount;
}
//------------------------------------------------------------------------------
bool ScriptManager::StartScript(Script * pScript, const bool bEnable)
{
uint8_t ui8dx = 255;
for (uint8_t ui8i = 0; ui8i < m_ui8ScriptCount; ui8i++)
{
if (pScript == m_ppScriptTable[ui8i])
{
ui8dx = ui8i;
break;
}
}
if (ui8dx == 255)
{
return false;
}
if (bEnable == true)
{
pScript->m_bEnabled = true;
#ifdef _BUILD_GUI
MainWindowPageScripts::m_Ptr->UpdateCheck(ui8dx);
#endif
}
if (ScriptStart(pScript) == false)
{
pScript->m_bEnabled = false;
#ifdef _BUILD_GUI
MainWindowPageScripts::m_Ptr->UpdateCheck(ui8dx);
#endif
return false;
}
if (m_pRunningScriptS == NULL)
{
m_pRunningScriptS = pScript;
m_pRunningScriptE = pScript;
}
else
{
// previous script
if (ui8dx != 0)
{
for (int16_t i16i = (int16_t)(ui8dx - 1); i16i > -1; i16i--)
{
if (m_ppScriptTable[i16i]->m_bEnabled == true)
{
m_ppScriptTable[i16i]->m_pNext = pScript;
pScript->m_pPrev = m_ppScriptTable[i16i];
break;
}
}
if (pScript->m_pPrev == NULL)
{
m_pRunningScriptS = pScript;
}
}
else
{
pScript->m_pNext = m_pRunningScriptS;
m_pRunningScriptS->m_pPrev = pScript;
m_pRunningScriptS = pScript;
}
// next script
if (ui8dx != m_ui8ScriptCount - 1)
{
for (uint8_t ui8i = ui8dx + 1; ui8i < m_ui8ScriptCount; ui8i++)
{
if (m_ppScriptTable[ui8i]->m_bEnabled == true)
{
m_ppScriptTable[ui8i]->m_pPrev = pScript;
pScript->m_pNext = m_ppScriptTable[ui8i];
break;
}
}
if (pScript->m_pNext == NULL)
{
m_pRunningScriptE = pScript;
}
}
else
{
pScript->m_pPrev = m_pRunningScriptE;
m_pRunningScriptE->m_pNext = pScript;
m_pRunningScriptE = pScript;
}
}
if (ServerManager::m_bServerRunning == true)
{
ScriptOnStartup(pScript);
}
return true;
}
//------------------------------------------------------------------------------
void ScriptManager::StopScript(Script * pScript, const bool bDisable)
{
if (bDisable == true)
{
pScript->m_bEnabled = false;
#ifdef _BUILD_GUI
for (uint8_t ui8i = 0; ui8i < m_ui8ScriptCount; ui8i++)
{
if (pScript == m_ppScriptTable[ui8i])
{
MainWindowPageScripts::m_Ptr->UpdateCheck(ui8i);
break;
}
}
#endif
}
RemoveRunningScript(pScript);
if (ServerManager::m_bServerRunning == true)
{
ScriptOnExit(pScript);
}
ScriptStop(pScript);
}
//------------------------------------------------------------------------------
void ScriptManager::MoveScript(const uint8_t ui8ScriptPosInTbl, const bool bUp)
{
if (bUp == true)
{
if (ui8ScriptPosInTbl == 0)
{
return;
}
Script * pScript = m_ppScriptTable[ui8ScriptPosInTbl];
m_ppScriptTable[ui8ScriptPosInTbl] = m_ppScriptTable[ui8ScriptPosInTbl - 1];
m_ppScriptTable[ui8ScriptPosInTbl - 1] = pScript;
// if one of moved scripts not running then return
if (pScript->m_pLua == NULL || m_ppScriptTable[ui8ScriptPosInTbl]->m_pLua == NULL)
{
return;
}
if (pScript->m_pPrev == NULL) // first running script, nothing to move
{
return;
}
else if (pScript->m_pNext == NULL) // last running script
{
// set prev script as last
m_pRunningScriptE = pScript->m_pPrev;
// change prev prev script next
if (m_pRunningScriptE->m_pPrev != NULL)
{
m_pRunningScriptE->m_pPrev->m_pNext = pScript;
}
else
{
m_pRunningScriptS = pScript;
}
// change current script prev and next
pScript->m_pPrev = m_pRunningScriptE->m_pPrev;
pScript->m_pNext = m_pRunningScriptE;
// change prev script prev to current and his next to NULL
m_pRunningScriptE->m_pPrev = pScript;
m_pRunningScriptE->m_pNext = NULL;
}
else // not first, not last ...
{
// remember original prev and next
Script * prev = pScript->m_pPrev;
Script * next = pScript->m_pNext;
// change current script prev
pScript->m_pPrev = prev->m_pPrev;
// change prev script next
prev->m_pNext = next;
// change current script next
pScript->m_pNext = prev;
// change next script prev
next->m_pPrev = prev;
// change prev prev script next
if (prev->m_pPrev != NULL)
{
prev->m_pPrev->m_pNext = pScript;
}
else
{
m_pRunningScriptS = pScript;
}
// change prev script prev
prev->m_pPrev = pScript;
}
}
else
{
if (ui8ScriptPosInTbl == m_ui8ScriptCount - 1)
{
return;
}
Script * pScript = m_ppScriptTable[ui8ScriptPosInTbl];
m_ppScriptTable[ui8ScriptPosInTbl] = m_ppScriptTable[ui8ScriptPosInTbl + 1];
m_ppScriptTable[ui8ScriptPosInTbl + 1] = pScript;
// if one of moved scripts not running then return
if (pScript->m_pLua == NULL || m_ppScriptTable[ui8ScriptPosInTbl]->m_pLua == NULL)
{
return;
}
if (pScript->m_pNext == NULL) // last running script, nothing to move
{
return;
}
else if (pScript->m_pPrev == NULL) // first running script
{
//set next running script as first
m_pRunningScriptS = pScript->m_pNext;
// change next next script prev
if (m_pRunningScriptS->m_pNext != NULL)
{
m_pRunningScriptS->m_pNext->m_pPrev = pScript;
}
else
{
m_pRunningScriptE = pScript;
}
// change current script prev and next
pScript->m_pPrev = m_pRunningScriptS;
pScript->m_pNext = m_pRunningScriptS->m_pNext;
// change next script next to current and his prev to NULL
m_pRunningScriptS->m_pPrev = NULL;
m_pRunningScriptS->m_pNext = pScript;
}
else // not first, not last ...
{
// remember original prev and next
Script * prev = pScript->m_pPrev;
Script * next = pScript->m_pNext;
// change current script next
pScript->m_pNext = next->m_pNext;
// change next script prev
next->m_pPrev = prev;
// change current script prev
pScript->m_pPrev = next;
// change prev script next
prev->m_pNext = next;
// change next next script prev
if (next->m_pNext != NULL)
{
next->m_pNext->m_pPrev = pScript;
}
else
{
m_pRunningScriptE = pScript;
}
// change next script next
next->m_pNext = pScript;
}
}
}
//------------------------------------------------------------------------------
void ScriptManager::DeleteScript(const uint8_t ui8ScriptPosInTbl)
{
Script * pScript = m_ppScriptTable[ui8ScriptPosInTbl];
if (pScript->m_pLua != NULL)
{
StopScript(pScript, false);
}
if (FileExist((ServerManager::m_sScriptPath + string(pScript->m_sName)).c_str()) == true)
{
#ifdef _WIN32
DeleteFile((ServerManager::m_sScriptPath + string(pScript->m_sName)).c_str());
#else
unlink((ServerManager::m_sScriptPath + string(pScript->m_sName)).c_str());
#endif
}
delete pScript;
for (uint8_t ui8i = ui8ScriptPosInTbl; ui8i + 1 < m_ui8ScriptCount; ui8i++)
{
m_ppScriptTable[ui8i] = m_ppScriptTable[ui8i + 1];
}
m_ppScriptTable[m_ui8ScriptCount - 1] = NULL;
m_ui8ScriptCount--;
}
//------------------------------------------------------------------------------
void ScriptManager::OnStartup()
{
if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_SCRIPTING] == false)
{
return;
}
m_pActualUser = NULL;
m_bMoved = false;
Script * pScript = NULL,
* next = m_pRunningScriptS;
while (next != NULL)
{
pScript = next;
next = pScript->m_pNext;
if (pScript->m_pLua != NULL &&((pScript->m_ui16Functions & Script::ONSTARTUP) == Script::ONSTARTUP) == true && (m_bMoved == false || pScript->m_bProcessed == false))
{
pScript->m_bProcessed = true;
ScriptOnStartup(pScript);
}
}
}
//------------------------------------------------------------------------------
void ScriptManager::OnExit(const bool bForce/* = false*/)
{
if (bForce == false && SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_SCRIPTING] == false)
{
return;
}
m_pActualUser = NULL;
m_bMoved = false;
Script * pScript = NULL,
* next = m_pRunningScriptS;
while (next != NULL)
{
pScript = next;
next = pScript->m_pNext;
if (pScript->m_pLua != NULL &&((pScript->m_ui16Functions & Script::ONEXIT) == Script::ONEXIT) == true && (m_bMoved == false || pScript->m_bProcessed == false))
{
pScript->m_bProcessed = true;
ScriptOnExit(pScript);
}
}
}
//------------------------------------------------------------------------------
bool ScriptManager::Arrival(DcCommand * pDcCommand, const uint8_t ui8Type)
{
if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_SCRIPTING] == false)
{
return false;
}
static const uint32_t iLuaArrivalBits[] =
{
0x1,
0x2,
0x4,
0x8,
0x10,
0x20,
0x40,
0x80,
0x100,
0x200,
0x400,
0x800,
0x1000,
0x2000,
0x4000,
0x8000,
0x10000,
0x20000,
0x40000,
0x80000,
0x100000
#ifdef USE_FLYLINKDC_EXT_JSON
, 0x200000
#endif
//alex82... More arrivals
, 0x400000
, 0x800000
};
m_bMoved = false;
int iTop = 0, iTraceback = 0;
Script * cur = NULL,
* next = m_pRunningScriptS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
if(cur->m_pLua == NULL)
{
continue;
}
// if any of the scripts returns a nonzero value,
// then stop for all other scripts
if (((cur->m_ui32DataArrivals & iLuaArrivalBits[ui8Type]) == iLuaArrivalBits[ui8Type]) == true && (m_bMoved == false || cur->m_bProcessed == false))
{
cur->m_bProcessed = true;
lua_pushcfunction(cur->m_pLua, ScriptTraceback);
iTraceback = lua_gettop(cur->m_pLua);
// PPK ... table of arrivals
static const char* arrival[] = { "ChatArrival", "KeyArrival", "ValidateNickArrival", "PasswordArrival",
"VersionArrival", "GetNickListArrival", "MyINFOArrival", "GetINFOArrival", "SearchArrival",
"ToArrival", "ConnectToMeArrival", "MultiConnectToMeArrival", "RevConnectToMeArrival", "SRArrival",
"UDPSRArrival", "KickArrival", "OpForceMoveArrival", "SupportsArrival", "BotINFOArrival",
"CloseArrival", "UnknownArrival"
#ifdef USE_FLYLINKDC_EXT_JSON
, "ExtJSONArrival"
#endif
// alex82 ... More arrivals
, "BadPassArrival", "ValidateDenideArrival"
};
#ifndef _WIN32
//syslog(LOG_NOTICE, "ScriptManager::Arrival nick=%s uiType = %d", u->m_sNick, int(uiType));
#else
//printf("ScriptManager::Arrival nick=%s uiType = %d\r\n", u->m_sNick, int(uiType));
#endif
lua_getglobal(cur->m_pLua, arrival[ui8Type]);
iTop = lua_gettop(cur->m_pLua);
if (lua_isfunction(cur->m_pLua, iTop) == 0)
{
cur->m_ui32DataArrivals &= ~iLuaArrivalBits[ui8Type];
lua_settop(cur->m_pLua, 0);
continue;
}
m_pActualUser = pDcCommand->m_pUser;
lua_checkstack(cur->m_pLua, 2); // we need 2 empty slots in stack, check it to be sure
ScriptPushUser(cur->m_pLua, pDcCommand->m_pUser); // usertable
lua_pushlstring(cur->m_pLua, pDcCommand->m_sCommand, pDcCommand->m_ui32CommandLen); // sData
// two passed parameters, zero returned
if (lua_pcall(cur->m_pLua, 2, LUA_MULTRET, iTraceback) != 0)
{
ScriptError(cur);
lua_settop(cur->m_pLua, 0);
continue;
}
m_pActualUser = NULL;
// check the return value
// if no return value specified, continue
// if non-boolean value returned, continue
// if a boolean true value dwels on the stack, return it
iTop = lua_gettop(cur->m_pLua);
// no return value
if (iTop == 0)
{
continue;
}
if (lua_type(cur->m_pLua, iTop) != LUA_TBOOLEAN || lua_toboolean(cur->m_pLua, iTop) == 0)
{
lua_settop(cur->m_pLua, 0);
continue;
}
// clear the stack for sure
lua_settop(cur->m_pLua, 0);
return true; // true means DO NOT process data by the hub's core
}
}
return false;
}
//------------------------------------------------------------------------------
bool ScriptManager::UserConnected(User * pUser)
{
if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_SCRIPTING] == false)
{
return false;
}
uint8_t ui8Type = 0; // User
if (pUser->m_i32Profile != -1)
{
if (((pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
{
ui8Type = 1; // Reg
}
else
{
ui8Type = 2; // OP
}
}
m_bMoved = false;
int iTop = 0, iTraceback = 0;
Script * cur = NULL,
* next = m_pRunningScriptS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
if(cur->m_pLua == NULL)
{
continue;
}
static const uint32_t iConnectedBits[] = { Script::USERCONNECTED, Script::REGCONNECTED, Script::OPCONNECTED };
if (((cur->m_ui16Functions & iConnectedBits[ui8Type]) == iConnectedBits[ui8Type]) == true && (m_bMoved == false || cur->m_bProcessed == false))
{
cur->m_bProcessed = true;
lua_pushcfunction(cur->m_pLua, ScriptTraceback);
iTraceback = lua_gettop(cur->m_pLua);
// PPK ... table of connected functions
static const char* ConnectedFunction[] = { "UserConnected", "RegConnected", "OpConnected" };
lua_getglobal(cur->m_pLua, ConnectedFunction[ui8Type]);
iTop = lua_gettop(cur->m_pLua);
if (lua_isfunction(cur->m_pLua, iTop) == 0)
{
switch (ui8Type)
{
case 0:
cur->m_ui16Functions &= ~Script::USERCONNECTED;
break;
case 1:
cur->m_ui16Functions &= ~Script::REGCONNECTED;
break;
case 2:
cur->m_ui16Functions &= ~Script::OPCONNECTED;
break;
}
lua_settop(cur->m_pLua, 0);
continue;
}
m_pActualUser = pUser;
lua_checkstack(cur->m_pLua, 1); // we need 1 empty slots in stack, check it to be sure
ScriptPushUser(cur->m_pLua, pUser); // usertable
// 1 passed parameters, zero returned
if (lua_pcall(cur->m_pLua, 1, LUA_MULTRET, iTraceback) != 0)
{
ScriptError(cur);
lua_settop(cur->m_pLua, 0);
continue;
}
m_pActualUser = NULL;
// check the return value
// if no return value specified, continue
// if non-boolean value returned, continue
// if a boolean true value dwels on the stack, return
iTop = lua_gettop(cur->m_pLua);
// no return value
if (iTop == 0)
{
continue;
}
if (lua_type(cur->m_pLua, iTop) != LUA_TBOOLEAN || lua_toboolean(cur->m_pLua, iTop) == 0)
{
lua_settop(cur->m_pLua, 0);
continue;
}
// clear the stack for sure
lua_settop(cur->m_pLua, 0);
UserDisconnected(pUser, cur);
return true; // means DO NOT process by next scripts
}
}
return false;
}
//------------------------------------------------------------------------------
void ScriptManager::UserDisconnected(User * pUser, Script * pScript/* = NULL*/)
{
if (SettingManager::m_Ptr->m_bBools[SETBOOL_ENABLE_SCRIPTING] == false)
{
return;
}
uint8_t ui8Type = 0; // User
if (pUser->m_i32Profile != -1)
{
if (((pUser->m_ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false)
{
ui8Type = 1; // Reg
}
else
{
ui8Type = 2; // OP
}
}
m_bMoved = false;
int iTop = 0, iTraceback = 0;
Script * cur = NULL,
* next = m_pRunningScriptS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
if (cur == pScript)
{
return;
}
if(cur->m_pLua == NULL)
{
continue;
}
static const uint32_t iDisconnectedBits[] = { Script::USERDISCONNECTED, Script::REGDISCONNECTED, Script::OPDISCONNECTED };
if (((cur->m_ui16Functions & iDisconnectedBits[ui8Type]) == iDisconnectedBits[ui8Type]) == true && (m_bMoved == false || cur->m_bProcessed == false))
{
cur->m_bProcessed = true;
lua_pushcfunction(cur->m_pLua, ScriptTraceback);
iTraceback = lua_gettop(cur->m_pLua);
// PPK ... table of disconnected functions
static const char* DisconnectedFunction[] = { "UserDisconnected", "RegDisconnected", "OpDisconnected" };
lua_getglobal(cur->m_pLua, DisconnectedFunction[ui8Type]);
iTop = lua_gettop(cur->m_pLua);
if (lua_isfunction(cur->m_pLua, iTop) == 0)
{
switch (ui8Type)
{
case 0:
cur->m_ui16Functions &= ~Script::USERDISCONNECTED;
break;
case 1:
cur->m_ui16Functions &= ~Script::REGDISCONNECTED;
break;
case 2:
cur->m_ui16Functions &= ~Script::OPDISCONNECTED;
break;
}
lua_settop(cur->m_pLua, 0);
continue;
}
m_pActualUser = pUser;
lua_checkstack(cur->m_pLua, 1); // we need 1 empty slots in stack, check it to be sure
ScriptPushUser(cur->m_pLua, pUser); // usertable
// 1 passed parameters, zero returned
if (lua_pcall(cur->m_pLua, 1, 0, iTraceback) != 0)
{
ScriptError(cur);
lua_settop(cur->m_pLua, 0);
continue;
}
m_pActualUser = NULL;
// clear the stack for sure
lua_settop(cur->m_pLua, 0);
}
}
}
//------------------------------------------------------------------------------
void ScriptManager::PrepareMove(lua_State * pLua)
{
if (m_bMoved == true)
{
return;
}
bool bBefore = true;
m_bMoved = true;
Script * cur = NULL,
* next = m_pRunningScriptS;
while (next != NULL)
{
cur = next;
next = cur->m_pNext;
if (bBefore == true)
{
cur->m_bProcessed = true;
}
else
{
cur->m_bProcessed = false;
}
if (cur->m_pLua == pLua)
{
bBefore = false;
}
}
}
//------------------------------------------------------------------------------
↑ V1042 This file is marked with copyleft license, which requires you to open the derived source code.