1 ////////////////////////////////////////////////////////////////////////////////
2 // Scorched3D (c) 2000-2011
3 //
4 // This file is part of Scorched3D.
5 //
6 // Scorched3D is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // Scorched3D is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License along
17 // with this program; if not, write to the Free Software Foundation, Inc.,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20
21 #include <vector>
22 #include <server/ServerTextFilter.h>
23 #include <server/ScorchedServer.h>
24 #include <common/OptionsScorched.h>
25 #include <common/Defines.h>
26
27 #define IS_SPACE(c) ((c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || (c > 'z' && c <= 127)))
28
ServerTextFilter()29 ServerTextFilter::ServerTextFilter() : lastReadTime_(0)
30 {
31 }
32
~ServerTextFilter()33 ServerTextFilter::~ServerTextFilter()
34 {
35 }
36
filterString(LangString & inputText)37 void ServerTextFilter::filterString(LangString &inputText)
38 {
39 loadFile();
40
41 if (words_.empty()) return;
42 std::vector<TextPart> parts;
43
44 // Split the string into parts (words) each seperated by the
45 // seperating characters
46 LangString current;
47 const unsigned int *pos = 0;
48 for (const unsigned int *c = inputText.c_str(); *c; c++)
49 {
50 if (IS_SPACE(*c))
51 {
52 if (current.c_str()[0])
53 {
54 TextPart part;
55 part.part = current;
56 part.pos = (unsigned int *) pos;
57 parts.push_back(part);
58 }
59 current.clear();
60 pos = 0;
61 }
62 else
63 {
64 if (!pos) pos = c;
65 current += *c;
66 }
67 }
68 // The first/last part
69 if (current.c_str()[0])
70 {
71 TextPart part;
72 part.part = current;
73 part.pos = (unsigned int *) pos;
74 parts.push_back(part);
75 }
76
77 // For each part
78 std::vector<TextPart>::iterator itor;
79 for (itor = parts.begin(); itor != parts.end(); ++itor)
80 {
81 TextPart &part = (*itor);
82 const unsigned int *text = part.part.c_str();
83
84 // Check that they don't contain the words
85 std::list<LangString>::iterator witor;
86 for (witor = words_.begin(); witor != words_.end(); ++witor)
87 {
88 const unsigned int *word = (*witor).c_str();
89 unsigned int *pos = LangStringUtil::stristr(text, word);
90 if (pos)
91 {
92 // Only filter out if the words is at the start or end of the word
93 if (pos == text || (pos - text) + LangStringUtil::strlen(word) == LangStringUtil::strlen(text))
94 {
95 // If they do then * out the word
96 for (int i=0; i<LangStringUtil::strlen(word); i++)
97 {
98 pos[i] = '*';
99 }
100 }
101 }
102 }
103 }
104
105 // For each combination of parts check that they don't add up to the words
106 for (int i=0; i<(int) parts.size(); i++)
107 {
108 LangString sofar;
109 for (int j=i; j<(int) parts.size(); j++)
110 {
111 sofar += parts[j].part;
112 const unsigned int *text = sofar.c_str();
113
114 // Check each word against the parts so far
115 std::list<LangString>::iterator witor;
116 for (witor = words_.begin(); witor != words_.end(); ++witor)
117 {
118 const unsigned int *word = (*witor).c_str();
119 if (LangStringUtil::strcasecmp(text, word) == 0)
120 {
121 // If they match, * out all parts
122 for (int k=i; k<=j; k++)
123 {
124 for (unsigned int *pos = (unsigned int *) parts[k].part.c_str();
125 *pos;
126 pos++)
127 {
128 *pos = '*';
129 }
130 }
131
132 break;
133 }
134 }
135 }
136 }
137
138 // Re-form the words
139 for (itor = parts.begin(); itor != parts.end(); ++itor)
140 {
141 TextPart &part = (*itor);
142 const unsigned int *text = part.part.c_str();
143
144 for (int i=0; i<(int) part.part.size(); i++)
145 {
146 part.pos[i] = text[i];
147 }
148 }
149 }
150
loadFile()151 void ServerTextFilter::loadFile()
152 {
153 std::string filename =
154 S3D::getSettingsFile(S3D::formatStringBuffer("filter-%i.txt",
155 ScorchedServer::instance()->getOptionsGame().getPortNo()));
156 if (!::S3D::fileExists(filename)) return;
157
158 time_t fileTime = S3D::fileModTime(filename);
159 if (fileTime == lastReadTime_) return;
160
161 FileLines lines;
162 if (!lines.readFile(filename)) return;
163
164 lastReadTime_ = fileTime;
165
166 words_.clear();
167 std::vector<std::string>::iterator itor;
168 for (itor = lines.getLines().begin();
169 itor != lines.getLines().end();
170 ++itor)
171 {
172 if ((*itor).c_str()[0])
173 {
174 words_.push_back(LANG_STRING(*itor));
175 }
176 }
177 }
178