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