diff --git a/dChatFilter/dChatFilter.cpp b/dChatFilter/dChatFilter.cpp index fe8a0d10..eb6674a4 100644 --- a/dChatFilter/dChatFilter.cpp +++ b/dChatFilter/dChatFilter.cpp @@ -19,12 +19,12 @@ dChatFilter::dChatFilter(const std::string& filepath, bool dontGenerateDCF) { m_DontGenerateDCF = dontGenerateDCF; if (!BinaryIO::DoesFileExist(filepath + ".dcf") || m_DontGenerateDCF) { - ReadWordlistPlaintext(filepath + ".txt"); - if (!m_DontGenerateDCF) ExportWordlistToDCF(filepath + ".dcf"); + ReadWordlistPlaintext(filepath + ".txt", true); + if (!m_DontGenerateDCF) ExportWordlistToDCF(filepath + ".dcf", true); } else if (!ReadWordlistDCF(filepath + ".dcf", true)) { - ReadWordlistPlaintext(filepath + ".txt"); - ExportWordlistToDCF(filepath + ".dcf"); + ReadWordlistPlaintext(filepath + ".txt", true); + ExportWordlistToDCF(filepath + ".dcf", true); } if (BinaryIO::DoesFileExist("blacklist.dcf")) { @@ -48,14 +48,15 @@ dChatFilter::~dChatFilter() { m_NoNoWords.clear(); } -void dChatFilter::ReadWordlistPlaintext(const std::string& filepath) { +void dChatFilter::ReadWordlistPlaintext(const std::string& filepath, bool whiteList) { std::ifstream file(filepath); if (file) { std::string line; 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 - m_YesYesWords.push_back(CalculateHash(line)); + if (whiteList) m_YesYesWords.push_back(CalculateHash(line)); + else m_NoNoWords.push_back(CalculateHash(line)); } } } @@ -94,14 +95,14 @@ bool dChatFilter::ReadWordlistDCF(const std::string& filepath, bool whiteList) { return false; } -void dChatFilter::ExportWordlistToDCF(const std::string& filepath) { +void dChatFilter::ExportWordlistToDCF(const std::string& filepath, bool whiteList) { std::ofstream file(filepath, std::ios::binary | std::ios_base::out); if (file) { BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::header)); BinaryIO::BinaryWrite(file, uint32_t(dChatFilterDCF::formatVersion)); - BinaryIO::BinaryWrite(file, size_t(m_YesYesWords.size())); + BinaryIO::BinaryWrite(file, size_t(whiteList ? m_YesYesWords.size() : m_NoNoWords.size())); - for (size_t word : m_YesYesWords) { + for (size_t word : whiteList ? m_YesYesWords : m_NoNoWords) { BinaryIO::BinaryWrite(file, word); } @@ -128,21 +129,18 @@ 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()) { - listOfBadSegments.push_back(originalSegment); // found word that isn't ok, just deny this code works for both white and black list + if (std::find(m_UserUnapprovedWordCache.begin(), m_UserUnapprovedWordCache.end(), hash) != m_UserUnapprovedWordCache.end() && whiteList) { + listOfBadSegments.push_back(originalSegment); } - if (!IsInWordlist(hash, whiteList)) { - if (whiteList) { - m_UserUnapprovedWordCache.push_back(hash); - listOfBadSegments.push_back(originalSegment); - } + if (std::find(m_YesYesWords.begin(), m_YesYesWords.end(), hash) == m_YesYesWords.end() && whiteList) { + m_UserUnapprovedWordCache.push_back(hash); + listOfBadSegments.push_back(originalSegment); } - else { - if (!whiteList) { - m_UserUnapprovedWordCache.push_back(hash); - listOfBadSegments.push_back(originalSegment); - } + + if (std::find(m_NoNoWords.begin(), m_NoNoWords.end(), hash) != m_NoNoWords.end() && !whiteList) { + m_UserUnapprovedWordCache.push_back(hash); + listOfBadSegments.push_back(originalSegment); } } @@ -155,10 +153,4 @@ size_t dChatFilter::CalculateHash(const std::string& word) { size_t value = hash(word); return value; -} - -bool dChatFilter::IsInWordlist(size_t word, bool whiteList) { - auto* list = whiteList ? &m_YesYesWords : &m_NoNoWords; - - return std::find(list->begin(), list->end(), word) != list->end(); } \ No newline at end of file diff --git a/dChatFilter/dChatFilter.h b/dChatFilter/dChatFilter.h index 5acd6063..62a47242 100644 --- a/dChatFilter/dChatFilter.h +++ b/dChatFilter/dChatFilter.h @@ -20,9 +20,9 @@ public: dChatFilter(const std::string& filepath, bool dontGenerateDCF); ~dChatFilter(); - void ReadWordlistPlaintext(const std::string& filepath); + void ReadWordlistPlaintext(const std::string& filepath, bool whiteList); bool ReadWordlistDCF(const std::string& filepath, bool whiteList); - void ExportWordlistToDCF(const std::string& filepath); + void ExportWordlistToDCF(const std::string& filepath, bool whiteList); std::vector IsSentenceOkay(const std::string& message, int gmLevel, bool whiteList = true); private: @@ -33,5 +33,4 @@ private: //Private functions: size_t CalculateHash(const std::string& word); - bool IsInWordlist(size_t word, bool whiteList); }; \ No newline at end of file diff --git a/dGame/User.cpp b/dGame/User.cpp index 3efc4d0a..98a37954 100644 --- a/dGame/User.cpp +++ b/dGame/User.cpp @@ -18,6 +18,8 @@ User::User(const SystemAddress& sysAddr, const std::string& username, const std: m_SystemAddress = sysAddr; m_Username = username; m_LoggedInCharID = 0; + + m_IsBestFriendMap = std::unordered_map(); //HACK HACK HACK //This needs to be re-enabled / updated whenever the mute stuff is moved to another table. diff --git a/dGame/User.h b/dGame/User.h index 3be9148e..78640b38 100644 --- a/dGame/User.h +++ b/dGame/User.h @@ -42,6 +42,9 @@ public: bool GetLastChatMessageApproved() { return m_LastChatMessageApproved; } void SetLastChatMessageApproved(bool approved) { m_LastChatMessageApproved = approved; } + std::unordered_map GetIsBestFriendMap() { return m_IsBestFriendMap; } + void SetIsBestFriendMap(std::unordered_map mapToSet) { m_IsBestFriendMap = mapToSet; } + bool GetIsMuted() const; time_t GetMuteExpire() const; @@ -63,6 +66,8 @@ private: std::vector m_Characters; LWOOBJID m_LoggedInCharID; + std::unordered_map m_IsBestFriendMap; + bool m_LastChatMessageApproved = false; int m_AmountOfTimesOutOfSync = 0; const int m_MaxDesyncAllowed = 12; diff --git a/dNet/ClientPackets.cpp b/dNet/ClientPackets.cpp index 187ee12f..abb08688 100644 --- a/dNet/ClientPackets.cpp +++ b/dNet/ClientPackets.cpp @@ -30,6 +30,9 @@ #include "VehiclePhysicsComponent.h" #include "dConfig.h" #include "CharacterComponent.h" +#include "Database.h" + + void ClientPackets::HandleChatMessage(const SystemAddress& sysAddr, Packet* packet) { User* user = UserManager::Instance()->GetUser(sysAddr); @@ -276,7 +279,6 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa std::string message = ""; stream.Read(chatLevel); - printf("%d", chatLevel); stream.Read(requestID); for (uint32_t i = 0; i < 42; ++i) { @@ -285,6 +287,12 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa receiver.push_back(static_cast(character)); } + if (!receiver.empty()) { + if (std::string(receiver.c_str(), 4) == "[GM]") { + receiver = std::string(receiver.c_str() + 4, receiver.size() - 4); + } + } + stream.Read(messageLength); for (uint32_t i = 0; i < messageLength; ++i) { uint16_t character; @@ -292,8 +300,52 @@ void ClientPackets::HandleChatModerationRequest(const SystemAddress& sysAddr, Pa message.push_back(static_cast(character)); } + bool isBestFriend = false; + + if (chatLevel == 1) { + // Private chat + LWOOBJID idOfReceiver = LWOOBJID_EMPTY; + + { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT name FROM charinfo WHERE name = ?"); + stmt->setString(1, receiver); + + sql::ResultSet* res = stmt->executeQuery(); + + if (res->next()) { + idOfReceiver = res->getInt("id"); + } + } + + if (user->GetIsBestFriendMap().find(receiver) == user->GetIsBestFriendMap().end() && idOfReceiver != LWOOBJID_EMPTY) { + sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT * FROM friends WHERE (player_id = ? AND friend_id = ?) OR (player_id = ? AND friend_id = ?) LIMIT 1;"); + stmt->setInt(1, entity->GetObjectID()); + stmt->setInt(2, idOfReceiver); + stmt->setInt(3, idOfReceiver); + stmt->setInt(4, entity->GetObjectID()); + + sql::ResultSet* res = stmt->executeQuery(); + + if (res->next()) { + isBestFriend = res->getInt("best_friend") == 3; + } + + if (isBestFriend) { + auto tmpBestFriendMap = user->GetIsBestFriendMap(); + tmpBestFriendMap[receiver] = true; + user->SetIsBestFriendMap(tmpBestFriendMap); + } + + delete res; + delete stmt; + } + else if (user->GetIsBestFriendMap().find(receiver) != user->GetIsBestFriendMap().end()) { + isBestFriend = true; + } + } + std::unordered_map unacceptedItems; - std::vector segments = Game::chatFilter->IsSentenceOkay(message, entity->GetGMLevel()); + std::vector segments = Game::chatFilter->IsSentenceOkay(message, entity->GetGMLevel(), !(isBestFriend && chatLevel == 1)); bool bAllClean = segments.empty(); diff --git a/resources/blacklist.dcf b/resources/blacklist.dcf index cdc64c2f..ca4db242 100644 Binary files a/resources/blacklist.dcf and b/resources/blacklist.dcf differ