From 310a2c101b32a5e71a616027b6a1b788a341bc02 Mon Sep 17 00:00:00 2001 From: manuel Date: Tue, 5 Mar 2013 17:39:48 +0100 Subject: initial GPLv2 release --- tsquerythread.cpp | 1105 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1105 insertions(+) create mode 100644 tsquerythread.cpp (limited to 'tsquerythread.cpp') diff --git a/tsquerythread.cpp b/tsquerythread.cpp new file mode 100644 index 0000000..94a1fef --- /dev/null +++ b/tsquerythread.cpp @@ -0,0 +1,1105 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Manuel Mausz (manuel@mausz.at) + * Christian Raschko (c.raschko@netcore.at) + */ + +// Header +#include "tsquerythread.h" +#include "wxbufferex.h" +#include "base64.h" + +//Libraries +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +IMPLEMENT_CLASS(TSQueryThread, wxObject) + +//------------------------------------------------------------------------------ +static bool strToChannelId(wxString &str, wxUint32 *pid, + bool pid_allowed = true) +{ + unsigned long l; + if (!str.ToULong(&l)) + return false; + if (l == ULONG_MAX) + l = TS_NO_PARENT; + if (l > TS_NO_PARENT || (!pid_allowed && l == TS_NO_PARENT)) + return false; + *pid = wxUint32(l); + return true; +} + +static bool strToNum(wxString &str, wxUint32 *val) +{ + unsigned long l; + if (!str.ToULong(&l)) + return false; + if (l > TS_NUM_MAX) + return false; + *val = wxUint32(l); + return true; +} + +//------------------------------------------------------------------------------ +// thread execution starts here +wxThread::ExitCode TSQueryThread::Entry() +{ + wxLogMessage(_T("TSQuery: thread started.")); + + // init libxml2 library + wxXml2::Init(); + + //check for bind + if(m_ServerAddress.Length() < 7 || m_ServerAddress == _T("0.0.0.0")) + m_ServerAddr.AnyAddress(); + else + m_ServerAddr.Hostname(m_ServerAddress); + + m_ServerAddr.Service(m_Port); + m_pSocket = new wxSocketServer(m_ServerAddr, wxSOCKET_REUSEADDR); + + //Check socket + if(!m_pSocket->Ok()) + { + if(m_pSocket->LastError() == wxSOCKET_INVPORT) + SetLastError(_T("Socket port in use")); + else + SetLastError(_T("Socket error")); + m_pSocket->Destroy(); + m_pSocket = NULL; + return wxThread::ExitCode(EXIT_FAILURE); + } + + while(1) + { + if (!Accept()) + wxLogError(_T("TSQuery: %s"), m_LastError.c_str()); + if (m_pSocket == NULL) + break; + } + + return wxThread::ExitCode(EXIT_SUCCESS); +} + +//------------------------------------------------------------------------------ +// and stops here +void TSQueryThread::OnExit() +{ + wxLogDebug(_T("TSQuery: thread terminated.")); + + // cleanup libxml2 statics + wxXml2::Cleanup(); + + if(m_pSocket != NULL) + { + m_pSocket->Destroy(); + m_pSocket = NULL; + } +} + +//------------------------------------------------------------------------------ +// Default CTor, Initializes the object. +TSQueryThread::TSQueryThread(TSClient *client) : wxThread(wxTHREAD_JOINABLE) +{ + Create(); + //create all objects + //m_pSocket = new wxSocketServer(m_ServerAddr, wxSOCKET_REUSEADDR); + m_pClient = client; + m_Password = _T(""); +} + +//------------------------------------------------------------------------------ +// Default DTor. +TSQueryThread::~TSQueryThread() +{ + //use OnExit() +} + +//------------------------------------------------------------------------------ +// Listen +bool TSQueryThread::Accept() +{ + //Wait until someone connect (NOTE: wxWidgets has an internal select timeout (~10 mins)) + wxSocketBase *sock = m_pSocket->Accept(); + + // wxSocketBase doesn't set Error() to true after socket timeout, so we check against null + if(m_pSocket->LastError() == wxSOCKET_TIMEDOUT && sock == NULL) + return true; + + // real check against null + if(sock == NULL) + { + SetLastError(_T("Socket, something really bad happend")); + m_pSocket->Destroy(); + m_pSocket = NULL; + return false; + } + + //Check if IP is allowed + wxIPV4address peeraddr; + sock->GetPeer(peeraddr); + + wxLogMessage(_T("TSQuery: incoming request from %s"), peeraddr.IPAddress().c_str()); + + if(!IsIPAllowed(peeraddr.IPAddress())) + { + wxLogError(_T("TSQuery: %s"),GetLastError().c_str()); + sock->Destroy(); + return false; + } + + //now receive + wxMemoryBufferEx buf(1024); + sock->Read(buf.GetData(), 1024); + buf.SetDataLen(sock->LastCount()); + wxMemoryInputStream in(buf.GetData(), buf.GetDataLen()); + + wxStringOutputStream strm; + buf.HexDump(strm); + wxLogDebug(_T("TSQuery: command received:\n%s"), strm.GetString().c_str()); + + //Check socket + if(sock->LastCount() == 0) + { + SetLastError(_T("Socket, no data available")); + sock->Destroy(); + return false; + } + + //Check XML format + wxString err; + if (!m_pXml.Load(in, &err)) + { + wxLogError(_T("XML format error: %s"), err.c_str()); + return false; + } + + //check node format + if(!IsValidFormat()) + { + SendError(_T("General"), GetLastError(), sock); + sock->Destroy(); + return false; + } + + //check password + wxXml2Node pNode = m_pXml.GetRoot().Get(_T("Password")).GetFirstChild(); + if(pNode.GetContent() != m_Password) + { + pNode = m_pXml.GetRoot().Get(_T("Command")).GetFirstChild(); + SetLastError(_T("Invalid password")); + SendError(pNode.GetContent(), GetLastError(), sock); + sock->Destroy(); + return false; + } + + //check if TSClient is connected + if(!m_pClient->IsConnected()) + { + pNode = m_pXml.GetRoot().Get(_T("Command")).GetFirstChild(); + SetLastError(_T("No connection to TSServer")); + SendError(pNode.GetContent(), GetLastError(), sock); + sock->Destroy(); + return false; + } + + //ok now process the command + if(!ProcessCommand(sock)) + { + sock->Destroy(); + return false; + } + + sock->Destroy(); + wxLogMessage(_T("TSQuery: request successfully processed.")); + return true; +} + +//------------------------------------------------------------------------------ +// IsIPAllowed +bool TSQueryThread::IsIPAllowed(wxString const &str) +{ + wxStringTokenizer tkz(m_AllowedAddresses, _T(",")); + bool found = false; + while(tkz.HasMoreTokens()) + { + wxString token = tkz.GetNextToken(); + wxIPV4address tmpaddr; + if(!tmpaddr.Hostname(token)) + { + SetLastError(wxString::Format(_T("'%s' this is no valid IP"),token.c_str())); + return false; + } + unsigned ip1[4], ip2[4]; + if(tmpaddr.IPAddress() == str) + { + found = true; + break; + } + //dirty C + else if(wxSscanf(tmpaddr.IPAddress().c_str(), _T("%u.%u.%u.%u"), &ip1[0], &ip1[1], &ip1[2], &ip1[3]) == 4 && + wxSscanf(str.c_str(), _T("%u.%u.%u.%u"), &ip2[0], &ip2[1], &ip2[2], &ip2[3]) == 4) + { + if((ip1[0] == 0 && ip1[1] == 0 && ip1[2] == 0 && ip1[3] == 0) || //0.0.0.0 + (ip1[0] == ip2[0] && ip1[1] == 0 && ip1[2] == 0 && ip1[3] == 0) || //x.0.0.0 + (ip1[0] == ip2[0] && ip1[1] == ip2[1] && ip1[2] == 0 && ip1[3] == 0) || //x.x.0.0 + (ip1[0] == ip2[0] && ip1[1] == ip2[1] && ip1[2] == ip2[2] && ip1[3] == 0)) //x.x.x.0 + { + found = true; + break; + } + } + } + if (!found) + { + SetLastError(_T("IP is not allowed")); + return false; + } + return true; +} + +//------------------------------------------------------------------------------ +// IsValidFormat +bool TSQueryThread::IsValidFormat() +{ + //check node + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + if(pNodeRoot.GetName() != _T("TSClient")) + { + SetLastError(_T("No 'TSClient' node found")); + return false; + } + + //check node + wxXml2Node pNode = pNodeRoot.Get(_T("Password")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No 'Password' node found")); + return false; + } + + pNode = pNodeRoot.Get(_T("Command")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No 'Command' node found")); + return false; + } + + return true; +} + + +//------------------------------------------------------------------------------ +// ProcessCommand. +bool TSQueryThread::ProcessCommand(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + //check node + wxXml2Node pNode = pNodeRoot.Get(_T("Command")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No 'Command' node found")); + SendError(_T("General"), GetLastError(), sock); + return false; + } + + wxString cmd = pNode.GetFirstChild().GetContent(); + wxLogMessage(_T("TSQuery: command '%s' received"), cmd.c_str()); + + pNode = pNodeRoot.Get(_T("Text")); + if(pNode != wxXml2EmptyNode) + wxLogMessage(_T("TSQuery: Text: '%s'"), pNode.GetFirstChild().GetContent().c_str()); + + if(cmd == _T("GetStatus")) + return CmdGetStatus(sock); + else if(cmd == _T("GetChannels")) + return CmdGetChannels(sock); + else if(cmd == _T("GetUsers")) + return CmdGetUsers(sock); + else if(cmd == _T("CreateChannel")) + return CmdCreateChannel(sock); + else if(cmd == _T("DeleteChannel")) + return CmdDeleteChannel(sock); + else if(cmd == _T("ModifyChannel")) + return CmdModifyChannel(sock); + else if(cmd == _T("MoveUser")) + return CmdMoveUser(sock); + else if(cmd == _T("KickUser")) + return CmdKickUser(sock); + else if(cmd == _T("Kill")) + return CmdKill(sock); + + SetLastError(_T("Unknown command")); + SendError(cmd, GetLastError(), sock); + return false; +} + +//------------------------------------------------------------------------------ +// SendError. +bool TSQueryThread::SendError(wxString const &cmd, wxString const &str, wxSocketBase *sock) +{ + wxSocketOutputStream so(*sock); + wxBufferedOutputStream out(so); + + m_pXml.Create(_T("1.0")); + wxXml2Node pNodeRoot; + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + + wxXml2Node pNode; + pNode = pNodeRoot.AddTextChild(_T("Command"), cmd); + pNode.AddProperty(_T("State"), _T("Error")); + + pNode = pNodeRoot.AddTextChild(_T("ErrorText"), str); + + if(!SendDOM(sock)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +// Dumps object. +void TSQueryThread::Dump(wxOutputStream &ostrm) const +{ + wxTextOutputStream out(ostrm); + out << wxString(_T("-"), 60) << endl; + out << _T("Object: TSQueryThread (") << wxString::Format(_T("0x%X"), this) << _T(")") << endl; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::SendDOM(wxSocketBase *sock) +{ + wxSocketOutputStream so(*sock); + wxBufferedOutputStream out(so); + if(!m_pXml.Save(out, _T("utf-8"), wxXML2DOC_USE_NATIVE_NEWLINES | wxXML2DOC_USE_INDENTATION, 2)) + { + SetLastError(_T("DOM serialization")); + return false; + } + out.Sync(); + return true; +} + +//------------------------------------------------------------------------------ +wxString TSQueryThread::GetNodeValue(wxXml2Node &pElemRoot, wxString const &str) +{ + wxXml2Node pElem = pElemRoot.Get(str); + if(pElem == wxXml2EmptyNode) + return _T(""); + else + return pElem.GetFirstChild().GetContent(); +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdGetStatus(wxSocketBase *sock) +{ + wxString str; + str = wxString::Format(_T("%s:%d"), m_pClient->GetServer()->GetServerAddress().c_str(), + m_pClient->GetServer()->GetPort()); + + if(!m_pClient->IsConnected()) + { + wxLogMessage(_T("TSQuery: TSServer %s is not connected"), str.c_str()); + SetLastError(_T("No connection to TSServer")); + SendError(_T("GetStatus"), GetLastError(), sock); + return false; + } + + m_pXml.Create(_T("1.0")); + wxXml2Node pNodeRoot; + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + + wxXml2Node pNode; + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("GetStatus")); + pNode.AddProperty(_T("State"), _T("Ok")); + + pNode = pNodeRoot.AddTextChild(_T("TSServer"), str); + + if(!SendDOM(sock)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdGetChannels(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSpChannelArray chs; + + wxXml2Node pNode = pNodeRoot.Get(_T("ChannelName")); + if(pNode != wxXml2EmptyNode) + { + wxString str = pNode.GetFirstChild().GetContent(); + m_pClient->FindChannelsByName(str, &chs); + + /* remove channels not matching ParentId */ + str = pNode.GetPropVal(_T("ParentId"), wxEmptyString); + wxUint32 pid; + if (!str.empty() && strToChannelId(str, &pid)) + { + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetParent() != pid) + chs.RemoveAt(i); + } + } + + /* add subchannels */ + if(pNode.GetPropVal(_T("Subchannels"), _T("No")) == _T("Yes")) + { + for(size_t i = 0; i < chs.Count(); i++) + m_pClient->FindChannelsByParent(chs[i]->GetId(), &chs); + } + } + + pNode = pNodeRoot.Get(_T("ChannelId")); + if(pNode != wxXml2EmptyNode) + { + wxString str = pNode.GetFirstChild().GetContent(); + wxUint32 chlid; + if (strToChannelId(str, &chlid, false)) + { + TSChannel *c = m_pClient->FindChannel(chlid); + if(c != NULL) + chs.Add(c); + + /* remove channels not matching ParentId */ + wxUint32 pid; + str = pNode.GetPropVal(_T("ParentId"), wxEmptyString); + if (!str.empty() && strToChannelId(str, &pid)) + { + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetParent() != pid) + chs.RemoveAt(i); + } + } + + /* add subchannels */ + if(pNode.GetPropVal(_T("Subchannels"), _T("No")) == _T("Yes")) + { + for(size_t i = 0; i < chs.Count(); i++) + m_pClient->FindChannelsByParent(chs[i]->GetId(), &chs); + } + } + } + + pNode = pNode.Get(_T("ChannelParentId")); + if(pNode != wxXml2EmptyNode) + { + wxString str = pNode.GetFirstChild().GetContent(); + wxUint32 pid; + if (strToChannelId(str, &pid)) + m_pClient->FindChannelsByParent(pid, &chs); + } + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("GetChannels")); + pNode.AddProperty(_T("State"), _T("Ok")); + + wxLogMessage(_T("TSQuery: sending requested channels.")); + + for(size_t i = 0; i < chs.Count(); i++) + { + wxXml2Node pChannelNode; + pChannelNode = pNodeRoot.AddContainerChild(_T("Channel")); + pChannelNode.AddProperty(_T("Id"), wxString::Format(_T("%d"), chs[i]->GetId())); + pChannelNode.AddProperty(_T("ParentId"), wxString::Format(_T("%d"), chs[i]->GetParent())); + + pChannelNode.AddTextChild(_T("ChannelName"), chs[i]->GetName()); + pChannelNode.AddTextChild(_T("ChannelTopic"), chs[i]->GetTopic()); + pChannelNode.AddTextChild(_T("ChannelSlots"), wxString::Format(_T("%d"), chs[i]->GetMaxUsers())); + pChannelNode.AddTextChild(_T("ChannelPassword"), chs[i]->GetPassword()); + pChannelNode.AddTextChild(_T("ChannelCodec"), wxString::Format(_T("%d"), chs[i]->GetCodec())); + const wxCharBuffer buf = chs[i]->GetDescription().mb_str(wxConvUTF8); + pChannelNode.AddTextChild(_T("ChannelDescription"), Base64Encode(buf, strlen(buf))); + pChannelNode.AddTextChild(_T("ChannelFlags"), chs[i]->GetFlagsString()); + + wxLogVerbose(_T("TSQuery: Channel '%s' transmitted."), chs[i]->GetName().c_str()); + } + + if(!SendDOM(sock)) + return false; + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdGetUsers(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSpPlayerArray pls; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("UserName")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + m_pClient->FindPlayersByName(str, &pls); + } + + pNode = pNodeRoot.Get(_T("UserId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 plyid; + if (strToNum(str, &plyid)) + pls.Add(m_pClient->FindPlayer(plyid)); + } + + pNode = pNodeRoot.Get(_T("ChannelName")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + TSpChannelArray chs; + m_pClient->FindChannelsByName(str, &chs); + + /* remove channels not matching ParentId */ + wxUint32 pid; + str = pNode.GetPropVal(_T("ParentId"), wxEmptyString); + if (!str.empty() && strToChannelId(str, &pid)) + { + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetParent() != pid) + chs.RemoveAt(i); + } + } + + /* find users */ + for(size_t i = 0; i < chs.Count(); i++) + { + m_pClient->FindPlayersByChannel(chs[i], &pls); + + /* add subchannels and their users */ + if (pNode.GetPropVal(_T("Subchannels"), _T("No")) == _T("Yes")) + { + TSpChannelArray chs2; + m_pClient->FindChannelsByParent(chs[i]->GetId(), &chs2); + for(size_t j = 0; j < chs2.Count(); j++) + m_pClient->FindPlayersByChannel(chs2[j], &pls); + } + } + } + + pNode = pNodeRoot.Get(_T("ChannelId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + TSChannel *cl = NULL; + wxUint32 chlid; + if (strToChannelId(str, &chlid, false)) + cl = m_pClient->FindChannel(chlid); + if (cl == NULL) + { + SetLastError(_T("Error while searching for channel.")); + SendError(_T("GetUsers"), GetLastError(), sock); + return false; + } + + m_pClient->FindPlayersByChannel(cl, &pls); + + if (pNode.GetPropVal(_T("Subchannels"), _T("No")) == _T("Yes")) + { + TSpChannelArray chs; + m_pClient->FindChannelsByParent(cl->GetId(), &chs); + for(size_t i = 0; i < chs.Count(); i++) + m_pClient->FindPlayersByChannel(chs[i], &pls); + } + } + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("GetUsers")); + pNode.AddProperty(_T("State"), _T("Ok")); + + wxLogMessage(_T("TSQuery: sending requested users.")); + + for(size_t i = 0; i < pls.Count(); i++) + { + wxXml2Node pUserNode; + pUserNode = pNodeRoot.AddContainerChild(_T("User")); + pUserNode.AddProperty(_T("Id"), wxString::Format(_T("%d"), pls[i]->GetId())); + + pUserNode.AddTextChild(_T("UserName"), pls[i]->GetNickname().c_str()); + pUserNode.AddTextChild(_T("UserChannelId"), wxString::Format(_T("%d"), pls[i]->GetChannelId()).c_str()); + pUserNode.AddTextChild(_T("UserFlags"), wxString::Format(_T("%d"), pls[i]->GetFlags()).c_str()); + pUserNode.AddTextChild(_T("UserPrivileges"), wxString::Format(_T("%d"), pls[i]->GetPrivileges()).c_str()); + pUserNode.AddTextChild(_T("UserChannelPrivileges"), wxString::Format(_T("%d"), pls[i]->GetChannelPrivileges()).c_str()); + + wxLogVerbose(_T("TSQuery: User '%s' transmitted."), pls[i]->GetNickname().c_str()); + } + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdCreateChannel(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSChannel cl; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("Channel")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No channel node")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + wxUint32 chlid; + str = pNode.GetPropVal(_T("ParentId"), _T("-1")); + if (!strToChannelId(str, &chlid)) + { + SetLastError(_T("Invalid parent id")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + cl.SetParent(chlid); + cl.SetName(GetNodeValue(pNode, _T("ChannelName"))); + cl.SetTopic(GetNodeValue(pNode, _T("ChannelTopic"))); + cl.SetPassword(GetNodeValue(pNode, _T("ChannelPassword"))); + + wxUint32 num; + str = GetNodeValue(pNode, _T("ChannelSlots")); + if (!strToNum(str, &num)) + { + SetLastError(_T("Invalid channel slots value")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + cl.SetMaxUsers(num); + + str = GetNodeValue(pNode, _T("ChannelCodec")); + if (!strToNum(str, &num)) + { + SetLastError(_T("Invalid channel codec value")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + cl.SetCodec(num); + + wxCSConv conv_iso(_T("iso-8859-1")); + wxString base64_encoded = GetNodeValue(pNode, _T("ChannelDescription")); + cl.SetDescription(wxString(Base64Decode(base64_encoded).mb_str(conv_iso), wxConvUTF8)); + cl.SetFlags(GetNodeValue(pNode, _T("ChannelFlags"))); + + m_pClient->CreateChannel(&cl); + + // dirty wait for channel id + wxUint32 channelid = 0; + for (wxUint32 i = 0; i <= 2; i++) + { + TSpChannelArray chs; + if (cl.GetParent() == TS_NO_PARENT) + { + // we wait for a main channel + m_pClient->FindChannelsByName(_T("^") + cl.GetName() + _T("$"), &chs); + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetParent() == TS_NO_PARENT) + { + channelid = chs[i]->GetId(); + break; + } + } + } + else + { + // we wait for a subchannel + m_pClient->FindChannelsByParent(cl.GetParent(), &chs); + for(size_t i = 0; i < chs.Count(); i++) + { + if (chs[i]->GetName() == cl.GetName()) + { + channelid = chs[i]->GetId(); + break; + } + } + } + + if (channelid > 0) + break; + Sleep(500); + } + + if (channelid <= 0) + { + SetLastError(_T("Error while creating channel.")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("CreateChannel")); + pNode.AddProperty(_T("State"), _T("Ok")); + + pNodeRoot.AddTextChild(_T("ChannelId"), wxString::Format(_T("%d"), channelid)); + + wxLogMessage(_T("TSQuery: Channel '%s' created."), cl.GetName().c_str()); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdDeleteChannel(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSChannel *cl = NULL; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("ChannelId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 chlid; + if (strToChannelId(str, &chlid, false)) + cl = m_pClient->FindChannel(chlid); + } + + if(cl == NULL) + { + SetLastError(_T("Channel not found.")); + SendError(_T("DeleteChannel"), GetLastError(), sock); + return false; + } + + TSChannel *defchl = m_pClient->FindDefaultChannel(); + + // process subchannels + TSpChannelArray chs; + m_pClient->FindChannelsByParent(cl->GetId(), &chs); + for(size_t i = 0; i < chs.Count(); i++) + { + TSpPlayerArray ply; + m_pClient->FindPlayersByChannel(chs[i], &ply); + + for(size_t i=0;iGetId()); + pl.SetChannelId(defchl->GetId()); + m_pClient->MovePlayer(&pl); + } + } + + // process main channel + TSpPlayerArray ply; + m_pClient->FindPlayersByChannel(cl,&ply); + + for(size_t i=0;iGetId()); + pl.SetChannelId(defchl->GetId()); + m_pClient->MovePlayer(&pl); + } + + wxLogMessage(_T("TSQuery: Channel '%s' deleted."),cl->GetName().c_str()); + + m_pClient->DeleteChannel(cl); + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("DeleteChannel")); + pNode.AddProperty(_T("State"), _T("Ok")); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdModifyChannel(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSChannel cl; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("Channel")); + if(pNode == wxXml2EmptyNode) + { + SetLastError(_T("No channel node")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + wxUint32 chlid; + str = pNode.GetPropVal(_T("Id"), _T("")); + if (!strToChannelId(str, &chlid, false)) + { + SetLastError(_T("No id attribute found")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + + cl.SetId(chlid); + cl.SetName(GetNodeValue(pNode, _T("ChannelName"))); + cl.SetTopic(GetNodeValue(pNode, _T("ChannelTopic"))); + cl.SetPassword(GetNodeValue(pNode, _T("ChannelPassword"))); + + wxUint32 num; + str = GetNodeValue(pNode, _T("ChannelSlots")); + if (!strToNum(str, &num)) + { + SetLastError(_T("Invalid channel slots value")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + cl.SetMaxUsers(num); + + str = GetNodeValue(pNode, _T("ChannelCodec")); + if (!strToNum(str, &num)) + { + SetLastError(_T("Invalid channel codec value")); + SendError(_T("CreateChannel"), GetLastError(), sock); + return false; + } + cl.SetCodec(num); + + wxCSConv conv_iso(_T("iso-8859-1")); + wxString base64_encoded = GetNodeValue(pNode, _T("ChannelDescription")); + cl.SetDescription(wxString(Base64Decode(base64_encoded).mb_str(conv_iso), wxConvUTF8)); + cl.SetFlags(GetNodeValue(pNode, _T("ChannelFlags"))); + + m_pClient->ModifyChannel(&cl); + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("ModifyChannel")); + pNode.AddProperty(_T("State"), _T("Ok")); + + wxLogMessage(_T("TSQuery: Channel '%s' modified."), cl.GetName().c_str()); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdMoveUser(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSPlayer *pl = NULL; + TSChannel *cl = NULL; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("UserId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 plyid; + if (strToNum(str, &plyid)) + pl = m_pClient->FindPlayer(plyid); + } + + if(pl == NULL) + { + SetLastError(_T("User not found.")); + SendError(_T("MoveUser"), GetLastError(), sock); + return false; + } + + pNode = pNodeRoot.Get(_T("ChannelId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 chlid; + if (strToChannelId(str, &chlid, false)) + cl = m_pClient->FindChannel(chlid); + } + + if(cl == NULL) + { + SetLastError(_T("Channel not found.")); + SendError(_T("MoveUser"), GetLastError(), sock); + return false; + } + + pl->SetChannelId(cl->GetId()); + m_pClient->MovePlayer(pl); + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("MoveUser")); + pNode.AddProperty(_T("State"), _T("Ok")); + + wxLogMessage(_T("TSQuery: User '%s' moved to '%s'."), pl->GetNickname().c_str(), + m_pClient->FindChannel(pl->GetChannelId())->GetName().c_str()); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdKickUser(wxSocketBase *sock) +{ + wxXml2Node pNodeRoot = m_pXml.GetRoot(); + TSPlayer *pl = NULL; + wxString str; + + wxXml2Node pNode; + pNode = pNodeRoot.Get(_T("UserId")); + if(pNode != wxXml2EmptyNode) + { + str = pNode.GetFirstChild().GetContent(); + wxUint32 plyid; + if (strToNum(str, &plyid)) + pl = m_pClient->FindPlayer(plyid); + } + + if(pl == NULL) + { + SetLastError(_T("User not found.")); + SendError(_T("KickUser"), GetLastError(), sock); + return false; + } + + str = _T(""); + pNode = pNodeRoot.Get(_T("Reason")); + if(pNode != wxXml2EmptyNode) + str = pNode.GetFirstChild().GetContent(); + + wxLogMessage(_T("TSQuery: User '%s' kicked."), pl->GetNickname().c_str()); + + m_pClient->KickPlayer(pl, str); + + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + pNode = pNodeRoot.AddTextChild(_T("Command"), _T("KickUser")); + pNode.AddProperty(_T("State"), _T("Ok")); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +bool TSQueryThread::CmdKill(wxSocketBase *sock) +{ + if(m_pClient->IsConnected()) + m_pClient->Disconnect(false); + + wxXml2Node pNodeRoot; + m_pXml.Create(_T("1.0")); + pNodeRoot.CreateRoot(m_pXml, _T("TSClient")); + wxXml2Node pNode = pNodeRoot.AddTextChild(_T("Command"), _T("Kill")); + pNode.AddProperty(_T("State"), _T("Ok")); + + if(!SendDOM(sock)) + return false; + + return true; +} + +//------------------------------------------------------------------------------ +// Sets the password for incomming connections. + +bool TSQueryThread::SetPassword(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("Empty string")); + return false; + } + m_Password = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the server address. +bool TSQueryThread::SetServerAddress(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("Empty string")); + return false; + } + m_ServerAddress = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the allowed address. +bool TSQueryThread::SetAllowedAddresses(wxString const &str) +{ + if(str.Length() == 0) + { + SetLastError(_T("Empty string")); + return false; + } + m_AllowedAddresses = str; + return true; +} + +//------------------------------------------------------------------------------ +// Sets the connection port. +bool TSQueryThread::SetPort(wxUint16 const &port) +{ + if(port == 0) + { + SetLastError(_T("Empty port")); + return false; + } + m_Port = port; + return true; +} + +//------------------------------------------------------------------------------ +// Start thread. +bool TSQueryThread::Start() +{ + Run(); + return true; +} + +//------------------------------------------------------------------------------ +// Stop thread. +bool TSQueryThread::Stop() +{ + Kill(); + return true; +} -- cgit v1.2.3