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