1 | #include "name_ban.h" |
2 | |
3 | #include <base/system.h> |
4 | |
5 | #include <engine/shared/config.h> |
6 | |
7 | CNameBan::CNameBan(const char *pName, const char *pReason, int Distance, bool IsSubstring) : |
8 | m_Distance(Distance), m_IsSubstring(IsSubstring) |
9 | { |
10 | str_copy(dst&: m_aName, src: pName); |
11 | str_copy(dst&: m_aReason, src: pReason); |
12 | m_SkeletonLength = str_utf8_to_skeleton(str: m_aName, buf: m_aSkeleton, buf_len: std::size(m_aSkeleton)); |
13 | } |
14 | |
15 | void CNameBans::InitConsole(IConsole *pConsole) |
16 | { |
17 | m_pConsole = pConsole; |
18 | |
19 | m_pConsole->Register(pName: "name_ban" , pParams: "s[name] ?i[distance] ?i[is_substring] ?r[reason]" , Flags: CFGFLAG_SERVER, pfnFunc: ConNameBan, pUser: this, pHelp: "Ban a certain nickname" ); |
20 | m_pConsole->Register(pName: "name_unban" , pParams: "s[name]" , Flags: CFGFLAG_SERVER, pfnFunc: ConNameUnban, pUser: this, pHelp: "Unban a certain nickname" ); |
21 | m_pConsole->Register(pName: "name_bans" , pParams: "" , Flags: CFGFLAG_SERVER, pfnFunc: ConNameBans, pUser: this, pHelp: "List all name bans" ); |
22 | } |
23 | |
24 | void CNameBans::Ban(const char *pName, const char *pReason, const int Distance, const bool IsSubstring) |
25 | { |
26 | for(auto &Ban : m_vNameBans) |
27 | { |
28 | if(str_comp(a: Ban.m_aName, b: pName) == 0) |
29 | { |
30 | if(m_pConsole) |
31 | { |
32 | char aBuf[256]; |
33 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "changed name='%s' distance=%d old_distance=%d is_substring=%d old_is_substring=%d reason='%s' old_reason='%s'" , pName, Distance, Ban.m_Distance, IsSubstring, Ban.m_IsSubstring, pReason, Ban.m_aReason); |
34 | m_pConsole->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "name_ban" , pStr: aBuf); |
35 | } |
36 | str_copy(dst&: Ban.m_aReason, src: pReason); |
37 | Ban.m_Distance = Distance; |
38 | Ban.m_IsSubstring = IsSubstring; |
39 | return; |
40 | } |
41 | } |
42 | |
43 | m_vNameBans.emplace_back(args&: pName, args&: pReason, args: Distance, args: IsSubstring); |
44 | if(m_pConsole) |
45 | { |
46 | char aBuf[256]; |
47 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "added name='%s' distance=%d is_substring=%d reason='%s'" , pName, Distance, IsSubstring, pReason); |
48 | m_pConsole->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "name_ban" , pStr: aBuf); |
49 | } |
50 | } |
51 | |
52 | void CNameBans::Unban(const char *pName) |
53 | { |
54 | auto ToRemove = std::remove_if(first: m_vNameBans.begin(), last: m_vNameBans.end(), pred: [pName](const CNameBan &Ban) { return str_comp(a: Ban.m_aName, b: pName) == 0; }); |
55 | if(ToRemove == m_vNameBans.end()) |
56 | { |
57 | if(m_pConsole) |
58 | { |
59 | char aBuf[256]; |
60 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "name ban '%s' not found" , pName); |
61 | m_pConsole->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "name_ban" , pStr: aBuf); |
62 | } |
63 | } |
64 | else |
65 | { |
66 | if(m_pConsole) |
67 | { |
68 | char aBuf[256]; |
69 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "removed name='%s' distance=%d is_substring=%d reason='%s'" , (*ToRemove).m_aName, (*ToRemove).m_Distance, (*ToRemove).m_IsSubstring, (*ToRemove).m_aReason); |
70 | m_pConsole->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "name_ban" , pStr: aBuf); |
71 | } |
72 | m_vNameBans.erase(first: ToRemove, last: m_vNameBans.end()); |
73 | } |
74 | } |
75 | |
76 | void CNameBans::Dump() const |
77 | { |
78 | if(!m_pConsole) |
79 | return; |
80 | |
81 | char aBuf[256]; |
82 | for(const auto &Ban : m_vNameBans) |
83 | { |
84 | str_format(buffer: aBuf, buffer_size: sizeof(aBuf), format: "name='%s' distance=%d is_substring=%d reason='%s'" , Ban.m_aName, Ban.m_Distance, Ban.m_IsSubstring, Ban.m_aReason); |
85 | m_pConsole->Print(Level: IConsole::OUTPUT_LEVEL_STANDARD, pFrom: "name_ban" , pStr: aBuf); |
86 | } |
87 | } |
88 | |
89 | const CNameBan *CNameBans::IsBanned(const char *pName) const |
90 | { |
91 | char aTrimmed[MAX_NAME_LENGTH]; |
92 | str_copy(dst&: aTrimmed, src: str_utf8_skip_whitespaces(str: pName)); |
93 | str_utf8_trim_right(param: aTrimmed); |
94 | |
95 | int aSkeleton[MAX_NAME_SKELETON_LENGTH]; |
96 | int SkeletonLength = str_utf8_to_skeleton(str: aTrimmed, buf: aSkeleton, buf_len: std::size(aSkeleton)); |
97 | int aBuffer[MAX_NAME_SKELETON_LENGTH * 2 + 2]; |
98 | |
99 | const CNameBan *pResult = nullptr; |
100 | for(const CNameBan &Ban : m_vNameBans) |
101 | { |
102 | int Distance = str_utf32_dist_buffer(a: aSkeleton, a_len: SkeletonLength, b: Ban.m_aSkeleton, b_len: Ban.m_SkeletonLength, buf: aBuffer, buf_len: std::size(aBuffer)); |
103 | if(Distance <= Ban.m_Distance || (Ban.m_IsSubstring && str_utf8_find_nocase(haystack: pName, needle: Ban.m_aName))) |
104 | pResult = &Ban; |
105 | } |
106 | return pResult; |
107 | } |
108 | |
109 | void CNameBans::ConNameBan(IConsole::IResult *pResult, void *pUser) |
110 | { |
111 | const char *pName = pResult->GetString(Index: 0); |
112 | const char *pReason = pResult->NumArguments() > 3 ? pResult->GetString(Index: 3) : "" ; |
113 | const int Distance = pResult->NumArguments() > 1 ? pResult->GetInteger(Index: 1) : str_length(str: pName) / 3; |
114 | const bool IsSubstring = pResult->NumArguments() > 2 ? pResult->GetInteger(Index: 2) != 0 : false; |
115 | static_cast<CNameBans *>(pUser)->Ban(pName, pReason, Distance, IsSubstring); |
116 | } |
117 | |
118 | void CNameBans::ConNameUnban(IConsole::IResult *pResult, void *pUser) |
119 | { |
120 | const char *pName = pResult->GetString(Index: 0); |
121 | static_cast<CNameBans *>(pUser)->Unban(pName); |
122 | } |
123 | |
124 | void CNameBans::ConNameBans(IConsole::IResult *pResult, void *pUser) |
125 | { |
126 | static_cast<CNameBans *>(pUser)->Dump(); |
127 | } |
128 | |