diff --git a/src/Components/Loader.cpp b/src/Components/Loader.cpp index 6c08d328..d23a24ba 100644 --- a/src/Components/Loader.cpp +++ b/src/Components/Loader.cpp @@ -10,6 +10,7 @@ namespace Components Loader::Register(new Dvar()); Loader::Register(new Maps()); + Loader::Register(new News()); Loader::Register(new Menus()); Loader::Register(new Party()); Loader::Register(new Colors()); diff --git a/src/Components/Loader.hpp b/src/Components/Loader.hpp index 739d2081..aacc9992 100644 --- a/src/Components/Loader.hpp +++ b/src/Components/Loader.hpp @@ -22,6 +22,7 @@ namespace Components #include "Modules\Dvar.hpp" #include "Modules\Maps.hpp" +#include "Modules\News.hpp" #include "Modules\Menus.hpp" #include "Modules\Colors.hpp" #include "Modules\Logger.hpp" diff --git a/src/Components/Modules/News.cpp b/src/Components/Modules/News.cpp new file mode 100644 index 00000000..3a38dcda --- /dev/null +++ b/src/Components/Modules/News.cpp @@ -0,0 +1,24 @@ +#include "..\..\STDInclude.hpp" + +namespace Components +{ + std::string News::Motd; + + const char* News::GetMotd() + { + return News::Motd.data(); + } + + News::News() + { + News::Motd = Utils::WebIO("IW4x", "http://localhost/iw4/motd.txt").Get(); + + if (!News::Motd.size()) + { + News::Motd = "Welcome to ReactIW4x Multiplayer!"; + } + + // Patch motd setting + Utils::Hook(0x60BF19, News::GetMotd, HOOK_CALL).Install()->Quick(); + } +} diff --git a/src/Components/Modules/News.hpp b/src/Components/Modules/News.hpp new file mode 100644 index 00000000..aefd38cc --- /dev/null +++ b/src/Components/Modules/News.hpp @@ -0,0 +1,13 @@ +namespace Components +{ + class News : public Component + { + public: + News(); + const char* GetName() { return "News"; }; + + private: + static std::string Motd; + static const char* GetMotd(); + }; +} diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index b98ca295..470ea770 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -108,10 +108,6 @@ namespace Components // Enable commandline arguments Utils::Hook::Set(0x464AE4, 0xEB); - // MOTD - Utils::Hook::Nop(0x60BF24, 5); - Utils::Hook::Set(0x4053CB, "Welcome to ReactIW4x Multiplayer!"); - // remove limit on IWD file loading Utils::Hook::Set(0x642BF3, 0xEB); diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index ceb1108b..b789173f 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -20,6 +20,7 @@ #include #include "Utils\Utils.hpp" +#include "Utils\WebIO.hpp" #include "Utils\Hooking.hpp" #include "Steam\Steam.hpp" diff --git a/src/Utils/WebIO.cpp b/src/Utils/WebIO.cpp new file mode 100644 index 00000000..50093178 --- /dev/null +++ b/src/Utils/WebIO.cpp @@ -0,0 +1,443 @@ +#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) + { + 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 = InternetOpen(useragent.c_str(), 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.c_str(), &pURL); + + // Parse protocol + if (pURL.cchProtocol && pURL.cchProtocol != 0xCCCCCCCC && pURL.pszProtocol) + { + for (UINT i = 0; i < pURL.cchProtocol; i++) + { + char lChar = 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.size()) 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.c_str() : NULL); + const char* password = (WebIO::m_password.size() ? WebIO::m_password.c_str() : NULL); + WebIO::m_hConnect = InternetConnect(WebIO::m_hSession, WebIO::m_sUrl.server.c_str(), wPort, username, password, dwService, dwFlag, 0); + + return (WebIO::m_hConnect != INVALID_HANDLE_VALUE); + } + + void WebIO::CloseConnection() + { + InternetCloseHandle(WebIO::m_hFile); + InternetCloseHandle(WebIO::m_hConnect); + } + + std::string WebIO::Execute(const char* command, std::string body) + { + WebIO::OpenConnection(); + + const char *acceptTypes[] = { "application/x-www-form-urlencoded", nullptr }; + + DWORD dwFlag = INTERNET_FLAG_RELOAD | (WebIO::IsSecuredConnection() ? INTERNET_FLAG_SECURE : 0); + WebIO::m_hFile = HttpOpenRequest(WebIO::m_hConnect, command, WebIO::m_sUrl.document.c_str(), NULL, NULL, acceptTypes, dwFlag, 0); + + const char* headers = "Content-type: application/x-www-form-urlencoded"; + HttpSendRequest(WebIO::m_hFile, headers, strlen(headers), (char*)body.c_str(), 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.c_str()) == 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.c_str(), directory.c_str()); + + 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.c_str()) == 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.c_str()) == TRUE); + } + + bool WebIO::RenameDirectory(std::string directory, std::string newDir) + { + return (FtpRenameFileA(WebIO::m_hConnect, directory.c_str(), newDir.c_str()) == TRUE); // According to the internetz, this should work + } + + bool WebIO::ListElements(std::string directory, std::vector &list, bool files) + { + list.clear(); + + WIN32_FIND_DATA 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.c_str(), file.c_str(), FTP_TRANSFER_TYPE_BINARY, NULL) == TRUE); + } + + bool WebIO::DeleteFile(std::string file) + { + return (FtpDeleteFileA(WebIO::m_hConnect, file.c_str()) == TRUE); + } + + bool WebIO::RenameFile(std::string file, std::string newFile) + { + return (FtpRenameFileA(WebIO::m_hConnect, file.c_str(), newFile.c_str()) == TRUE); + } + + bool WebIO::DownloadFile(std::string file, std::string localfile) + { + return (FtpGetFileA(WebIO::m_hConnect, file.c_str(), localfile.c_str(), 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.c_str(), 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.c_str(), 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.c_str(), 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; + } +} diff --git a/src/Utils/WebIO.hpp b/src/Utils/WebIO.hpp new file mode 100644 index 00000000..457dcc8e --- /dev/null +++ b/src/Utils/WebIO.hpp @@ -0,0 +1,113 @@ +/* + This project is released under the GPL 2.0 license. + Some parts are based on research by Bas Timmer and the OpenSteamworks project. + Please do no evil. + + Initial author: (https://github.com/)momo5502 + Started: 2015-03-01 + Notes: + Small FTP and HTTP utility class using WinAPI +*/ + +#pragma once +#include +#include +#include +#include +#include +#include + +#pragma comment(lib, "Wininet.lib") +#pragma comment(lib, "shlwapi.lib") +#pragma comment(lib, "Ws2_32.lib") + +namespace Utils +{ + class WebIO + { + public: + + typedef std::map Params; + + WebIO(); + WebIO(std::string useragent); + WebIO(std::string useragent, std::string url); + + ~WebIO(); + + void SetURL(std::string url); + void SetCredentials(std::string username, std::string password); + + std::string Post(std::string url, WebIO::Params params); + std::string Post(std::string url, std::string body); + std::string Post(WebIO::Params params); + std::string Post(std::string body); + + std::string Get(std::string url); + std::string Get(); + + // FTP + bool Connect(); + void Disconnect(); // Not necessary + + bool SetDirectory(std::string directory); + bool SetRelativeDirectory(std::string directory); + bool GetDirectory(std::string &directory); + bool CreateDirectory(std::string directory); + bool DeleteDirectory(std::string directory); + bool RenameDirectory(std::string directory, std::string newDir); + + bool ListDirectories(std::string directory, std::vector &list); + bool ListFiles(std::string directory, std::vector &list); + + bool DeleteFile(std::string file); + bool RenameFile(std::string file, std::string newFile); + bool UploadFile(std::string file, std::string localfile); + bool DownloadFile(std::string file, std::string localfile); + + bool UploadFileData(std::string file, std::string data); + bool DownloadFileData(std::string file, std::string &data); + + private: + + enum Command + { + COMMAND_POST, + COMMAND_GET, + }; + + struct WebURL + { + std::string protocol; + std::string server; + std::string document; + std::string raw; + }; + + bool m_isFTP; + std::string m_username; + std::string m_password; + + WebURL m_sUrl; + + HINTERNET m_hSession; + HINTERNET m_hConnect; + HINTERNET m_hFile; + + std::string BuildPostBody(WebIO::Params params); + + bool IsSecuredConnection(); + + std::string Execute(const char* command, std::string body); + + bool ListElements(std::string directory, std::vector &list, bool files); + + void OpenSession(std::string useragent); + void CloseSession(); + + bool OpenConnection(); + void CloseConnection(); + + void FormatPath(std::string &path, bool win); /* if (win == true): / -> \\ */ + }; +}