diff --git a/src/engine/server.h b/src/engine/server.h index 010e3edf0..54c63da66 100644 --- a/src/engine/server.h +++ b/src/engine/server.h @@ -190,6 +190,7 @@ public: virtual void GetMapInfo(char *pMapName, int MapNameSize, int *pMapSize, SHA256_DIGEST *pSha256, int *pMapCrc) = 0; + virtual bool WouldClientNameChange(int ClientID, const char *pNameRequest) = 0; virtual void SetClientName(int ClientID, char const *pName) = 0; virtual void SetClientClan(int ClientID, char const *pClan) = 0; virtual void SetClientCountry(int ClientID, int Country) = 0; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 0a33c08f1..bcb0d8f78 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -329,82 +329,96 @@ CServer::CServer() : Init(); } -int CServer::TrySetClientName(int ClientID, const char *pName) +bool CServer::IsClientNameAvailable(int ClientID, const char *pNameRequest) { - char aTrimmedName[64]; - - // trim the name - str_copy(aTrimmedName, str_utf8_skip_whitespaces(pName), sizeof(aTrimmedName)); - str_utf8_trim_right(aTrimmedName); - // check for empty names - if(!aTrimmedName[0]) - return -1; + if(!pNameRequest[0]) + return false; // check for names starting with /, as they can be abused to make people // write chat commands - if(aTrimmedName[0] == '/') - return -1; + if(pNameRequest[0] == '/') + return false; // make sure that two clients don't have the same name for(int i = 0; i < MAX_CLIENTS; i++) { if(i != ClientID && m_aClients[i].m_State >= CClient::STATE_READY) { - if(str_utf8_comp_confusable(aTrimmedName, m_aClients[i].m_aName) == 0) - return -1; + if(str_utf8_comp_confusable(pNameRequest, m_aClients[i].m_aName) == 0) + return false; } } - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "'%s' -> '%s'", pName, aTrimmedName); - Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); - pName = aTrimmedName; - - // set the client name - str_copy(m_aClients[ClientID].m_aName, pName, MAX_NAME_LENGTH); - return 0; + return true; } -void CServer::SetClientName(int ClientID, const char *pName) +bool CServer::SetClientNameImpl(int ClientID, const char *pNameRequest, bool Set) { - if(ClientID < 0 || ClientID >= MAX_CLIENTS || m_aClients[ClientID].m_State < CClient::STATE_READY) - return; + dbg_assert(0 <= ClientID && ClientID < MAX_CLIENTS, "invalid client id"); + if(m_aClients[ClientID].m_State < CClient::STATE_READY) + return false; - if(!pName) - return; - - CNameBan *pBanned = IsNameBanned(pName, m_aNameBans.base_ptr(), m_aNameBans.size()); - if(pBanned) + if(Set) { - if(m_aClients[ClientID].m_State == CClient::STATE_READY) + CNameBan *pBanned = IsNameBanned(pNameRequest, m_aNameBans.base_ptr(), m_aNameBans.size()); + if(pBanned) { - char aBuf[256]; - if(pBanned->m_aReason[0]) + if(m_aClients[ClientID].m_State == CClient::STATE_READY) { - str_format(aBuf, sizeof(aBuf), "Kicked (your name is banned: %s)", pBanned->m_aReason); + char aBuf[256]; + if(pBanned->m_aReason[0]) + { + str_format(aBuf, sizeof(aBuf), "Kicked (your name is banned: %s)", pBanned->m_aReason); + } + else + { + str_copy(aBuf, "Kicked (your name is banned)", sizeof(aBuf)); + } + Kick(ClientID, aBuf); } - else - { - str_copy(aBuf, "Kicked (your name is banned)", sizeof(aBuf)); - } - Kick(ClientID, aBuf); + return true; } - return; } + // trim the name + char aTrimmedName[MAX_NAME_LENGTH]; + str_copy(aTrimmedName, str_utf8_skip_whitespaces(pNameRequest), sizeof(aTrimmedName)); + str_utf8_trim_right(aTrimmedName); + char aNameTry[MAX_NAME_LENGTH]; - str_copy(aNameTry, pName, sizeof(aNameTry)); - if(TrySetClientName(ClientID, aNameTry)) + str_copy(aNameTry, aTrimmedName, sizeof(aNameTry)); + + if(!IsClientNameAvailable(ClientID, aNameTry)) { // auto rename for(int i = 1;; i++) { - str_format(aNameTry, sizeof(aNameTry), "(%d)%s", i, pName); - if(TrySetClientName(ClientID, aNameTry) == 0) + str_format(aNameTry, sizeof(aNameTry), "(%d)%s", i, aTrimmedName); + if(IsClientNameAvailable(ClientID, aNameTry)) break; } } + + bool Changed = str_comp(m_aClients[ClientID].m_aName, aNameTry) != 0; + + if(Set) + { + // set the client name + str_copy(m_aClients[ClientID].m_aName, aNameTry, MAX_NAME_LENGTH); + } + + return Changed; +} + +bool CServer::WouldClientNameChange(int ClientID, const char *pNameRequest) +{ + return SetClientNameImpl(ClientID, pNameRequest, false); +} + +void CServer::SetClientName(int ClientID, const char *pName) +{ + SetClientNameImpl(ClientID, pName, true); } void CServer::SetClientClan(int ClientID, const char *pClan) diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 8cc7236f0..56913e109 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -258,8 +258,10 @@ public: CServer(); - int TrySetClientName(int ClientID, const char *pName); + bool IsClientNameAvailable(int ClientID, const char *pNameRequest); + bool SetClientNameImpl(int ClientID, const char *pNameRequest, bool Set); + virtual bool WouldClientNameChange(int ClientID, const char *pNameRequest); virtual void SetClientName(int ClientID, const char *pName); virtual void SetClientClan(int ClientID, char const *pClan); virtual void SetClientCountry(int ClientID, int Country); diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 4de416b08..edce59e2c 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -2173,9 +2173,10 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID) // set infos char aOldName[MAX_NAME_LENGTH]; str_copy(aOldName, Server()->ClientName(ClientID), sizeof(aOldName)); - Server()->SetClientName(ClientID, pMsg->m_pName); - if(str_comp(aOldName, Server()->ClientName(ClientID)) != 0) + if(Server()->WouldClientNameChange(ClientID, pMsg->m_pName) && !ProcessSpamProtection(ClientID)) { + Server()->SetClientName(ClientID, pMsg->m_pName); + char aChatText[256]; str_format(aChatText, sizeof(aChatText), "'%s' changed name to '%s'", aOldName, Server()->ClientName(ClientID)); SendChat(-1, CGameContext::CHAT_ALL, aChatText);