]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_messageflood.cpp
Removed need for server kicks to be managed in here
[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
26 /* $ModDesc: Provides channel mode +f (message flood protection) */
27
28 class floodsettings
29 {
30  public:
31         bool ban;
32         int secs;
33         int lines;
34         time_t reset;
35         std::map<userrec*,int> counters;
36
37         floodsettings() : ban(0), secs(0), lines(0) {};
38         floodsettings(bool a, int b, int c) : ban(a), secs(b), lines(c)
39         {
40                 reset = time(NULL) + secs;
41                 log(DEBUG,"Create new floodsettings: %lu %lu",time(NULL),reset);
42         };
43
44         void addmessage(userrec* who)
45         {
46                 std::map<userrec*,int>::iterator iter = counters.find(who);
47                 if (iter != counters.end())
48                 {
49                         iter->second++;
50                         log(DEBUG,"Count for %s is now %d",who->nick,iter->second);
51                 }
52                 else
53                 {
54                         counters[who] = 1;
55                         log(DEBUG,"Count for %s is now *1*",who->nick);
56                 }
57                 if (time(NULL) > reset)
58                 {
59                         log(DEBUG,"floodsettings timer Resetting.");
60                         counters.clear();
61                         reset = time(NULL) + secs;
62                 }
63         }
64
65         bool shouldkick(userrec* who)
66         {
67                 std::map<userrec*,int>::iterator iter = counters.find(who);
68                 if (iter != counters.end())
69                 {
70                         return (iter->second >= this->lines);
71                 }
72                 else return false;
73         }
74
75         void clear(userrec* who)
76         {
77                 std::map<userrec*,int>::iterator iter = counters.find(who);
78                 if (iter != counters.end())
79                 {
80                         counters.erase(iter);
81                 }
82         }
83 };
84
85 class ModuleMsgFlood : public Module
86 {
87         Server *Srv;
88         
89  public:
90  
91         ModuleMsgFlood(Server* Me)
92                 : Module::Module(Me)
93         {
94                 Srv = Me;
95                 Srv->AddExtendedMode('f',MT_CHANNEL,false,1,0);
96         }
97         
98         virtual int OnExtendedMode(userrec* user, void* target, char modechar, int type, bool mode_on, string_list &params)
99         {
100                 if ((modechar == 'f') && (type == MT_CHANNEL))
101                 {
102                         if (mode_on)
103                         {
104                                 std::string FloodParams = params[0];
105                                 chanrec* c = (chanrec*)target;
106                                 char ndata[MAXBUF];
107                                 char* data = ndata;
108                                 strlcpy(ndata,FloodParams.c_str(),MAXBUF);
109                                 char* lines = data;
110                                 char* secs = NULL;
111                                 bool ban = false;
112                                 if (*data == '*')
113                                 {
114                                         ban = true;
115                                         lines++;
116                                 }
117                                 else
118                                 {
119                                         ban = false;
120                                 }
121                                 while (*data)
122                                 {
123                                         if (*data == ':')
124                                         {
125                                                 *data = 0;
126                                                 data++;
127                                                 secs = data;
128                                                 break;
129                                         }
130                                         else data++;
131                                 }
132                                 if (secs)
133                                 {
134                                         /* Set up the flood parameters for this channel */
135                                         int nlines = atoi(lines);
136                                         int nsecs = atoi(secs);
137                                         if ((nlines<1) || (nsecs<1))
138                                         {
139                                                 WriteServ(user->fd,"608 %s %s :Invalid flood parameter",user->nick,c->name);
140                                                 return 0;
141                                         }
142                                         else
143                                         {
144                                                 if (!c->GetExt("flood"))
145                                                 {
146                                                         floodsettings *f = new floodsettings(ban,nlines,nsecs);
147                                                         c->Extend("flood",(char*)f);
148                                                 }
149                                         }
150                                         return 1;
151                                 }
152                                 else
153                                 {
154                                         WriteServ(user->fd,"608 %s %s :Invalid flood parameter",user->nick,c->name);
155                                         return 0;
156                                 }
157                                 
158                         }
159                         else
160                         {
161                                 chanrec* c = (chanrec*)target;
162                                 if (c->GetExt("flood"))
163                                 {
164                                         floodsettings *f = (floodsettings*)c->GetExt("flood");
165                                         delete f;
166                                         c->Shrink("flood");
167                                 }
168                         }
169                         return 1;
170                 }
171                 return 0;
172         }
173
174         int ProcessMessages(userrec* user,chanrec* dest,std::string &text)
175         {
176                 floodsettings *f = (floodsettings*)dest->GetExt("flood");
177                 if (f)
178                 {
179                         f->addmessage(user);
180                         if (f->shouldkick(user))
181                         {
182                                 /* Youre outttta here! */
183                                 f->clear(user);
184                                 if (f->ban)
185                                 {
186                                         char* parameters[3];
187                                         parameters[0] = dest->name;
188                                         parameters[1] = "+b";
189                                         parameters[2] = user->MakeWildHost();
190                                         Srv->SendMode(parameters,3,user);
191                                 }
192                                 Srv->KickUser(NULL, user, dest, "Channel flood triggered (mode +f)");
193                                 return 1;
194                         }
195                 }
196                 return 0;
197         }
198
199         virtual int OnUserPreMessage(userrec* user,void* dest,int target_type, std::string &text)
200         {
201                 if (target_type == TYPE_CHANNEL)
202                 {
203                         return ProcessMessages(user,(chanrec*)dest,text);
204                 }
205                 else return 0;
206         }
207
208         virtual int OnUserPreNotice(userrec* user,void* dest,int target_type, std::string &text)
209         {
210                 if (target_type == TYPE_CHANNEL)
211                 {
212                         return ProcessMessages(user,(chanrec*)dest,text);
213                 }
214                 else return 0;
215         }
216
217         void OnChannelDelete(chanrec* chan)
218         {
219                 if (chan->GetExt("flood"))
220                 {
221                         floodsettings *f = (floodsettings*)chan->GetExt("flood");
222                         delete f;
223                         chan->Shrink("flood");
224                 }
225         }
226
227         void Implements(char* List)
228         {
229                 List[I_On005Numeric] = List[I_OnExtendedMode] = List[I_OnChannelDelete] = List[I_OnUserPreNotice] = List[I_OnUserPreMessage] = 1;
230         }
231
232         virtual void On005Numeric(std::string &output)
233         {
234                 std::stringstream line(output);
235                 std::string temp1, temp2;
236                 while (!line.eof())
237                 {
238                         line >> temp1;
239                         if (temp1.substr(0,10) == "CHANMODES=")
240                         {
241                                 // By doing this we're *assuming* no other module has fucked up the CHANMODES=
242                                 // section of the 005 numeric. If they have, we're going DOWN in a blaze of glory,
243                                 // with a honking great EXCEPTION :)
244                                 temp1.insert(temp1.find(",")+1,"f");
245                         }
246                         temp2 = temp2 + temp1 + " ";
247                 }
248                 if (temp2.length())
249                         output = temp2.substr(0,temp2.length()-1);
250         }
251
252         virtual ~ModuleMsgFlood()
253         {
254         }
255         
256         virtual Version GetVersion()
257         {
258                 return Version(1,0,0,0,VF_STATIC|VF_VENDOR);
259         }
260 };
261
262
263 class ModuleMsgFloodFactory : public ModuleFactory
264 {
265  public:
266         ModuleMsgFloodFactory()
267         {
268         }
269         
270         ~ModuleMsgFloodFactory()
271         {
272         }
273         
274         virtual Module * CreateModule(Server* Me)
275         {
276                 return new ModuleMsgFlood(Me);
277         }
278         
279 };
280
281
282 extern "C" void * init_module( void )
283 {
284         return new ModuleMsgFloodFactory;
285 }
286