]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_messageflood.cpp
0f2bb23c6a57efc9c58a084ffd5a489f2e502114
[user/henk/code/inspircd.git] / src / modules / m_messageflood.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
6  *                       E-mail:
7  *                <brain@chatspike.net>
8  *                <Craig@chatspike.net>
9  *     
10  * Written by Craig Edwards, Craig McLure, and others.
11  * This program is free but copyrighted software; see
12  *            the file COPYING for details.
13  *
14  * ---------------------------------------------------
15  */
16
17 using namespace std;
18
19 #include <stdio.h>
20 #include <map>
21 #include "users.h"
22 #include "channels.h"
23 #include "modules.h"
24 #include "helperfuncs.h"
25 #include "inspircd.h"
26
27 /* $ModDesc: Provides channel mode +f (message flood protection) */
28
29
30
31 class floodsettings : public classbase
32 {
33  public:
34         bool ban;
35         int secs;
36         int lines;
37         time_t reset;
38         std::map<userrec*,int> counters;
39
40         floodsettings() : ban(0), secs(0), lines(0) {};
41         floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c)
42         {
43                 reset = time(NULL) + secs;
44         };
45
46         void addmessage(userrec* who)
47         {
48                 std::map<userrec*,int>::iterator iter = counters.find(who);
49                 if (iter != counters.end())
50                 {
51                         iter->second++;
52                 }
53                 else
54                 {
55                         counters[who] = 1;
56                 }
57                 if (time(NULL) > reset)
58                 {
59                         counters.clear();
60                         reset = time(NULL) + secs;
61                 }
62         }
63
64         bool shouldkick(userrec* who)
65         {
66                 std::map<userrec*,int>::iterator iter = counters.find(who);
67                 if (iter != counters.end())
68                 {
69                         return (iter->second >= this->lines);
70                 }
71                 else return false;
72         }
73
74         void clear(userrec* who)
75         {
76                 std::map<userrec*,int>::iterator iter = counters.find(who);
77                 if (iter != counters.end())
78                 {
79                         counters.erase(iter);
80                 }
81         }
82 };
83
84 class MsgFlood : public ModeHandler
85 {
86  public:
87         MsgFlood(InspIRCd* Instance) : ModeHandler(Instance, 'f', 1, 0, false, MODETYPE_CHANNEL, false) { }
88
89         ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
90         {
91                 floodsettings* x;
92                 if (channel->GetExt("flood",x))
93                         return std::make_pair(true, (x->ban ? "*" : "")+ConvToStr(x->lines)+":"+ConvToStr(x->secs));
94                 else
95                         return std::make_pair(false, parameter);
96         }
97
98         bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel)
99         {
100                 /* When TS is equal, the alphabetically later one wins */
101                 return (their_param < our_param);
102         }
103
104         ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
105         {
106                 floodsettings *f;
107
108                 if (adding)
109                 {
110                         char ndata[MAXBUF];
111                         char* data = ndata;
112                         strlcpy(ndata,parameter.c_str(),MAXBUF);
113                         char* lines = data;
114                         char* secs = NULL;
115                         bool ban = false;
116                         if (*data == '*')
117                         {
118                                 ban = true;
119                                 lines++;
120                         }
121                         else
122                         {
123                                 ban = false;
124                         }
125                         while (*data)
126                         {
127                                 if (*data == ':')
128                                 {
129                                         *data = 0;
130                                         data++;
131                                         secs = data;
132                                         break;
133                                 }
134                                 else data++;
135                         }
136                         if (secs)
137                         {
138                                 /* Set up the flood parameters for this channel */
139                                 int nlines = atoi(lines);
140                                 int nsecs = atoi(secs);
141                                 if ((nlines<1) || (nsecs<1))
142                                 {
143                                         source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
144                                         parameter = "";
145                                         return MODEACTION_DENY;
146                                 }
147                                 else
148                                 {
149                                         if (!channel->GetExt("flood", f))
150                                         {
151                                                 parameter = ConvToStr(nlines) + ":" +ConvToStr(nsecs);
152                                                 floodsettings *f = new floodsettings(ban,nsecs,nlines);
153                                                 channel->Extend("flood",f);
154                                                 channel->SetMode('f', true);
155                                                 channel->SetModeParam('f', parameter.c_str(), true);
156                                                 return MODEACTION_ALLOW;
157                                         }
158                                 }
159                         }
160                         else
161                         {
162                                 source->WriteServ("608 %s %s :Invalid flood parameter",source->nick,channel->name);
163                                 parameter = "";
164                                 return MODEACTION_DENY;
165                         }
166                 }
167                 else
168                 {
169                         if (channel->GetExt("flood", f))
170                         {
171                                 DELETE(f);
172                                 channel->Shrink("flood");
173                                 channel->SetMode('f', false);
174                                 return MODEACTION_ALLOW;
175                         }
176                 }
177                 
178                 return MODEACTION_DENY;
179         }
180 };
181
182 class ModuleMsgFlood : public Module
183 {
184         
185         MsgFlood* mf;
186         
187  public:
188  
189         ModuleMsgFlood(InspIRCd* Me)
190                 : Module::Module(Me)
191         {
192                 
193                 mf = new MsgFlood(ServerInstance);
194                 ServerInstance->AddMode(mf, 'f');
195         }
196         
197         void ProcessMessages(userrec* user,chanrec* dest, const std::string &text)
198         {
199                 if (IS_LOCAL(user))
200                 {
201                         floodsettings *f;
202                         if (dest->GetExt("flood", f))
203                         {
204                                 f->addmessage(user);
205                                 if (f->shouldkick(user))
206                                 {
207                                         /* Youre outttta here! */
208                                         f->clear(user);
209                                         if (f->ban)
210                                         {
211                                                 const char* parameters[3];
212                                                 parameters[0] = dest->name;
213                                                 parameters[1] = "+b";
214                                                 parameters[2] = user->MakeWildHost();
215                                                 ServerInstance->SendMode(parameters,3,user);
216                                                 std::deque<std::string> n;
217                                                 /* Propogate the ban to other servers.
218                                                  * We dont know what protocol we may be using,
219                                                  * so this event is picked up by our protocol
220                                                  * module and formed into a ban command that
221                                                  * suits the protocol in use.
222                                                  */
223                                                 n.push_back(dest->name);
224                                                 n.push_back("+b");
225                                                 n.push_back(user->MakeWildHost());
226                                                 Event rmode((char *)&n, NULL, "send_mode");
227                                                 rmode.Send(ServerInstance);
228                                         }
229                                         dest->ServerKickUser(user, "Channel flood triggered (mode +f)", true);
230                                 }
231                         }
232                 }
233         }
234
235         virtual void OnUserMessage(userrec* user, void* dest, int target_type, const std::string &text, char status)
236         {
237                 if (target_type == TYPE_CHANNEL)
238                 {
239                         ProcessMessages(user,(chanrec*)dest,text);
240                 }
241         }
242
243         virtual void OnUserNotice(userrec* user, void* dest, int target_type, const std::string &text, char status)
244         {
245                 if (target_type == TYPE_CHANNEL)
246                 {
247                         ProcessMessages(user,(chanrec*)dest,text);
248                 }
249         }
250
251         void OnChannelDelete(chanrec* chan)
252         {
253                 floodsettings* f;
254                 if (chan->GetExt("flood", f))
255                 {
256                         DELETE(f);
257                         chan->Shrink("flood");
258                 }
259         }
260
261         void Implements(char* List)
262         {
263                 List[I_On005Numeric] = List[I_OnChannelDelete] = List[I_OnUserNotice] = List[I_OnUserMessage] = 1;
264         }
265
266         virtual void On005Numeric(std::string &output)
267         {
268                 ServerInstance->ModeGrok->InsertMode(output, "f", 3);
269         }
270
271         virtual ~ModuleMsgFlood()
272         {
273                 DELETE(mf);
274         }
275         
276         virtual Version GetVersion()
277         {
278                 return Version(1,0,0,0,VF_STATIC|VF_VENDOR);
279         }
280 };
281
282
283 class ModuleMsgFloodFactory : public ModuleFactory
284 {
285  public:
286         ModuleMsgFloodFactory()
287         {
288         }
289         
290         ~ModuleMsgFloodFactory()
291         {
292         }
293         
294         virtual Module * CreateModule(InspIRCd* Me)
295         {
296                 return new ModuleMsgFlood(Me);
297         }
298         
299 };
300
301
302 extern "C" void * init_module( void )
303 {
304         return new ModuleMsgFloodFactory;
305 }
306