diff --git a/CMakeLists.txt b/CMakeLists.txt index caa61e4e..a9218bdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,10 +15,10 @@ foreach(variable ${variables}) # If the string contains a #, skip it if(NOT "${variable}" MATCHES "#") - # Split the variable into name and value + # Split the variable into name and value string(REPLACE "=" ";" variable ${variable}) - # Check that the length of the variable is 2 (name and value) + # Check that the length of the variable is 2 (name and value) list(LENGTH variable length) if(${length} EQUAL 2) @@ -83,7 +83,7 @@ make_directory(${CMAKE_BINARY_DIR}/locale) # Create a /logs directory make_directory(${CMAKE_BINARY_DIR}/logs) -# Copy ini files on first build +# Copy resource files on first build set(RESOURCE_FILES "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf") foreach(resource_file ${RESOURCE_FILES}) if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file}) diff --git a/dChatFilter/dChatFilter.cpp b/dChatFilter/dChatFilter.cpp index eb6674a4..6389623e 100644 --- a/dChatFilter/dChatFilter.cpp +++ b/dChatFilter/dChatFilter.cpp @@ -37,15 +37,15 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) { while (res->next()) { std::string line = res->getString(1).c_str(); std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase - m_YesYesWords.push_back(CalculateHash(line)); + m_ApprovedWords.push_back(CalculateHash(line)); } delete res; delete stmt; } dChatFilter::~dChatFilter() { - m_YesYesWords.clear(); - m_NoNoWords.clear(); + m_ApprovedWords.clear(); + m_DeniedWords.clear(); } void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) { @@ -55,8 +55,8 @@ void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteL while (std::getline(file, line)) { line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); std::transform(line.begin(), line.end(), line.begin(), ::tolower); //Transform to lowercase - if (whiteList) m_YesYesWords.push_back(CalculateHash(line)); - else m_NoNoWords.push_back(CalculateHash(line)); + if (whiteList) m_ApprovedWords.push_back(CalculateHash(line)); + else m_DeniedWords.push_back(CalculateHash(line)); } } } @@ -74,14 +74,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) { if (hdr.formatVersion == formatVersion) { size_t wordsToRead = 0; BinaryIO::BinaryRead(file, wordsToRead); - if (whiteList) m_YesYesWords.reserve(wordsToRead); - else m_NoNoWords.reserve(wordsToRead); + if (whiteList) m_ApprovedWords.reserve(wordsToRead); + else m_DeniedWords.reserve(wordsToRead); size_t word = 0; for (size_t i = 0; i < wordsToRead; ++i) { BinaryIO::BinaryRead(file, word); - if (whiteList) m_YesYesWords.push_back(word); - else m_NoNoWords.push_back(word); + if (whiteList) m_ApprovedWords.push_back(word); + else m_DeniedWords.push_back(word); } return true; @@ -100,9 +100,9 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis if (file) { BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header)); BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion)); - BinaryIO::BinaryWrite(file, size_t(whiteList ? m_YesYesWords.size() : m_NoNoWords.size())); + BinaryIO::BinaryWrite(file, size_t(whiteList ? m_ApprovedWords.size() : m_DeniedWords.size())); - for (size_t word : whiteList ? m_YesYesWords : m_NoNoWords) { + for (size_t word : whiteList ? m_ApprovedWords : m_DeniedWords) { BinaryIO::BinaryWrite(file, word); } @@ -110,16 +110,18 @@ void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteLis } } -std::vector dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList) { +std::vector> dChatFilter::IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList) { if (gmLevel > GAME_MASTER_LEVEL_FORUM_MODERATOR) return { }; //If anything but a forum mod, return true. if (message.empty()) return { }; - if (!whiteList && m_NoNoWords.empty()) return { "" }; + if (!whiteList && m_DeniedWords.empty()) return { { 0, message.length() } }; std::stringstream sMessage(message); std::string segment; std::regex reg("(!*|\\?*|\\;*|\\.*|\\,*)"); - std::vector listOfBadSegments = std::vector(); + std::vector> listOfBadSegments = std::vector>(); + + uint32_t position = 0; while (std::getline(sMessage, segment, ' ')) { std::string originalSegment = segment; @@ -130,18 +132,20 @@ std::vector dChatFilter::IsSentenceOkay(const std::string& message, size_t hash = CalculateHash(segment); if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) { - listOfBadSegments.push_back(originalSegment); + listOfBadSegments.emplace_back(position, originalSegment.length()); } - if (std::find(m_YesYesWords.begin(), m_YesYesWords.end(), hash) == m_YesYesWords.end() && whiteList) { + if (std::find(m_ApprovedWords.begin(), m_ApprovedWords.end(), hash) == m_ApprovedWords.end() && whiteList) { m_UserUnapprovedWordCache.push_back(hash); - listOfBadSegments.push_back(originalSegment); + listOfBadSegments.emplace_back(position, originalSegment.length()); } - if (std::find(m_NoNoWords.begin(), m_NoNoWords.end(), hash) != m_NoNoWords.end() && !whiteList) { + if (std::find(m_DeniedWords.begin(), m_DeniedWords.end(), hash) != m_DeniedWords.end() && !whiteList) { m_UserUnapprovedWordCache.push_back(hash); - listOfBadSegments.push_back(originalSegment); + listOfBadSegments.emplace_back(position, originalSegment.length()); } + + position += segment.length() + 1; } return listOfBadSegments; @@ -153,4 +157,4 @@ size_t dChatFilter::CalculateHash(const std::string& word) { size_t value = hash(word); return value; -} \ No newline at end of file +} diff --git a/dChatFilter/dChatFilter.h b/dChatFilter/dChatFilter.h index 62a47242..7e7dd859 100644 --- a/dChatFilter/dChatFilter.h +++ b/dChatFilter/dChatFilter.h @@ -23,14 +23,14 @@ public: void ReadWordlistPlaintext(const std::string& filepath, bool whiteList); bool ReadWordlistDCF(const std::string& filepath, bool whiteList); void ExportWordlistToDCF(const std::string& filepath, bool whiteList); - std::vector IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList = true); + std::vector> IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList = true); private: bool m_DontGenerateDCF; - std::vector m_NoNoWords; - std::vector m_YesYesWords; + std::vector m_DeniedWords; + std::vector m_ApprovedWords; std::vector m_UserUnapprovedWordCache; //Private functions: size_t CalculateHash(const std::string& word); -}; \ No newline at end of file +}; diff --git a/dNet/ClientPackets.cpp b/dNet/ClientPackets.cpp index abb08688..b9f715ad 100644 --- a/dNet/ClientPackets.cpp +++ b/dNet/ClientPackets.cpp @@ -288,7 +288,7 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa } if (!receiver.empty()) { - if (std::string(receiver.c_str(), 4) == "[GM]") { + if (std::string(receiver.c_str(), 4) == "[GM]") { // Shift the string forward if we are speaking to a GM as the client appends "[GM]" if they are receiver = std::string(receiver.c_str() + 4, receiver.size() - 4); } } @@ -315,6 +315,9 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa if (res->next()) { idOfReceiver = res->getInt("id"); } + + delete stmt; + delete res; } if (user->GetIsBestFriendMap().find(receiver) == user->GetIsBestFriendMap().end() && idOfReceiver != LWOOBJID_EMPTY) { @@ -344,26 +347,14 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa } } - std::unordered_map unacceptedItems; - std::vector segments = Game::chatFilter->IsSentenceOkay(message, entity->GetGMLevel(), !(isBestFriend && chatLevel == 1)); + std::vector> segments = Game::chatFilter->IsSentenceOkay(message, entity->GetGMLevel(), !(isBestFriend && chatLevel == 1)); bool bAllClean = segments.empty(); - if (!bAllClean) { - for (const auto& item : segments) { - if (item == "") { - unacceptedItems.insert({ (char)0, (char)message.length()}); - break; - } - - unacceptedItems.insert({ message.find(item), item.length() }); - } - } - if (user->GetIsMuted()) { bAllClean = false; } user->SetLastChatMessageApproved(bAllClean); - WorldPackets::SendChatModerationResponse(sysAddr, bAllClean, requestID, receiver, unacceptedItems); + WorldPackets::SendChatModerationResponse(sysAddr, bAllClean, requestID, receiver, segments); } diff --git a/dNet/WorldPackets.cpp b/dNet/WorldPackets.cpp index 94792c91..54c925d6 100644 --- a/dNet/WorldPackets.cpp +++ b/dNet/WorldPackets.cpp @@ -188,28 +188,28 @@ void WorldPackets::SendCreateCharacter(const SystemAddress& sysAddr, Entity* ent Game::logger->Log("WorldPackets", "Sent CreateCharacter for ID: %llu\n", entity->GetObjectID()); } -void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::unordered_map unacceptedItems) { - CBITSTREAM - PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHAT_MODERATION_STRING); +void WorldPackets::SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector> unacceptedItems) { + CBITSTREAM + PacketUtils::WriteHeader(bitStream, CLIENT, MSG_CLIENT_CHAT_MODERATION_STRING); bitStream.Write(unacceptedItems.empty()); // Is sentence ok? bitStream.Write(0x16); // Source ID, unknown bitStream.Write(static_cast(requestID)); // request ID - bitStream.Write(static_cast(0)); // chat mode + bitStream.Write(static_cast(0)); // chat mode PacketUtils::WritePacketWString(receiver, 42, &bitStream); // receiver name - for (auto it : unacceptedItems) { - bitStream.Write(it.first); // start index - bitStream.Write(it.second); // length - } + for (auto it : unacceptedItems) { + bitStream.Write(it.first); // start index + bitStream.Write(it.second); // length + } for (int i = unacceptedItems.size(); 64 > i; i++) { bitStream.Write(0); } - SEND_PACKET + SEND_PACKET } void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success, uint8_t highestLevel, uint8_t prevLevel, uint8_t newLevel) { diff --git a/dNet/WorldPackets.h b/dNet/WorldPackets.h index 3508d6f0..b88602a4 100644 --- a/dNet/WorldPackets.h +++ b/dNet/WorldPackets.h @@ -18,7 +18,7 @@ namespace WorldPackets { void SendTransferToWorld(const SystemAddress& sysAddr, const std::string& serverIP, uint32_t serverPort, bool mythranShift); void SendServerState(const SystemAddress& sysAddr); void SendCreateCharacter(const SystemAddress& sysAddr, Entity* entity, const std::string& xmlData, const std::u16string& username, int32_t gm); - void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::unordered_map unacceptedItems); + void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector> unacceptedItems); void SendGMLevelChange(const SystemAddress& sysAddr, bool success, uint8_t highestLevel, uint8_t prevLevel, uint8_t newLevel); }