]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_filter.h
Fix warning, remove unused var
[user/henk/code/inspircd.git] / src / modules / m_filter.h
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "xline.h"
15
16 class FilterResult : public classbase
17 {
18  public:
19         std::string freeform;
20         std::string reason;
21         std::string action;
22         long gline_time;
23
24         FilterResult(const std::string free, const std::string &rea, const std::string &act, long gt) : freeform(free), reason(rea), action(act), gline_time(gt)
25         {
26         }
27
28         FilterResult()
29         {
30         }
31
32         virtual ~FilterResult()
33         {
34         }
35 };
36
37 class cmd_filter;
38
39 class FilterBase : public Module
40 {
41         cmd_filter* filtcommand;
42  public:
43         FilterBase(InspIRCd* Me, const std::string &source);
44         virtual ~FilterBase();
45         virtual void Implements(char* List);
46         virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
47         virtual FilterResult* FilterMatch(const std::string &text) = 0;
48         virtual bool DeleteFilter(const std::string &freeform) = 0;
49         virtual void SyncFilters(Module* proto, void* opaque) = 0;
50         virtual void SendFilter(Module* proto, void* opaque, FilterResult* iter);
51         virtual std::pair<bool, std::string> AddFilter(const std::string &freeform, const std::string &type, const std::string &reason, long duration) = 0;
52         virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list);
53         virtual void OnRehash(userrec* user, const std::string &parameter);
54         virtual Version GetVersion();
55         std::string EncodeFilter(FilterResult* filter);
56         FilterResult DecodeFilter(const std::string &data);
57         virtual void OnSyncOtherMetaData(Module* proto, void* opaque);
58         virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata);
59         virtual int OnStats(char symbol, userrec* user, string_list &results) = 0;
60         virtual int OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line);
61 };
62
63 class cmd_filter : public command_t
64 {
65         FilterBase* Base;
66  public:
67         cmd_filter(FilterBase* f, InspIRCd* Me, const std::string &source) : command_t(Me, "FILTER", 'o', 1), Base(f)
68         {
69                 this->source = source;
70                 this->syntax = "<filter-definition> <type> [<gline-duration>] :<reason>";
71         }
72
73         CmdResult Handle(const char** parameters, int pcnt, userrec *user)
74         {
75                 if (pcnt == 1)
76                 {
77                         /* Deleting a filter */
78                         if (Base->DeleteFilter(parameters[0]))
79                         {
80                                 user->WriteServ("NOTICE %s :*** Deleted filter '%s'", user->nick, parameters[0]);
81                                 return CMD_SUCCESS;
82                         }
83                         else
84                         {
85                                 user->WriteServ("NOTICE %s :*** Filter '%s' not found on list.", user->nick, parameters[0]);
86                                 return CMD_FAILURE;
87                         }
88                 }
89                 else
90                 {
91                         /* Adding a filter */
92                         if (pcnt >= 3)
93                         {
94                                 std::string freeform = parameters[0];
95                                 std::string type = parameters[1];
96                                 std::string reason;
97                                 long duration = 0;
98
99                                 if ((type != "gline") && (type != "none") && (type != "block") && (type != "kill"))
100                                 {
101                                         user->WriteServ("NOTICE %s :*** Invalid filter type '%s'. Supported types are 'gline', 'none', 'block', and 'kill'.", user->nick, freeform.c_str());
102                                         return CMD_FAILURE;
103                                 }
104
105                                 if (type == "gline")
106                                 {
107                                         if (pcnt >= 4)
108                                         {
109                                                 duration = ServerInstance->Duration(parameters[2]);
110                                                 reason = parameters[3];
111                                         }
112                                         else
113                                         {
114                                                 this->TooFewParams(user, " When setting a gline type filter, a gline duration must be specified as the third parameter.");
115                                                 return CMD_FAILURE;
116                                         }
117                                 }
118                                 else
119                                 {
120                                         reason = parameters[2];
121                                 }
122                                 std::pair<bool, std::string> result = Base->AddFilter(freeform, type, reason, duration);
123                                 if (result.first)
124                                 {
125                                         user->WriteServ("NOTICE %s :*** Added filter '%s', type '%s'%s%s, reason: '%s'", user->nick, freeform.c_str(),
126                                                         type.c_str(), (duration ? " duration: " : ""), (duration ? parameters[2] : ""),
127                                                         reason.c_str());
128                                         return CMD_SUCCESS;
129                                 }
130                                 else
131                                 {
132                                         user->WriteServ("NOTICE %s :*** Filter '%s' could not be added: %s", user->nick, freeform.c_str(), result.second.c_str());
133                                         return CMD_FAILURE;
134                                 }
135                         }
136                         else
137                         {
138                                 this->TooFewParams(user, ".");
139                                 return CMD_FAILURE;
140                         }
141
142                 }
143         }
144
145         void TooFewParams(userrec* user, const std::string &extra_text)
146         {
147                 user->WriteServ("NOTICE %s :*** Not enough parameters%s", user->nick, extra_text.c_str());
148         }
149 };
150
151 FilterBase::FilterBase(InspIRCd* Me, const std::string &source) : Module::Module(Me)
152 {
153         filtcommand = new cmd_filter(this, Me, source);
154         ServerInstance->AddCommand(filtcommand);
155 }
156
157 FilterBase::~FilterBase()
158 {
159 }
160
161 void FilterBase::Implements(char* List)
162 {
163         List[I_OnPreCommand] = List[I_OnStats] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnUserPreMessage] = List[I_OnUserPreNotice] = List[I_OnRehash] = 1;
164 }
165
166 int FilterBase::OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
167 {
168         return OnUserPreNotice(user,dest,target_type,text,status,exempt_list);
169 }
170
171 int FilterBase::OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text, char status, CUList &exempt_list)
172 {
173         /* Leave ulines alone */
174         if ((ServerInstance->ULine(user->server)) || (!IS_LOCAL(user)))
175                 return 0;
176
177         FilterResult* f = this->FilterMatch(text);
178         if (f)
179         {
180                 std::string target = "";
181                 if (target_type == TYPE_USER)
182                 {
183                         userrec* t = (userrec*)dest;
184                         target = std::string(t->nick);
185                 }
186                 else if (target_type == TYPE_CHANNEL)
187                 {
188                         chanrec* t = (chanrec*)dest;
189                         target = std::string(t->name);
190                 }
191                 if (f->action == "block")
192                 {       
193                         ServerInstance->WriteOpers(std::string("FILTER: ")+user->nick+" had their notice filtered, target was "+target+": "+f->reason);
194                         user->WriteServ("NOTICE "+std::string(user->nick)+" :Your notice has been filtered and opers notified: "+f->reason);
195                 }
196                 ServerInstance->Log(DEFAULT,"FILTER: "+std::string(user->nick)+std::string(" had their notice filtered, target was ")+target+": "+f->reason+" Action: "+f->action);
197                 if (f->action == "kill")
198                 {
199                         userrec::QuitUser(ServerInstance,user,"Filtered: "+f->reason);
200                 }
201                 if (f->action == "gline")
202                 {
203                         if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), user->MakeHostIP()))
204                         {
205                                 ServerInstance->XLines->apply_lines(APPLY_GLINES);
206                                 FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP()));
207                         }
208                 }
209                 return 1;
210         }
211         return 0;
212 }
213
214 int FilterBase::OnPreCommand(const std::string &command, const char** parameters, int pcnt, userrec *user, bool validated, const std::string &original_line)
215 {
216         if ((validated == 1) && (IS_LOCAL(user)))
217         {
218                 std::string checkline;
219                 int replacepoint = 0;
220                 bool parting = false;
221         
222                 if (command == "QUIT")
223                 {
224                         /* QUIT with no reason: nothing to do */
225                         if (pcnt < 1)
226                                 return 0;
227
228                         checkline = parameters[0];
229                         replacepoint = 0;
230                         parting = false;
231                 }
232                 else if (command == "PART")
233                 {
234                         /* PART with no reason: nothing to do */
235                         if (pcnt < 2)
236                                 return 0;
237
238                         checkline = parameters[1];
239                         replacepoint = 1;
240                         parting = true;
241                 }
242                 else
243                         /* We're only messing with PART and QUIT */
244                         return 0;
245
246                 FilterResult* f = this->FilterMatch(checkline);
247
248                 if (!f)
249                         /* PART or QUIT reason doesnt match a filter */
250                         return 0;
251
252                 ServerInstance->Log(DEBUG,"Match block text");
253
254                 /* We cant block a part or quit, so instead we change the reason to 'Reason filtered' */
255                 command_t* c = ServerInstance->Parser->GetHandler(command);
256                 if (c)
257                 {
258                         ServerInstance->Log(DEBUG,"Found handler");
259
260                         const char* params[127];
261                         for (int item = 0; item < pcnt; item++)
262                                 params[item] = parameters[item];
263                         params[replacepoint] = "Reason filtered";
264
265                         /* We're blocking, OR theyre quitting and its a KILL action
266                          * (we cant kill someone whos already quitting, so filter them anyway)
267                          */
268                         if ((f->action == "block") || (((!parting) && (f->action == "kill"))))
269                         {
270                                 c->Handle(params, pcnt, user);
271                                 return 1;
272                         }
273                         else
274                         {
275                                 /* Are they parting, if so, kill is applicable */
276                                 if ((parting) && (f->action == "kill"))
277                                 {
278                                         user->SetWriteError("Filtered: "+f->reason);
279                                         /* This WriteServ causes the write error to be applied.
280                                          * Its not safe to kill here with QuitUser in a PreCommand handler,
281                                          * so we do it this way, which is safe just about anywhere.
282                                          */
283                                         user->WriteServ("NOTICE %s :*** Your PART message was filtered: %s", user->nick, f->reason.c_str());
284                                 }
285                                 if (f->action == "gline")
286                                 {
287                                         /* Note: We gline *@IP so that if their host doesnt resolve the gline still applies. */
288                                         std::string wild = "*@";
289                                         wild.append(user->GetIPString());
290
291                                         if (ServerInstance->XLines->add_gline(f->gline_time, ServerInstance->Config->ServerName, f->reason.c_str(), wild.c_str()))
292                                         {
293                                                 ServerInstance->XLines->apply_lines(APPLY_GLINES);
294                                                 FOREACH_MOD(I_OnAddGLine,OnAddGLine(f->gline_time, NULL, f->reason, user->MakeHostIP()));
295                                         }
296                                 }
297                                 return 1;
298                         }
299                 }
300                 return 0;
301         }
302         return 0;
303 }
304
305 void FilterBase::OnRehash(userrec* user, const std::string &parameter)
306 {
307 }
308         
309 Version FilterBase::GetVersion()
310 {
311         return Version(1,1,0,2,VF_VENDOR|VF_COMMON,API_VERSION);
312 }
313
314
315 std::string FilterBase::EncodeFilter(FilterResult* filter)
316 {
317         std::ostringstream stream;
318         std::string x = filter->freeform;
319
320         for (std::string::iterator n = x.begin(); n != x.end(); n++)
321                 if (*n == ' ')
322                         *n = '\7';
323
324         stream << x << " " << filter->action << " " << filter->gline_time << " " << filter->reason;
325         return stream.str();
326 }
327
328 FilterResult FilterBase::DecodeFilter(const std::string &data)
329 {
330         FilterResult res;
331         std::istringstream stream(data);
332
333         stream >> res.freeform;
334         stream >> res.action;
335         stream >> res.gline_time;
336         res.reason = stream.str();
337
338         for (std::string::iterator n = res.freeform.begin(); n != res.freeform.end(); n++)
339                 if (*n == '\7')
340                         *n = ' ';
341
342         return res;
343 }
344
345 void FilterBase::OnSyncOtherMetaData(Module* proto, void* opaque)
346 {
347         this->SyncFilters(proto, opaque);
348 }
349
350 void FilterBase::SendFilter(Module* proto, void* opaque, FilterResult* iter)
351 {
352         proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "filter", EncodeFilter(iter));
353 }
354
355 void FilterBase::OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
356 {
357         if ((target_type == TYPE_OTHER) && (extname == "filter"))
358         {
359                 FilterResult data = DecodeFilter(extdata);
360                 this->AddFilter(data.freeform, data.action, data.reason, data.gline_time);
361         }
362 }
363