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