diff --git a/deps/fmt b/deps/fmt index 0d5ef5c2..d5893c9a 160000 --- a/deps/fmt +++ b/deps/fmt @@ -1 +1 @@ -Subproject commit 0d5ef5c2a66026409b0cfbafa1d2f46cdc5aa4d0 +Subproject commit d5893c9a133382e1862c929c1d50ccaef2a6d2fc diff --git a/deps/mongoose b/deps/mongoose index 68dd8d27..b987df19 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit 68dd8d277d7b5bb26daf04f08bef3030ad2d7725 +Subproject commit b987df197436b8581a7a5a9e00c1d341f81fdb30 diff --git a/deps/protobuf b/deps/protobuf index 042993b3..2ba058c6 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 042993b3dd8c52f979870c91ea7fcbcf0dcf94a0 +Subproject commit 2ba058c66c10781d57a332987be23e3fed0f9e1c diff --git a/src/Components/Modules/AntiCheat.cpp b/src/Components/Modules/AntiCheat.cpp index 3c824204..33b9f10b 100644 --- a/src/Components/Modules/AntiCheat.cpp +++ b/src/Components/Modules/AntiCheat.cpp @@ -101,9 +101,9 @@ namespace Components static uint8_t loadLibAStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xBE }; // LoadLibraryA static uint8_t loadLibWStr[] = { 0xB3, 0x90, 0x9E, 0x9B, 0xB3, 0x96, 0x9D, 0x8D, 0x9E, 0x8D, 0x86, 0xA8 }; // LoadLibraryW - HMODULE kernel32 = GetModuleHandleA(Utils::String::XORString(std::string(reinterpret_cast(kernel32Str), sizeof kernel32Str), -1).data()); - FARPROC loadLibA = GetProcAddress(kernel32, Utils::String::XORString(std::string(reinterpret_cast(loadLibAStr), sizeof loadLibAStr), -1).data()); - FARPROC loadLibW = GetProcAddress(kernel32, Utils::String::XORString(std::string(reinterpret_cast(loadLibWStr), sizeof loadLibWStr), -1).data()); + HMODULE kernel32 = GetModuleHandleA(Utils::String::XOR(std::string(reinterpret_cast(kernel32Str), sizeof kernel32Str), -1).data()); + FARPROC loadLibA = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast(loadLibAStr), sizeof loadLibAStr), -1).data()); + FARPROC loadLibW = GetProcAddress(kernel32, Utils::String::XOR(std::string(reinterpret_cast(loadLibWStr), sizeof loadLibWStr), -1).data()); AntiCheat::LoadLibHook[0].Initialize(loadLibA, loadLibStub, HOOK_JUMP); AntiCheat::LoadLibHook[1].Initialize(loadLibW, loadLibStub, HOOK_JUMP); diff --git a/src/Components/Modules/Auth.cpp b/src/Components/Modules/Auth.cpp index b1b7421c..23579bc2 100644 --- a/src/Components/Modules/Auth.cpp +++ b/src/Components/Modules/Auth.cpp @@ -145,7 +145,7 @@ namespace Components void Auth::StoreKey() { - if (!Dedicated::IsDedicated() && !ZoneBuilder::IsEnabled()) + if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled()) { Proto::Auth::Certificate cert; cert.set_token(Auth::GuidToken.ToString()); @@ -158,7 +158,7 @@ namespace Components void Auth::LoadKey(bool force) { - if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) return; + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return; if (!force && Auth::GuidKey.IsValid()) return; Proto::Auth::Certificate cert; @@ -292,7 +292,7 @@ namespace Components Auth::LoadKey(true); // Only clients receive the auth request - if (!Dedicated::IsDedicated()) + if (!Dedicated::IsEnabled()) { Network::Handle("xuidAuthReq", [] (Network::Address address, std::string data) { diff --git a/src/Components/Modules/Command.cpp b/src/Components/Modules/Command.cpp index 4e0130f9..4ab0c01d 100644 --- a/src/Components/Modules/Command.cpp +++ b/src/Components/Modules/Command.cpp @@ -34,7 +34,7 @@ namespace Components void Command::Add(const char* name, Command::Callback* callback) { - std::string command = Utils::String::StrToLower(name); + std::string command = Utils::String::ToLower(name); if (Command::FunctionMap.find(command) == Command::FunctionMap.end()) { @@ -46,7 +46,7 @@ namespace Components void Command::AddSV(const char* name, Command::Callback* callback) { - std::string command = Utils::String::StrToLower(name); + std::string command = Utils::String::ToLower(name); if (Command::FunctionMapSV.find(command) == Command::FunctionMapSV.end()) { @@ -98,7 +98,7 @@ namespace Components { Command::Params params(false, *Game::cmd_id); - std::string command = Utils::String::StrToLower(params[0]); + std::string command = Utils::String::ToLower(params[0]); if (Command::FunctionMap.find(command) != Command::FunctionMap.end()) { @@ -110,7 +110,7 @@ namespace Components { Command::Params params(true, *Game::cmd_id_sv); - std::string command = Utils::String::StrToLower(params[0]); + std::string command = Utils::String::ToLower(params[0]); if (Command::FunctionMapSV.find(command) != Command::FunctionMapSV.end()) { diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 9981b0df..24a0c701 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -523,7 +523,7 @@ namespace Components Console::LastRefresh = Game::Sys_Milliseconds(); }); } - else if (Dedicated::IsDedicated()/* || ZoneBuilder::IsEnabled()*/) + else if (Dedicated::IsEnabled()/* || ZoneBuilder::IsEnabled()*/) { Utils::Hook::Nop(0x60BB58, 11); diff --git a/src/Components/Modules/Dedicated.cpp b/src/Components/Modules/Dedicated.cpp index 246bcaca..d57d86c9 100644 --- a/src/Components/Modules/Dedicated.cpp +++ b/src/Components/Modules/Dedicated.cpp @@ -7,7 +7,7 @@ namespace Components bool Dedicated::SendChat; - bool Dedicated::IsDedicated() + bool Dedicated::IsEnabled() { return Flags::HasFlag("dedicated"); } @@ -118,7 +118,7 @@ namespace Components void Dedicated::MapRotate() { - if (!Dedicated::IsDedicated() && Dvar::Var("sv_dontrotate").Get()) + if (!Dedicated::IsEnabled() && Dvar::Var("sv_dontrotate").Get()) { Dvar::Var("sv_dontrotate").SetRaw(0); return; @@ -226,7 +226,7 @@ namespace Components Utils::Hook::Set(0x4152E8, Dedicated::MapRotate); Dvar::Register("sv_dontrotate", false, Game::dvar_flag::DVAR_FLAG_CHEAT, ""); - if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) // Run zonebuilder as dedi :P + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) // Run zonebuilder as dedi :P { Dvar::Register("sv_lanOnly", false, Game::dvar_flag::DVAR_FLAG_NONE, "Don't act as node"); diff --git a/src/Components/Modules/Dedicated.hpp b/src/Components/Modules/Dedicated.hpp index 80b08b88..392924a6 100644 --- a/src/Components/Modules/Dedicated.hpp +++ b/src/Components/Modules/Dedicated.hpp @@ -1,37 +1,37 @@ -namespace Components -{ - class Dedicated : public Component - { - public: - typedef void(Callback)(); - - Dedicated(); - ~Dedicated(); - const char* GetName() { return "Dedicated"; }; - - static bool IsDedicated(); - - static void Heartbeat(); - - static void OnFrame(Callback* callback); - static void Once(Callback* callback); - - private: - static wink::signal> FrameSignal; - static wink::signal> FrameOnceSignal; - - static bool SendChat; - - static void MapRotate(); - static void FrameStub(); - static void InitDedicatedServer(); - - static void PostInitialization(); - static void PostInitializationStub(); - - static const char* EvaluateSay(char* text); - - static void PreSayStub(); - static void PostSayStub(); - }; -} +namespace Components +{ + class Dedicated : public Component + { + public: + typedef void(Callback)(); + + Dedicated(); + ~Dedicated(); + const char* GetName() { return "Dedicated"; }; + + static bool IsEnabled(); + + static void Heartbeat(); + + static void OnFrame(Callback* callback); + static void Once(Callback* callback); + + private: + static wink::signal> FrameSignal; + static wink::signal> FrameOnceSignal; + + static bool SendChat; + + static void MapRotate(); + static void FrameStub(); + static void InitDedicatedServer(); + + static void PostInitialization(); + static void PostInitializationStub(); + + static const char* EvaluateSay(char* text); + + static void PreSayStub(); + static void PostSayStub(); + }; +} diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index de125036..8803a060 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -285,7 +285,7 @@ namespace Components Download::Download() { - if (Dedicated::IsDedicated()) + if (Dedicated::IsEnabled()) { mg_mgr_init(&Download::Mgr, NULL); @@ -319,7 +319,7 @@ namespace Components Download::~Download() { - if (Dedicated::IsDedicated()) + if (Dedicated::IsEnabled()) { mg_mgr_free(&Download::Mgr); } diff --git a/src/Components/Modules/Flags.cpp b/src/Components/Modules/Flags.cpp index f598053c..535b9471 100644 --- a/src/Components/Modules/Flags.cpp +++ b/src/Components/Modules/Flags.cpp @@ -8,7 +8,7 @@ namespace Components { for (auto entry : Flags::EnabledFlags) { - if (Utils::String::StrToLower(entry) == Utils::String::StrToLower(flag)) + if (Utils::String::ToLower(entry) == Utils::String::ToLower(flag)) { return true; } diff --git a/src/Components/Modules/IPCPipe.cpp b/src/Components/Modules/IPCPipe.cpp index fea00597..38999f43 100644 --- a/src/Components/Modules/IPCPipe.cpp +++ b/src/Components/Modules/IPCPipe.cpp @@ -1,254 +1,254 @@ -#include "STDInclude.hpp" - -namespace Components -{ - Pipe* IPCPipe::ServerPipe = 0; - Pipe* IPCPipe::ClientPipe = 0; - -#pragma region Pipe - - Pipe::Pipe() : mType(IPCTYPE_NONE), ReconnectAttempt(0), hPipe(INVALID_HANDLE_VALUE), ConnectCallback(0), mThreadAttached(false) - { - this->Destroy(); - } - - Pipe::~Pipe() - { - this->Destroy(); - } - - bool Pipe::Connect(std::string name) - { - this->Destroy(); - - this->mType = IPCTYPE_CLIENT; - this->SetName(name); - - this->hPipe = CreateFileA(this->PipeFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); - - if (INVALID_HANDLE_VALUE == this->hPipe) - { - Logger::Print("Failed to connect to the pipe\n"); - - if (this->ReconnectAttempt < IPC_MAX_RECONNECTS) - { - Logger::Print("Attempting to reconnect to the pipe.\n"); - ++this->ReconnectAttempt; - std::this_thread::sleep_for(500ms); - - return this->Connect(name); - } - else - { - this->Destroy(); - return false; - } - } - - this->ReconnectAttempt = 0; - Logger::Print("Successfully connected to the pipe\n"); - - return true; - } - - bool Pipe::Create(std::string name) - { - this->Destroy(); - - this->mType = IPCTYPE_SERVER; - this->SetName(name); - - this->hPipe = CreateNamedPipeA(this->PipeFile, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, sizeof(this->mPacket), sizeof(this->mPacket), NMPWAIT_USE_DEFAULT_WAIT, NULL); - - if (INVALID_HANDLE_VALUE != this->hPipe) - { - // Only create the thread, when not performing unit tests! - if (!Loader::PerformingUnitTests()) - { - this->mThreadAttached = true; - this->mThread = std::thread(Pipe::ReceiveThread, this); - } - - Logger::Print("Pipe successfully created\n"); - return true; - } - - Logger::Print("Failed to create the pipe\n"); - this->Destroy(); - return false; - } - - void Pipe::OnConnect(Pipe::Callback callback) - { - this->ConnectCallback = callback; - } - - void Pipe::SetCallback(std::string command, Pipe::PacketCallback callback) - { - this->PacketCallbacks[command] = callback; - } - - bool Pipe::Write(std::string command, std::string data) - { - if (this->mType != IPCTYPE_CLIENT || this->hPipe == INVALID_HANDLE_VALUE) return false; - - Pipe::Packet packet; - strcpy_s(packet.Command, command.data()); - strcpy_s(packet.Buffer, data.data()); - - DWORD cbBytes; - return (WriteFile(this->hPipe, &packet, sizeof(packet), &cbBytes, NULL) || GetLastError() == ERROR_IO_PENDING); - } - - void Pipe::Destroy() - { - //this->Type = IPCTYPE_NONE; - - //*this->PipeFile = 0; - //*this->PipeName = 0; - - if (this->hPipe && INVALID_HANDLE_VALUE != this->hPipe) - { - if (this->mType == IPCTYPE_SERVER) DisconnectNamedPipe(this->hPipe); - - CloseHandle(this->hPipe); - Logger::Print("Disconnected from the pipe.\n"); - } - - this->mThreadAttached = false; - - if (this->mThread.joinable()) - { - Logger::Print("Terminating pipe thread...\n"); - - this->mThread.join(); - - Logger::Print("Pipe thread terminated.\n"); - } - } - - void Pipe::SetName(std::string name) - { - memset(this->PipeName, 0, sizeof(this->PipeName)); - memset(this->PipeFile, 0, sizeof(this->PipeFile)); - - strncpy_s(this->PipeName, name.data(), sizeof(this->PipeName)); - sprintf_s(this->PipeFile, sizeof(this->PipeFile), "\\\\.\\Pipe\\%s", this->PipeName); - } - - void Pipe::ReceiveThread(Pipe* pipe) - { - if (!pipe || pipe->mType != IPCTYPE_SERVER || pipe->hPipe == INVALID_HANDLE_VALUE || !pipe->hPipe) return; - - if (ConnectNamedPipe(pipe->hPipe, NULL) == FALSE) - { - Logger::Print("Failed to initialize pipe reading.\n"); - return; - } - - Logger::Print("Client connected to the pipe\n"); - if (pipe->ConnectCallback) pipe->ConnectCallback(); - - DWORD cbBytes; - - while (pipe->mThreadAttached && pipe->hPipe && pipe->hPipe != INVALID_HANDLE_VALUE) - { - BOOL bResult = ReadFile(pipe->hPipe, &pipe->mPacket, sizeof(pipe->mPacket), &cbBytes, NULL); - - if (bResult && cbBytes) - { - if (pipe->PacketCallbacks.find(pipe->mPacket.Command) != pipe->PacketCallbacks.end()) - { - pipe->PacketCallbacks[pipe->mPacket.Command](pipe->mPacket.Buffer); - } - } - else if (pipe->mThreadAttached && pipe->hPipe != INVALID_HANDLE_VALUE) - { - Logger::Print("Failed to read from client through pipe\n"); - - DisconnectNamedPipe(pipe->hPipe); - ConnectNamedPipe(pipe->hPipe, NULL); - if (pipe->ConnectCallback) pipe->ConnectCallback(); - } - - ZeroMemory(&pipe->mPacket, sizeof(pipe->mPacket)); - } - } - -#pragma endregion - - // Callback to connect first instance's client pipe to the second instance's server pipe - void IPCPipe::ConnectClient() - { - if (Singleton::IsFirstInstance() && IPCPipe::ClientPipe) - { - IPCPipe::ClientPipe->Connect(IPC_PIPE_NAME_CLIENT); - } - } - - // Writes to the process on the other end of the pipe - bool IPCPipe::Write(std::string command, std::string data) - { - if (IPCPipe::ClientPipe) - { - return IPCPipe::ClientPipe->Write(command, data); - } - - return false; - } - - // Installs a callback for receiving commands from the process on the other end of the pipe - void IPCPipe::On(std::string command, Pipe::PacketCallback callback) - { - if (IPCPipe::ServerPipe) - { - IPCPipe::ServerPipe->SetCallback(command, callback); - } - } - - IPCPipe::IPCPipe() - { - if (Dedicated::IsDedicated()) return; - - // Server pipe - IPCPipe::ServerPipe = new Pipe(); - IPCPipe::ServerPipe->OnConnect(IPCPipe::ConnectClient); - IPCPipe::ServerPipe->Create((Singleton::IsFirstInstance() ? IPC_PIPE_NAME_SERVER : IPC_PIPE_NAME_CLIENT)); - - // Client pipe - IPCPipe::ClientPipe = new Pipe(); - - // Connect second instance's client pipe to first instance's server pipe - if (!Singleton::IsFirstInstance()) - { - IPCPipe::ClientPipe->Connect(IPC_PIPE_NAME_SERVER); - } - - IPCPipe::On("ping", [] (std::string data) - { - Logger::Print("Received ping form pipe, sending pong!\n"); - IPCPipe::Write("pong", data); - }); - - IPCPipe::On("pong", [] (std::string data) - { - Logger::Print("Received pong form pipe!\n"); - }); - - // Test pipe functionality by sending pings - Command::Add("ipcping", [] (Command::Params params) - { - Logger::Print("Sending ping to pipe!\n"); - IPCPipe::Write("ping", ""); - }); - } - - IPCPipe::~IPCPipe() - { - if (IPCPipe::ServerPipe) delete IPCPipe::ServerPipe; - if (IPCPipe::ClientPipe) delete IPCPipe::ClientPipe; - - IPCPipe::ServerPipe = 0; - IPCPipe::ClientPipe = 0; - } -} +#include "STDInclude.hpp" + +namespace Components +{ + Pipe* IPCPipe::ServerPipe = 0; + Pipe* IPCPipe::ClientPipe = 0; + +#pragma region Pipe + + Pipe::Pipe() : mType(IPCTYPE_NONE), ReconnectAttempt(0), hPipe(INVALID_HANDLE_VALUE), ConnectCallback(0), mThreadAttached(false) + { + this->Destroy(); + } + + Pipe::~Pipe() + { + this->Destroy(); + } + + bool Pipe::Connect(std::string name) + { + this->Destroy(); + + this->mType = IPCTYPE_CLIENT; + this->SetName(name); + + this->hPipe = CreateFileA(this->PipeFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + if (INVALID_HANDLE_VALUE == this->hPipe) + { + Logger::Print("Failed to connect to the pipe\n"); + + if (this->ReconnectAttempt < IPC_MAX_RECONNECTS) + { + Logger::Print("Attempting to reconnect to the pipe.\n"); + ++this->ReconnectAttempt; + std::this_thread::sleep_for(500ms); + + return this->Connect(name); + } + else + { + this->Destroy(); + return false; + } + } + + this->ReconnectAttempt = 0; + Logger::Print("Successfully connected to the pipe\n"); + + return true; + } + + bool Pipe::Create(std::string name) + { + this->Destroy(); + + this->mType = IPCTYPE_SERVER; + this->SetName(name); + + this->hPipe = CreateNamedPipeA(this->PipeFile, PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, sizeof(this->mPacket), sizeof(this->mPacket), NMPWAIT_USE_DEFAULT_WAIT, NULL); + + if (INVALID_HANDLE_VALUE != this->hPipe) + { + // Only create the thread, when not performing unit tests! + if (!Loader::PerformingUnitTests()) + { + this->mThreadAttached = true; + this->mThread = std::thread(Pipe::ReceiveThread, this); + } + + Logger::Print("Pipe successfully created\n"); + return true; + } + + Logger::Print("Failed to create the pipe\n"); + this->Destroy(); + return false; + } + + void Pipe::OnConnect(Pipe::Callback callback) + { + this->ConnectCallback = callback; + } + + void Pipe::SetCallback(std::string command, Pipe::PacketCallback callback) + { + this->PacketCallbacks[command] = callback; + } + + bool Pipe::Write(std::string command, std::string data) + { + if (this->mType != IPCTYPE_CLIENT || this->hPipe == INVALID_HANDLE_VALUE) return false; + + Pipe::Packet packet; + strcpy_s(packet.Command, command.data()); + strcpy_s(packet.Buffer, data.data()); + + DWORD cbBytes; + return (WriteFile(this->hPipe, &packet, sizeof(packet), &cbBytes, NULL) || GetLastError() == ERROR_IO_PENDING); + } + + void Pipe::Destroy() + { + //this->Type = IPCTYPE_NONE; + + //*this->PipeFile = 0; + //*this->PipeName = 0; + + if (this->hPipe && INVALID_HANDLE_VALUE != this->hPipe) + { + if (this->mType == IPCTYPE_SERVER) DisconnectNamedPipe(this->hPipe); + + CloseHandle(this->hPipe); + Logger::Print("Disconnected from the pipe.\n"); + } + + this->mThreadAttached = false; + + if (this->mThread.joinable()) + { + Logger::Print("Terminating pipe thread...\n"); + + this->mThread.join(); + + Logger::Print("Pipe thread terminated.\n"); + } + } + + void Pipe::SetName(std::string name) + { + memset(this->PipeName, 0, sizeof(this->PipeName)); + memset(this->PipeFile, 0, sizeof(this->PipeFile)); + + strncpy_s(this->PipeName, name.data(), sizeof(this->PipeName)); + sprintf_s(this->PipeFile, sizeof(this->PipeFile), "\\\\.\\Pipe\\%s", this->PipeName); + } + + void Pipe::ReceiveThread(Pipe* pipe) + { + if (!pipe || pipe->mType != IPCTYPE_SERVER || pipe->hPipe == INVALID_HANDLE_VALUE || !pipe->hPipe) return; + + if (ConnectNamedPipe(pipe->hPipe, NULL) == FALSE) + { + Logger::Print("Failed to initialize pipe reading.\n"); + return; + } + + Logger::Print("Client connected to the pipe\n"); + if (pipe->ConnectCallback) pipe->ConnectCallback(); + + DWORD cbBytes; + + while (pipe->mThreadAttached && pipe->hPipe && pipe->hPipe != INVALID_HANDLE_VALUE) + { + BOOL bResult = ReadFile(pipe->hPipe, &pipe->mPacket, sizeof(pipe->mPacket), &cbBytes, NULL); + + if (bResult && cbBytes) + { + if (pipe->PacketCallbacks.find(pipe->mPacket.Command) != pipe->PacketCallbacks.end()) + { + pipe->PacketCallbacks[pipe->mPacket.Command](pipe->mPacket.Buffer); + } + } + else if (pipe->mThreadAttached && pipe->hPipe != INVALID_HANDLE_VALUE) + { + Logger::Print("Failed to read from client through pipe\n"); + + DisconnectNamedPipe(pipe->hPipe); + ConnectNamedPipe(pipe->hPipe, NULL); + if (pipe->ConnectCallback) pipe->ConnectCallback(); + } + + ZeroMemory(&pipe->mPacket, sizeof(pipe->mPacket)); + } + } + +#pragma endregion + + // Callback to connect first instance's client pipe to the second instance's server pipe + void IPCPipe::ConnectClient() + { + if (Singleton::IsFirstInstance() && IPCPipe::ClientPipe) + { + IPCPipe::ClientPipe->Connect(IPC_PIPE_NAME_CLIENT); + } + } + + // Writes to the process on the other end of the pipe + bool IPCPipe::Write(std::string command, std::string data) + { + if (IPCPipe::ClientPipe) + { + return IPCPipe::ClientPipe->Write(command, data); + } + + return false; + } + + // Installs a callback for receiving commands from the process on the other end of the pipe + void IPCPipe::On(std::string command, Pipe::PacketCallback callback) + { + if (IPCPipe::ServerPipe) + { + IPCPipe::ServerPipe->SetCallback(command, callback); + } + } + + IPCPipe::IPCPipe() + { + if (Dedicated::IsEnabled()) return; + + // Server pipe + IPCPipe::ServerPipe = new Pipe(); + IPCPipe::ServerPipe->OnConnect(IPCPipe::ConnectClient); + IPCPipe::ServerPipe->Create((Singleton::IsFirstInstance() ? IPC_PIPE_NAME_SERVER : IPC_PIPE_NAME_CLIENT)); + + // Client pipe + IPCPipe::ClientPipe = new Pipe(); + + // Connect second instance's client pipe to first instance's server pipe + if (!Singleton::IsFirstInstance()) + { + IPCPipe::ClientPipe->Connect(IPC_PIPE_NAME_SERVER); + } + + IPCPipe::On("ping", [] (std::string data) + { + Logger::Print("Received ping form pipe, sending pong!\n"); + IPCPipe::Write("pong", data); + }); + + IPCPipe::On("pong", [] (std::string data) + { + Logger::Print("Received pong form pipe!\n"); + }); + + // Test pipe functionality by sending pings + Command::Add("ipcping", [] (Command::Params params) + { + Logger::Print("Sending ping to pipe!\n"); + IPCPipe::Write("ping", ""); + }); + } + + IPCPipe::~IPCPipe() + { + if (IPCPipe::ServerPipe) delete IPCPipe::ServerPipe; + if (IPCPipe::ClientPipe) delete IPCPipe::ClientPipe; + + IPCPipe::ServerPipe = 0; + IPCPipe::ClientPipe = 0; + } +} diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index 77729c3e..7a9f61a5 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -8,7 +8,7 @@ namespace Components bool Logger::IsConsoleReady() { - return (IsWindow(*reinterpret_cast(0x64A3288)) != FALSE || (Dedicated::IsDedicated() && !Flags::HasFlag("console"))); + return (IsWindow(*reinterpret_cast(0x64A3288)) != FALSE || (Dedicated::IsEnabled() && !Flags::HasFlag("console"))); } void Logger::Print(const char* message, ...) diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index 9368dd62..e461dfd1 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -609,7 +609,7 @@ namespace Components Menus::Menus() { - if (Dedicated::IsDedicated()) return; + if (Dedicated::IsEnabled()) return; // Ensure everything is zero'ed Menus::FreeEverything(); diff --git a/src/Components/Modules/MusicalTalent.cpp b/src/Components/Modules/MusicalTalent.cpp index 8c91598d..e06166bb 100644 --- a/src/Components/Modules/MusicalTalent.cpp +++ b/src/Components/Modules/MusicalTalent.cpp @@ -6,14 +6,14 @@ namespace Components void MusicalTalent::Replace(std::string sound, const char* file) { - MusicalTalent::SoundAliasList[Utils::String::StrToLower(sound)] = file; + MusicalTalent::SoundAliasList[Utils::String::ToLower(sound)] = file; } Game::XAssetHeader MusicalTalent::ModifyAliases(Game::XAssetType type, std::string filename) { Game::XAssetHeader header = { 0 }; - if (MusicalTalent::SoundAliasList.find(Utils::String::StrToLower(filename)) != MusicalTalent::SoundAliasList.end()) + if (MusicalTalent::SoundAliasList.find(Utils::String::ToLower(filename)) != MusicalTalent::SoundAliasList.end()) { Game::snd_alias_list_t* aliases = Game::DB_FindXAssetHeader(type, filename.data()).aliasList; @@ -21,7 +21,7 @@ namespace Components { if (aliases->aliases->stream->type == 2) { - aliases->aliases->stream->file = MusicalTalent::SoundAliasList[Utils::String::StrToLower(filename)]; + aliases->aliases->stream->file = MusicalTalent::SoundAliasList[Utils::String::ToLower(filename)]; } header.aliasList = aliases; @@ -33,6 +33,8 @@ namespace Components MusicalTalent::MusicalTalent() { + if (ZoneBuilder::IsEnabled()) return; + AssetHandler::OnFind(Game::XAssetType::ASSET_TYPE_SOUND, MusicalTalent::ModifyAliases); MusicalTalent::Replace("music_mainmenu_mp", "hz_t_menumusic.mp3"); diff --git a/src/Components/Modules/Network.cpp b/src/Components/Modules/Network.cpp index bd54dae7..c4b5dda0 100644 --- a/src/Components/Modules/Network.cpp +++ b/src/Components/Modules/Network.cpp @@ -125,7 +125,7 @@ namespace Components void Network::Handle(std::string packet, Network::Callback* callback) { - Network::PacketHandlers[Utils::String::StrToLower(packet)] = callback; + Network::PacketHandlers[Utils::String::ToLower(packet)] = callback; } void Network::OnStart(Network::CallbackRaw* callback) @@ -228,12 +228,12 @@ namespace Components packetCommand = packetCommand.substr(0, pos); } - packetCommand = Utils::String::StrToLower(packetCommand); + packetCommand = Utils::String::ToLower(packetCommand); // Check if custom handler exists for (auto i = Network::PacketHandlers.begin(); i != Network::PacketHandlers.end(); ++i) { - if (Utils::String::StrToLower(i->first) == packetCommand) + if (Utils::String::ToLower(i->first) == packetCommand) { Network::SelectedPacket = i->first; return 0; diff --git a/src/Components/Modules/Node.cpp b/src/Components/Modules/Node.cpp index 23ade51d..1fad2629 100644 --- a/src/Components/Modules/Node.cpp +++ b/src/Components/Modules/Node.cpp @@ -37,7 +37,7 @@ namespace Components } void Node::StoreNodes(bool force) { - if (Dedicated::IsDedicated() && Dvar::Var("sv_lanOnly").Get()) return; + if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").Get()) return; static int lastStorage = 0; @@ -141,7 +141,7 @@ namespace Components if (address.IsSelf()) return; Proto::Node::List list; - list.set_is_dedi(Dedicated::IsDedicated()); + list.set_is_dedi(Dedicated::IsEnabled()); list.set_protocol(PROTOCOL); list.set_version(NODE_VERSION); @@ -222,7 +222,7 @@ namespace Components entry->lastTime = Game::Sys_Milliseconds(); - if (Dedicated::IsDedicated()) + if (Dedicated::IsEnabled()) { entry->challenge = fmt::sprintf("%X", Utils::Cryptography::Rand::GenerateInt()); @@ -245,7 +245,7 @@ namespace Components void Node::FrameHandler() { - if (Dedicated::IsDedicated() && Dvar::Var("sv_lanOnly").Get()) return; + if (Dedicated::IsEnabled() && Dvar::Var("sv_lanOnly").Get()) return; // Frame limit static int lastFrame = 0; @@ -302,7 +302,7 @@ namespace Components node.lastTime = Game::Sys_Milliseconds(); node.lastListQuery = Game::Sys_Milliseconds(); - if (Dedicated::IsDedicated()) + if (Dedicated::IsEnabled()) { Network::SendCommand(node.address, "nodeListRequest"); } @@ -361,7 +361,7 @@ namespace Components }); // Send deadline when shutting down - if (Dedicated::IsDedicated()) + if (Dedicated::IsEnabled()) { QuickPatch::OnShutdown([] () { @@ -692,7 +692,7 @@ namespace Components entry->state = Node::STATE_VALID; entry->lastTime = Game::Sys_Milliseconds(); - if (!Dedicated::IsDedicated() && entry->isDedi && ServerList::IsOnlineList() && entry->protocol == PROTOCOL) + if (!Dedicated::IsEnabled() && entry->isDedi && ServerList::IsOnlineList() && entry->protocol == PROTOCOL) { ServerList::InsertRequest(entry->address, true); } @@ -739,7 +739,7 @@ namespace Components // So we either have to register as node, or register a remote session Network::Handle("nodeListError", [] (Network::Address address, std::string data) { - if (Dedicated::IsDedicated()) + if (Dedicated::IsEnabled()) { Node::NodeEntry* entry = Node::FindNode(address); if (entry) diff --git a/src/Components/Modules/Party.cpp b/src/Components/Modules/Party.cpp index 40f78594..75bb6270 100644 --- a/src/Components/Modules/Party.cpp +++ b/src/Components/Modules/Party.cpp @@ -115,7 +115,7 @@ namespace Components Party::Party() { - static Game::dvar_t* partyEnable = Dvar::Register("party_enable", Dedicated::IsDedicated(), Game::dvar_flag::DVAR_FLAG_NONE, "Enable party system").Get(); + static Game::dvar_t* partyEnable = Dvar::Register("party_enable", Dedicated::IsEnabled(), Game::dvar_flag::DVAR_FLAG_NONE, "Enable party system").Get(); Dvar::Register("xblive_privatematch", true, Game::dvar_flag::DVAR_FLAG_WRITEPROTECTED, "").Get(); // various changes to SV_DirectConnect-y stuff to allow non-party joinees diff --git a/src/Components/Modules/Playlist.cpp b/src/Components/Modules/Playlist.cpp index 09affde5..08a7057d 100644 --- a/src/Components/Modules/Playlist.cpp +++ b/src/Components/Modules/Playlist.cpp @@ -11,7 +11,7 @@ namespace Components if (Utils::Hook::Get(0x1AD3680)) return; // Don't load playlists when dedi and no party - if (Dedicated::IsDedicated() && !Dvar::Var("party_enable").Get()) + if (Dedicated::IsEnabled() && !Dvar::Var("party_enable").Get()) { Utils::Hook::Set(0x1AD3680, true); // Set received to true Dvar::Var("xblive_privateserver").Set(true); diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index df73b1c2..2c1a4a07 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -23,7 +23,7 @@ namespace Components void QuickPatch::OnFrame(QuickPatch::Callback* callback) { - if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) { Dedicated::OnFrame(callback); } @@ -35,7 +35,7 @@ namespace Components void QuickPatch::Once(QuickPatch::Callback* callback) { - if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) { Dedicated::Once(callback); } @@ -157,7 +157,7 @@ namespace Components { Utils::Hook::Set(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): ZoneBuilder"); } - else if (Dedicated::IsDedicated()) + else if (Dedicated::IsEnabled()) { Utils::Hook::Set(0x4289E8, "IW4x (r" REVISION_STR REVISION_SUFFIX "): Dedicated"); } @@ -322,8 +322,9 @@ namespace Components //Utils::Hook::Set(0x68323A, 0xEB); // Exploit fixes - Utils::Hook(0x414D92, QuickPatch::MsgReadBitsCompressCheckSV, HOOK_CALL).Install()->Quick(); - Utils::Hook(0x4A9F56, QuickPatch::MsgReadBitsCompressCheckCL, HOOK_CALL).Install()->Quick(); + Utils::Hook::Set(0x412370, 0xC3); // SV_SteamAuthClient + Utils::Hook(0x414D92, QuickPatch::MsgReadBitsCompressCheckSV, HOOK_CALL).Install()->Quick(); // SV_ExecuteClientCommands + Utils::Hook(0x4A9F56, QuickPatch::MsgReadBitsCompressCheckCL, HOOK_CALL).Install()->Quick(); // CL_ParseServerMessage Command::Add("unlockstats", [] (Command::Params params) { diff --git a/src/Components/Modules/RCon.cpp b/src/Components/Modules/RCon.cpp index 7e5cfd08..d0b4ae01 100644 --- a/src/Components/Modules/RCon.cpp +++ b/src/Components/Modules/RCon.cpp @@ -46,7 +46,7 @@ namespace Components }); // TODO: Maybe execute that for clients as well, when we use triangular natting. - if (!Dedicated::IsDedicated()) return; + if (!Dedicated::IsEnabled()) return; // Load public key static uint8_t publicKey[] = diff --git a/src/Components/Modules/Singleton.cpp b/src/Components/Modules/Singleton.cpp index 0e029f20..7c8d5956 100644 --- a/src/Components/Modules/Singleton.cpp +++ b/src/Components/Modules/Singleton.cpp @@ -1,29 +1,29 @@ -#include "STDInclude.hpp" - -namespace Components -{ - bool Singleton::FirstInstance = true; - - bool Singleton::IsFirstInstance() - { - return Singleton::FirstInstance; - } - - Singleton::Singleton() - { - if (Flags::HasFlag("version")) - { - printf("IW4x r" REVISION_STR "-" MILESTONE " (built " __DATE__ " " __TIME__ ")\n"); - ExitProcess(0); - } - - if (Dedicated::IsDedicated() || ZoneBuilder::IsEnabled()) return; - - Singleton::FirstInstance = (CreateMutexA(NULL, FALSE, "iw4x_mutex") && GetLastError() != ERROR_ALREADY_EXISTS); - - if (!Singleton::FirstInstance && !ConnectProtocol::Used() && MessageBoxA(0, "Do you want to start another instance?", "Game already running", MB_ICONEXCLAMATION | MB_YESNO) == IDNO) - { - ExitProcess(0); - } - } -} +#include "STDInclude.hpp" + +namespace Components +{ + bool Singleton::FirstInstance = true; + + bool Singleton::IsFirstInstance() + { + return Singleton::FirstInstance; + } + + Singleton::Singleton() + { + if (Flags::HasFlag("version")) + { + printf("IW4x r" REVISION_STR "-" MILESTONE " (built " __DATE__ " " __TIME__ ")\n"); + ExitProcess(0); + } + + if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) return; + + Singleton::FirstInstance = (CreateMutexA(NULL, FALSE, "iw4x_mutex") && GetLastError() != ERROR_ALREADY_EXISTS); + + if (!Singleton::FirstInstance && !ConnectProtocol::Used() && MessageBoxA(0, "Do you want to start another instance?", "Game already running", MB_ICONEXCLAMATION | MB_YESNO) == IDNO) + { + ExitProcess(0); + } + } +} diff --git a/src/Components/Modules/Theatre.cpp b/src/Components/Modules/Theatre.cpp index cbe4c4aa..1dca1c48 100644 --- a/src/Components/Modules/Theatre.cpp +++ b/src/Components/Modules/Theatre.cpp @@ -366,7 +366,7 @@ namespace Components UIFeeder::Add(10.0f, Theatre::GetDemoCount, Theatre::GetDemoText, Theatre::SelectDemo); // set the configstrings stuff to load the default (empty) string table; this should allow demo recording on all gametypes/maps - if(!Dedicated::IsDedicated()) Utils::Hook::Set(0x47440B, "mp/defaultStringTable.csv"); + if(!Dedicated::IsEnabled()) Utils::Hook::Set(0x47440B, "mp/defaultStringTable.csv"); // Change font size Utils::Hook::Set(0x5AC854, 2); diff --git a/src/Components/Modules/Toast.cpp b/src/Components/Modules/Toast.cpp index 2ccd714f..2279de8d 100644 --- a/src/Components/Modules/Toast.cpp +++ b/src/Components/Modules/Toast.cpp @@ -95,7 +95,7 @@ namespace Components // Text float leftText = width / 2 - bWidth / 2 - cornerSize + iOffsetLeft * 2 + imgDim; float rightText = width / 2 + bWidth / 2 - cornerSize - iOffsetLeft; - Game::R_AddCmdDrawText(Utils::String::StrToUpper(toast->Title).data(), 0x7FFFFFFF, font, static_cast(leftText + (rightText - leftText) / 2 - titleSize / 2 + cornerSize), static_cast(height - bHeight / 2 + cornerSize * 2 + 7), fontSize, fontSize, 0, wColor, Game::ITEM_TEXTSTYLE_SHADOWED); // Title + Game::R_AddCmdDrawText(Utils::String::ToUpper(toast->Title).data(), 0x7FFFFFFF, font, static_cast(leftText + (rightText - leftText) / 2 - titleSize / 2 + cornerSize), static_cast(height - bHeight / 2 + cornerSize * 2 + 7), fontSize, fontSize, 0, wColor, Game::ITEM_TEXTSTYLE_SHADOWED); // Title Game::R_AddCmdDrawText(toast->Desc.data(), 0x7FFFFFFF, descfont, leftText + (rightText - leftText) / 2 - descrSize / 2 + cornerSize, static_cast(height - bHeight / 2 + cornerSize * 2 + 33), descSize, descSize, 0, wColor, Game::ITEM_TEXTSTYLE_SHADOWED); // Description } diff --git a/src/Components/Modules/ZoneBuilder.cpp b/src/Components/Modules/ZoneBuilder.cpp index 3c627bcb..ddfc257a 100644 --- a/src/Components/Modules/ZoneBuilder.cpp +++ b/src/Components/Modules/ZoneBuilder.cpp @@ -441,7 +441,7 @@ namespace Components bool ZoneBuilder::IsEnabled() { - return (Flags::HasFlag("zonebuilder") && !Dedicated::IsDedicated()); + return (Flags::HasFlag("zonebuilder") && !Dedicated::IsEnabled()); } void ZoneBuilder::BeginAssetTrace(std::string zone) diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index 13dc02a3..ce33141a 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -12,32 +12,32 @@ #define WIN32_LEAN_AND_MEAN #include -#include -#include -#include -#include +//#include +//#include +//#include +//#include #include #include -#include -#include +//#include +//#include #include -#include +//#include #include -#include -#include -#include -#include +//#include +//#include +//#include +//#include #include #include -#include -#include -#include +//#include +//#include +//#include #include -#include +//#include #include #include -#include +//#include #include #include diff --git a/src/Steam/Interfaces/SteamUser.cpp b/src/Steam/Interfaces/SteamUser.cpp index 3a9c269f..6364592d 100644 --- a/src/Steam/Interfaces/SteamUser.cpp +++ b/src/Steam/Interfaces/SteamUser.cpp @@ -1,102 +1,102 @@ -#include "STDInclude.hpp" - -namespace Steam -{ - int User::GetHSteamUser() - { - return NULL; - } - - bool User::LoggedOn() - { - return true; - } - - SteamID User::GetSteamID() - { - static unsigned int subId = 0; - - SteamID id; - - if (!subId) - { - if (Components::Dedicated::IsDedicated() || Components::ZoneBuilder::IsEnabled()) // Dedi guid - { - subId = ~0xDED1CA7E; - } - else if (Components::Singleton::IsFirstInstance()) // ECDSA guid - { - subId = Components::Auth::GetKeyHash(); - } - else // Random guid - { - subId = (Game::Sys_Milliseconds() + timeGetTime()); - } - - subId &= ~0x80000000; // Ensure it's positive - } - - id.Bits = 0x110000100000000 | subId; - return id; - } - - int User::InitiateGameConnection(void *pAuthBlob, int cbMaxAuthBlob, SteamID steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer, bool bSecure) - { - Components::Logger::Print("%s\n", __FUNCTION__); - return 0; - } - - void User::TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer) - { - } - - void User::TrackAppUsageEvent(SteamID gameID, int eAppUsageEvent, const char *pchExtraInfo) - { - } - - bool User::GetUserDataFolder(char *pchBuffer, int cubBuffer) - { - return false; - } - - void User::StartVoiceRecording() - { - } - - void User::StopVoiceRecording() - { - } - - int User::GetCompressedVoice(void *pDestBuffer, unsigned int cbDestBufferSize, unsigned int *nBytesWritten) - { - return 0; - } - - int User::DecompressVoice(void *pCompressed, unsigned int cbCompressed, void *pDestBuffer, unsigned int cbDestBufferSize, unsigned int *nBytesWritten) - { - return 0; - } - - unsigned int User::GetAuthSessionTicket(void *pTicket, int cbMaxTicket, unsigned int *pcbTicket) - { - return 0; - } - - int User::BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, SteamID steamID) - { - return 0; - } - - void User::EndAuthSession(SteamID steamID) - { - } - - void User::CancelAuthTicket(unsigned int hAuthTicket) - { - } - - unsigned int User::UserHasLicenseForApp(SteamID steamID, unsigned int appID) - { - return 0; - } -} +#include "STDInclude.hpp" + +namespace Steam +{ + int User::GetHSteamUser() + { + return NULL; + } + + bool User::LoggedOn() + { + return true; + } + + SteamID User::GetSteamID() + { + static unsigned int subId = 0; + + SteamID id; + + if (!subId) + { + if (Components::Dedicated::IsEnabled() || Components::ZoneBuilder::IsEnabled()) // Dedi guid + { + subId = ~0xDED1CA7E; + } + else if (Components::Singleton::IsFirstInstance()) // ECDSA guid + { + subId = Components::Auth::GetKeyHash(); + } + else // Random guid + { + subId = (Game::Sys_Milliseconds() + timeGetTime()); + } + + subId &= ~0x80000000; // Ensure it's positive + } + + id.Bits = 0x110000100000000 | subId; + return id; + } + + int User::InitiateGameConnection(void *pAuthBlob, int cbMaxAuthBlob, SteamID steamIDGameServer, unsigned int unIPServer, unsigned short usPortServer, bool bSecure) + { + Components::Logger::Print("%s\n", __FUNCTION__); + return 0; + } + + void User::TerminateGameConnection(unsigned int unIPServer, unsigned short usPortServer) + { + } + + void User::TrackAppUsageEvent(SteamID gameID, int eAppUsageEvent, const char *pchExtraInfo) + { + } + + bool User::GetUserDataFolder(char *pchBuffer, int cubBuffer) + { + return false; + } + + void User::StartVoiceRecording() + { + } + + void User::StopVoiceRecording() + { + } + + int User::GetCompressedVoice(void *pDestBuffer, unsigned int cbDestBufferSize, unsigned int *nBytesWritten) + { + return 0; + } + + int User::DecompressVoice(void *pCompressed, unsigned int cbCompressed, void *pDestBuffer, unsigned int cbDestBufferSize, unsigned int *nBytesWritten) + { + return 0; + } + + unsigned int User::GetAuthSessionTicket(void *pTicket, int cbMaxTicket, unsigned int *pcbTicket) + { + return 0; + } + + int User::BeginAuthSession(const void *pAuthTicket, int cbAuthTicket, SteamID steamID) + { + return 0; + } + + void User::EndAuthSession(SteamID steamID) + { + } + + void User::CancelAuthTicket(unsigned int hAuthTicket) + { + } + + unsigned int User::UserHasLicenseForApp(SteamID steamID, unsigned int appID) + { + return 0; + } +} diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 6c0b1b21..96fd97c8 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -4,13 +4,13 @@ namespace Utils { namespace String { - std::string StrToLower(std::string input) + std::string ToLower(std::string input) { std::transform(input.begin(), input.end(), input.begin(), ::tolower); return input; } - std::string StrToUpper(std::string input) + std::string ToUpper(std::string input) { std::transform(input.begin(), input.end(), input.begin(), ::toupper); return input; @@ -38,7 +38,7 @@ namespace Utils return result; } - std::string XORString(std::string str, char value) + std::string XOR(std::string str, char value) { for (unsigned int i = 0; i < str.size(); ++i) { diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 5feed183..be6a283b 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -19,8 +19,8 @@ namespace Utils return buffer; } - std::string StrToLower(std::string input); - std::string StrToUpper(std::string input); + std::string ToLower(std::string input); + std::string ToUpper(std::string input); bool EndsWith(std::string haystack, std::string needle); std::vector Explode(const std::string& str, char delim); void Replace(std::string &string, std::string find, std::string replace); @@ -33,6 +33,6 @@ namespace Utils std::string DumpHex(std::string data, std::string separator = " "); - std::string XORString(std::string str, char value); + std::string XOR(std::string str, char value); } } diff --git a/src/Utils/WebIO.cpp b/src/Utils/WebIO.cpp index 69f1c977..064cdc3f 100644 --- a/src/Utils/WebIO.cpp +++ b/src/Utils/WebIO.cpp @@ -1,462 +1,463 @@ -#include "STDInclude.hpp" - -namespace Utils -{ - WebIO::WebIO() : WebIO("WebIO") {} - - WebIO::WebIO(std::string useragent, std::string url) : WebIO(useragent) - { - WebIO::SetURL(url); - } - - WebIO::WebIO(std::string useragent) : m_timeout(5000) // 5 seconds timeout by default - { - WebIO::OpenSession(useragent); - } - - WebIO::~WebIO() - { - WebIO::m_username.clear(); - WebIO::m_password.clear(); - - WebIO::CloseConnection(); - WebIO::CloseSession(); - } - - void WebIO::OpenSession(std::string useragent) - { - WebIO::m_hSession = InternetOpenA(useragent.data(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); - } - - void WebIO::CloseSession() - { - InternetCloseHandle(WebIO::m_hSession); - } - - void WebIO::SetCredentials(std::string username, std::string password) - { - WebIO::m_username.clear(); - WebIO::m_password.clear(); - - WebIO::m_username.append(username.begin(), username.end()); - WebIO::m_password.append(password.begin(), password.end()); - } - - void WebIO::SetURL(std::string url) - { - WebIO::m_sUrl.server.clear(); - WebIO::m_sUrl.protocol.clear(); - WebIO::m_sUrl.document.clear(); - - // Insert protocol if none - if (url.find("://") == std::string::npos) - { - url = "http://" + url; - } - - PARSEDURLA pURL; - pURL.cbSize = sizeof(pURL); - ParseURLA(url.data(), &pURL); - - // Parse protocol - if (pURL.cchProtocol && pURL.cchProtocol != 0xCCCCCCCC && pURL.pszProtocol) - { - for (UINT i = 0; i < pURL.cchProtocol; ++i) - { - char lChar = static_cast(tolower(pURL.pszProtocol[i])); - WebIO::m_sUrl.protocol.append(&lChar, 1); - } - } - else - { - WebIO::m_sUrl.protocol.append("http"); - } - - // Parse suffix - std::string server; - - if (pURL.cchSuffix && pURL.cchSuffix != 0xCCCCCCCC && pURL.pszSuffix) - { - server.append(pURL.pszSuffix, pURL.cchSuffix); - } - else - { - // TODO: Add some error handling here - return; - } - - // Remove '//' from the url - if (!server.find("//")) - { - server = server.substr(2); - } - - size_t pos = server.find("/"); - if (pos == std::string::npos) - { - WebIO::m_sUrl.server = server; - WebIO::m_sUrl.document = "/"; - } - else - { - WebIO::m_sUrl.server = server.substr(0, pos); - WebIO::m_sUrl.document = server.substr(pos); - } - - WebIO::m_sUrl.raw.clear(); - WebIO::m_sUrl.raw.append(WebIO::m_sUrl.protocol); - WebIO::m_sUrl.raw.append("://"); - WebIO::m_sUrl.raw.append(WebIO::m_sUrl.server); - WebIO::m_sUrl.raw.append(WebIO::m_sUrl.document); - - WebIO::m_isFTP = (WebIO::m_sUrl.protocol == "ftp"); - } - - std::string WebIO::BuildPostBody(WebIO::Params params) - { - std::string body; - - for (auto param = params.begin(); param != params.end(); ++param) - { - std::string key = param->first; - std::string value = param->second; - - if (!body.empty()) body.append("&"); - - body.append(key); - body.append("="); - body.append(value); - } - - body.append("\0"); - - return body; - } - - std::string WebIO::Post(std::string url, std::string body) - { - WebIO::SetURL(url); - return WebIO::Post(body); - } - - std::string WebIO::Post(std::string url, WebIO::Params params) - { - WebIO::SetURL(url); - return WebIO::Post(params); - } - - std::string WebIO::Post(WebIO::Params params) - { - return WebIO::Post(WebIO::BuildPostBody(params)); - } - - std::string WebIO::Post(std::string body) - { - return WebIO::Execute("POST", body); - } - - std::string WebIO::Get(std::string url) - { - WebIO::SetURL(url); - return WebIO::Get(); - } - - std::string WebIO::Get() - { - return WebIO::Execute("GET", ""); - } - - bool WebIO::OpenConnection() - { - WORD wPort = INTERNET_DEFAULT_HTTP_PORT; - DWORD dwService = INTERNET_SERVICE_HTTP; - DWORD dwFlag = 0; - - if (WebIO::m_isFTP) - { - wPort = INTERNET_DEFAULT_FTP_PORT; - dwService = INTERNET_SERVICE_FTP; - dwFlag = INTERNET_FLAG_PASSIVE; - } - else if (WebIO::IsSecuredConnection()) - { - wPort = INTERNET_DEFAULT_HTTPS_PORT; - } - - const char* username = (WebIO::m_username.size() ? WebIO::m_username.data() : NULL); - const char* password = (WebIO::m_password.size() ? WebIO::m_password.data() : NULL); - WebIO::m_hConnect = InternetConnectA(WebIO::m_hSession, WebIO::m_sUrl.server.data(), wPort, username, password, dwService, dwFlag, 0); - - return (WebIO::m_hConnect && WebIO::m_hConnect != INVALID_HANDLE_VALUE); - } - - void WebIO::CloseConnection() - { - if (WebIO::m_hFile && WebIO::m_hFile != INVALID_HANDLE_VALUE) InternetCloseHandle(WebIO::m_hFile); - if (WebIO::m_hConnect && WebIO::m_hConnect != INVALID_HANDLE_VALUE) InternetCloseHandle(WebIO::m_hConnect); - } - - WebIO* WebIO::SetTimeout(DWORD mseconds) - { - this->m_timeout = mseconds; - return this; - } - - std::string WebIO::Execute(const char* command, std::string body) - { - if (!WebIO::OpenConnection()) return ""; - - const char *acceptTypes[] = { "application/x-www-form-urlencoded", nullptr }; - - DWORD dwFlag = INTERNET_FLAG_RELOAD | (WebIO::IsSecuredConnection() ? INTERNET_FLAG_SECURE : 0); - - // This doesn't seem to actually do anything, half of those options don't even seem to be implemented. - // Good job microsoft... ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa385328%28v=vs.85%29.aspx ) - //InternetSetOption(WebIO::m_hConnect, INTERNET_OPTION_CONNECT_TIMEOUT, &m_timeout, sizeof(m_timeout)); - //InternetSetOption(WebIO::m_hConnect, INTERNET_OPTION_RECEIVE_TIMEOUT, &m_timeout, sizeof(m_timeout)); - //InternetSetOption(WebIO::m_hConnect, INTERNET_OPTION_SEND_TIMEOUT, &m_timeout, sizeof(m_timeout)); - - WebIO::m_hFile = HttpOpenRequestA(WebIO::m_hConnect, command, WebIO::m_sUrl.document.data(), NULL, NULL, acceptTypes, dwFlag, 0); - - if (!WebIO::m_hFile || WebIO::m_hFile == INVALID_HANDLE_VALUE) - { - WebIO::CloseConnection(); - return ""; - } - - const char* headers = "Content-type: application/x-www-form-urlencoded"; - HttpSendRequestA(WebIO::m_hFile, headers, strlen(headers), const_cast(body.data()), body.size() + 1); - - std::string returnBuffer; - - DWORD size = 0; - char buffer[0x2001] = { 0 }; - - while (InternetReadFile(WebIO::m_hFile, buffer, 0x2000, &size)) - { - returnBuffer.append(buffer, size); - if (!size) break; - } - - WebIO::CloseConnection(); - - return returnBuffer; - } - - bool WebIO::IsSecuredConnection() - { - return (WebIO::m_sUrl.protocol == "https"); - } - - bool WebIO::Connect() - { - return WebIO::OpenConnection(); - } - - void WebIO::Disconnect() - { - WebIO::CloseConnection(); - } - - bool WebIO::SetDirectory(std::string directory) - { - return (FtpSetCurrentDirectoryA(WebIO::m_hConnect, directory.data()) == TRUE); - } - - bool WebIO::SetRelativeDirectory(std::string directory) - { - std::string currentDir; - - if (WebIO::GetDirectory(currentDir)) - { - WebIO::FormatPath(directory, true); - WebIO::FormatPath(currentDir, true); - - char path[MAX_PATH] = { 0 }; - PathCombineA(path, currentDir.data(), directory.data()); - - std::string newPath(path); - WebIO::FormatPath(newPath, false); - - return WebIO::SetDirectory(newPath); - } - - return false; - } - - bool WebIO::GetDirectory(std::string &directory) - { - directory.clear(); - - DWORD size = MAX_PATH; - char currentDir[MAX_PATH] = { 0 }; - - if (FtpGetCurrentDirectoryA(WebIO::m_hConnect, currentDir, &size) == TRUE) - { - directory.append(currentDir, size); - return true; - } - - return false; - } - - void WebIO::FormatPath(std::string &path, bool win) - { - size_t nPos; - std::string find = "\\"; - std::string replace = "/"; - - if (win) - { - find = "/"; - replace = "\\"; - } - - while ((nPos = path.find(find)) != std::wstring::npos) - { - path = path.replace(nPos, find.length(), replace); - } - } - - bool WebIO::CreateDirectory(std::string directory) - { - return (FtpCreateDirectoryA(WebIO::m_hConnect, directory.data()) == TRUE); - } - - // Recursively delete a directory - bool WebIO::DeleteDirectory(std::string directory) - { - std::string tempDir; - WebIO::GetDirectory(tempDir); - - WebIO::SetRelativeDirectory(directory); - - std::vector list; - - WebIO::ListFiles(".", list); - for (auto file : list) WebIO::DeleteFile(file); - - WebIO::ListDirectories(".", list); - for (auto dir : list) WebIO::DeleteDirectory(dir); - - WebIO::SetDirectory(tempDir); - - return (FtpRemoveDirectoryA(WebIO::m_hConnect, directory.data()) == TRUE); - } - - bool WebIO::RenameDirectory(std::string directory, std::string newDir) - { - return (FtpRenameFileA(WebIO::m_hConnect, directory.data(), newDir.data()) == TRUE); // According to the internetz, this should work - } - - bool WebIO::ListElements(std::string directory, std::vector &list, bool files) - { - list.clear(); - - WIN32_FIND_DATAA findFileData; - bool result = false; - DWORD dwAttribute = (files ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DIRECTORY); - - // Any filename. - std::string tempDir; - WebIO::GetDirectory(tempDir); - WebIO::SetRelativeDirectory(directory); - - WebIO::m_hFile = FtpFindFirstFileA(WebIO::m_hConnect, "*", &findFileData, INTERNET_FLAG_RELOAD, NULL); - - if (WebIO::m_hFile != INVALID_HANDLE_VALUE) - { - do - { - //if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) continue; - //if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) continue; - - if (findFileData.dwFileAttributes == dwAttribute) // No bitwise flag check, as it might return archives/offline/hidden or other files/dirs - { - //printf("%s: %X\n", findFileData.cFileName, findFileData.dwFileAttributes); - list.push_back(findFileData.cFileName); - result = true; - } - } while (InternetFindNextFileA(WebIO::m_hFile, &findFileData)); - - InternetCloseHandle(WebIO::m_hFile); - } - - WebIO::SetDirectory(tempDir); - - return result; - } - - bool WebIO::ListDirectories(std::string directory, std::vector &list) - { - return WebIO::ListElements(directory, list, false); - } - - bool WebIO::ListFiles(std::string directory, std::vector &list) - { - return WebIO::ListElements(directory, list, true); - } - - bool WebIO::UploadFile(std::string file, std::string localfile) - { - return (FtpPutFileA(WebIO::m_hConnect, localfile.data(), file.data(), FTP_TRANSFER_TYPE_BINARY, NULL) == TRUE); - } - - bool WebIO::DeleteFile(std::string file) - { - return (FtpDeleteFileA(WebIO::m_hConnect, file.data()) == TRUE); - } - - bool WebIO::RenameFile(std::string file, std::string newFile) - { - return (FtpRenameFileA(WebIO::m_hConnect, file.data(), newFile.data()) == TRUE); - } - - bool WebIO::DownloadFile(std::string file, std::string localfile) - { - return (FtpGetFileA(WebIO::m_hConnect, file.data(), localfile.data(), FALSE, NULL, FTP_TRANSFER_TYPE_BINARY, 0) == TRUE); - } - - bool WebIO::UploadFileData(std::string file, std::string data) - { - bool result = false; - WebIO::m_hFile = FtpOpenFileA(WebIO::m_hConnect, file.data(), GENERIC_WRITE, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, 0); - - if (WebIO::m_hFile) - { - DWORD size = 0; - if (InternetWriteFile(WebIO::m_hFile, data.data(), data.size(), &size) == TRUE) - { - result = (size == data.size()); - } - - InternetCloseHandle(WebIO::m_hFile); - } - - return result; - } - - bool WebIO::DownloadFileData(std::string file, std::string &data) - { - data.clear(); - - WebIO::m_hFile = FtpOpenFileA(WebIO::m_hConnect, file.data(), GENERIC_READ, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, 0); - - if (WebIO::m_hFile) - { - DWORD size = 0; - char buffer[0x2001] = { 0 }; - - while (InternetReadFile(WebIO::m_hFile, buffer, 0x2000, &size)) - { - data.append(buffer, size); - if (!size) break; - } - - InternetCloseHandle(WebIO::m_hFile); - return true; - } - - return false; - } -} +#include "STDInclude.hpp" +#include + +namespace Utils +{ + WebIO::WebIO() : WebIO("WebIO") {} + + WebIO::WebIO(std::string useragent, std::string url) : WebIO(useragent) + { + WebIO::SetURL(url); + } + + WebIO::WebIO(std::string useragent) : m_timeout(5000) // 5 seconds timeout by default + { + WebIO::OpenSession(useragent); + } + + WebIO::~WebIO() + { + WebIO::m_username.clear(); + WebIO::m_password.clear(); + + WebIO::CloseConnection(); + WebIO::CloseSession(); + } + + void WebIO::OpenSession(std::string useragent) + { + WebIO::m_hSession = InternetOpenA(useragent.data(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); + } + + void WebIO::CloseSession() + { + InternetCloseHandle(WebIO::m_hSession); + } + + void WebIO::SetCredentials(std::string username, std::string password) + { + WebIO::m_username.clear(); + WebIO::m_password.clear(); + + WebIO::m_username.append(username.begin(), username.end()); + WebIO::m_password.append(password.begin(), password.end()); + } + + void WebIO::SetURL(std::string url) + { + WebIO::m_sUrl.server.clear(); + WebIO::m_sUrl.protocol.clear(); + WebIO::m_sUrl.document.clear(); + + // Insert protocol if none + if (url.find("://") == std::string::npos) + { + url = "http://" + url; + } + + PARSEDURLA pURL; + pURL.cbSize = sizeof(pURL); + ParseURLA(url.data(), &pURL); + + // Parse protocol + if (pURL.cchProtocol && pURL.cchProtocol != 0xCCCCCCCC && pURL.pszProtocol) + { + for (UINT i = 0; i < pURL.cchProtocol; ++i) + { + char lChar = static_cast(tolower(pURL.pszProtocol[i])); + WebIO::m_sUrl.protocol.append(&lChar, 1); + } + } + else + { + WebIO::m_sUrl.protocol.append("http"); + } + + // Parse suffix + std::string server; + + if (pURL.cchSuffix && pURL.cchSuffix != 0xCCCCCCCC && pURL.pszSuffix) + { + server.append(pURL.pszSuffix, pURL.cchSuffix); + } + else + { + // TODO: Add some error handling here + return; + } + + // Remove '//' from the url + if (!server.find("//")) + { + server = server.substr(2); + } + + size_t pos = server.find("/"); + if (pos == std::string::npos) + { + WebIO::m_sUrl.server = server; + WebIO::m_sUrl.document = "/"; + } + else + { + WebIO::m_sUrl.server = server.substr(0, pos); + WebIO::m_sUrl.document = server.substr(pos); + } + + WebIO::m_sUrl.raw.clear(); + WebIO::m_sUrl.raw.append(WebIO::m_sUrl.protocol); + WebIO::m_sUrl.raw.append("://"); + WebIO::m_sUrl.raw.append(WebIO::m_sUrl.server); + WebIO::m_sUrl.raw.append(WebIO::m_sUrl.document); + + WebIO::m_isFTP = (WebIO::m_sUrl.protocol == "ftp"); + } + + std::string WebIO::BuildPostBody(WebIO::Params params) + { + std::string body; + + for (auto param = params.begin(); param != params.end(); ++param) + { + std::string key = param->first; + std::string value = param->second; + + if (!body.empty()) body.append("&"); + + body.append(key); + body.append("="); + body.append(value); + } + + body.append("\0"); + + return body; + } + + std::string WebIO::Post(std::string url, std::string body) + { + WebIO::SetURL(url); + return WebIO::Post(body); + } + + std::string WebIO::Post(std::string url, WebIO::Params params) + { + WebIO::SetURL(url); + return WebIO::Post(params); + } + + std::string WebIO::Post(WebIO::Params params) + { + return WebIO::Post(WebIO::BuildPostBody(params)); + } + + std::string WebIO::Post(std::string body) + { + return WebIO::Execute("POST", body); + } + + std::string WebIO::Get(std::string url) + { + WebIO::SetURL(url); + return WebIO::Get(); + } + + std::string WebIO::Get() + { + return WebIO::Execute("GET", ""); + } + + bool WebIO::OpenConnection() + { + WORD wPort = INTERNET_DEFAULT_HTTP_PORT; + DWORD dwService = INTERNET_SERVICE_HTTP; + DWORD dwFlag = 0; + + if (WebIO::m_isFTP) + { + wPort = INTERNET_DEFAULT_FTP_PORT; + dwService = INTERNET_SERVICE_FTP; + dwFlag = INTERNET_FLAG_PASSIVE; + } + else if (WebIO::IsSecuredConnection()) + { + wPort = INTERNET_DEFAULT_HTTPS_PORT; + } + + const char* username = (WebIO::m_username.size() ? WebIO::m_username.data() : NULL); + const char* password = (WebIO::m_password.size() ? WebIO::m_password.data() : NULL); + WebIO::m_hConnect = InternetConnectA(WebIO::m_hSession, WebIO::m_sUrl.server.data(), wPort, username, password, dwService, dwFlag, 0); + + return (WebIO::m_hConnect && WebIO::m_hConnect != INVALID_HANDLE_VALUE); + } + + void WebIO::CloseConnection() + { + if (WebIO::m_hFile && WebIO::m_hFile != INVALID_HANDLE_VALUE) InternetCloseHandle(WebIO::m_hFile); + if (WebIO::m_hConnect && WebIO::m_hConnect != INVALID_HANDLE_VALUE) InternetCloseHandle(WebIO::m_hConnect); + } + + WebIO* WebIO::SetTimeout(DWORD mseconds) + { + this->m_timeout = mseconds; + return this; + } + + std::string WebIO::Execute(const char* command, std::string body) + { + if (!WebIO::OpenConnection()) return ""; + + const char *acceptTypes[] = { "application/x-www-form-urlencoded", nullptr }; + + DWORD dwFlag = INTERNET_FLAG_RELOAD | (WebIO::IsSecuredConnection() ? INTERNET_FLAG_SECURE : 0); + + // This doesn't seem to actually do anything, half of those options don't even seem to be implemented. + // Good job microsoft... ( https://msdn.microsoft.com/en-us/library/windows/desktop/aa385328%28v=vs.85%29.aspx ) + //InternetSetOption(WebIO::m_hConnect, INTERNET_OPTION_CONNECT_TIMEOUT, &m_timeout, sizeof(m_timeout)); + //InternetSetOption(WebIO::m_hConnect, INTERNET_OPTION_RECEIVE_TIMEOUT, &m_timeout, sizeof(m_timeout)); + //InternetSetOption(WebIO::m_hConnect, INTERNET_OPTION_SEND_TIMEOUT, &m_timeout, sizeof(m_timeout)); + + WebIO::m_hFile = HttpOpenRequestA(WebIO::m_hConnect, command, WebIO::m_sUrl.document.data(), NULL, NULL, acceptTypes, dwFlag, 0); + + if (!WebIO::m_hFile || WebIO::m_hFile == INVALID_HANDLE_VALUE) + { + WebIO::CloseConnection(); + return ""; + } + + const char* headers = "Content-type: application/x-www-form-urlencoded"; + HttpSendRequestA(WebIO::m_hFile, headers, strlen(headers), const_cast(body.data()), body.size() + 1); + + std::string returnBuffer; + + DWORD size = 0; + char buffer[0x2001] = { 0 }; + + while (InternetReadFile(WebIO::m_hFile, buffer, 0x2000, &size)) + { + returnBuffer.append(buffer, size); + if (!size) break; + } + + WebIO::CloseConnection(); + + return returnBuffer; + } + + bool WebIO::IsSecuredConnection() + { + return (WebIO::m_sUrl.protocol == "https"); + } + + bool WebIO::Connect() + { + return WebIO::OpenConnection(); + } + + void WebIO::Disconnect() + { + WebIO::CloseConnection(); + } + + bool WebIO::SetDirectory(std::string directory) + { + return (FtpSetCurrentDirectoryA(WebIO::m_hConnect, directory.data()) == TRUE); + } + + bool WebIO::SetRelativeDirectory(std::string directory) + { + std::string currentDir; + + if (WebIO::GetDirectory(currentDir)) + { + WebIO::FormatPath(directory, true); + WebIO::FormatPath(currentDir, true); + + char path[MAX_PATH] = { 0 }; + PathCombineA(path, currentDir.data(), directory.data()); + + std::string newPath(path); + WebIO::FormatPath(newPath, false); + + return WebIO::SetDirectory(newPath); + } + + return false; + } + + bool WebIO::GetDirectory(std::string &directory) + { + directory.clear(); + + DWORD size = MAX_PATH; + char currentDir[MAX_PATH] = { 0 }; + + if (FtpGetCurrentDirectoryA(WebIO::m_hConnect, currentDir, &size) == TRUE) + { + directory.append(currentDir, size); + return true; + } + + return false; + } + + void WebIO::FormatPath(std::string &path, bool win) + { + size_t nPos; + std::string find = "\\"; + std::string replace = "/"; + + if (win) + { + find = "/"; + replace = "\\"; + } + + while ((nPos = path.find(find)) != std::wstring::npos) + { + path = path.replace(nPos, find.length(), replace); + } + } + + bool WebIO::CreateDirectory(std::string directory) + { + return (FtpCreateDirectoryA(WebIO::m_hConnect, directory.data()) == TRUE); + } + + // Recursively delete a directory + bool WebIO::DeleteDirectory(std::string directory) + { + std::string tempDir; + WebIO::GetDirectory(tempDir); + + WebIO::SetRelativeDirectory(directory); + + std::vector list; + + WebIO::ListFiles(".", list); + for (auto file : list) WebIO::DeleteFile(file); + + WebIO::ListDirectories(".", list); + for (auto dir : list) WebIO::DeleteDirectory(dir); + + WebIO::SetDirectory(tempDir); + + return (FtpRemoveDirectoryA(WebIO::m_hConnect, directory.data()) == TRUE); + } + + bool WebIO::RenameDirectory(std::string directory, std::string newDir) + { + return (FtpRenameFileA(WebIO::m_hConnect, directory.data(), newDir.data()) == TRUE); // According to the internetz, this should work + } + + bool WebIO::ListElements(std::string directory, std::vector &list, bool files) + { + list.clear(); + + WIN32_FIND_DATAA findFileData; + bool result = false; + DWORD dwAttribute = (files ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DIRECTORY); + + // Any filename. + std::string tempDir; + WebIO::GetDirectory(tempDir); + WebIO::SetRelativeDirectory(directory); + + WebIO::m_hFile = FtpFindFirstFileA(WebIO::m_hConnect, "*", &findFileData, INTERNET_FLAG_RELOAD, NULL); + + if (WebIO::m_hFile != INVALID_HANDLE_VALUE) + { + do + { + //if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) continue; + //if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) continue; + + if (findFileData.dwFileAttributes == dwAttribute) // No bitwise flag check, as it might return archives/offline/hidden or other files/dirs + { + //printf("%s: %X\n", findFileData.cFileName, findFileData.dwFileAttributes); + list.push_back(findFileData.cFileName); + result = true; + } + } while (InternetFindNextFileA(WebIO::m_hFile, &findFileData)); + + InternetCloseHandle(WebIO::m_hFile); + } + + WebIO::SetDirectory(tempDir); + + return result; + } + + bool WebIO::ListDirectories(std::string directory, std::vector &list) + { + return WebIO::ListElements(directory, list, false); + } + + bool WebIO::ListFiles(std::string directory, std::vector &list) + { + return WebIO::ListElements(directory, list, true); + } + + bool WebIO::UploadFile(std::string file, std::string localfile) + { + return (FtpPutFileA(WebIO::m_hConnect, localfile.data(), file.data(), FTP_TRANSFER_TYPE_BINARY, NULL) == TRUE); + } + + bool WebIO::DeleteFile(std::string file) + { + return (FtpDeleteFileA(WebIO::m_hConnect, file.data()) == TRUE); + } + + bool WebIO::RenameFile(std::string file, std::string newFile) + { + return (FtpRenameFileA(WebIO::m_hConnect, file.data(), newFile.data()) == TRUE); + } + + bool WebIO::DownloadFile(std::string file, std::string localfile) + { + return (FtpGetFileA(WebIO::m_hConnect, file.data(), localfile.data(), FALSE, NULL, FTP_TRANSFER_TYPE_BINARY, 0) == TRUE); + } + + bool WebIO::UploadFileData(std::string file, std::string data) + { + bool result = false; + WebIO::m_hFile = FtpOpenFileA(WebIO::m_hConnect, file.data(), GENERIC_WRITE, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, 0); + + if (WebIO::m_hFile) + { + DWORD size = 0; + if (InternetWriteFile(WebIO::m_hFile, data.data(), data.size(), &size) == TRUE) + { + result = (size == data.size()); + } + + InternetCloseHandle(WebIO::m_hFile); + } + + return result; + } + + bool WebIO::DownloadFileData(std::string file, std::string &data) + { + data.clear(); + + WebIO::m_hFile = FtpOpenFileA(WebIO::m_hConnect, file.data(), GENERIC_READ, INTERNET_FLAG_TRANSFER_BINARY | INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, 0); + + if (WebIO::m_hFile) + { + DWORD size = 0; + char buffer[0x2001] = { 0 }; + + while (InternetReadFile(WebIO::m_hFile, buffer, 0x2000, &size)) + { + data.append(buffer, size); + if (!size) break; + } + + InternetCloseHandle(WebIO::m_hFile); + return true; + } + + return false; + } +}