]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_joinflood.cpp
Add extra method to mode handler, ModeHandler::ModeSet().
[user/henk/code/inspircd.git] / src / modules / m_joinflood.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 +j (join flood protection) */
27
28 class joinfloodsettings : public classbase
29 {
30  public:
31
32         int secs;
33         int joins;
34         time_t reset;
35         time_t unlocktime;
36         int counter;
37         bool locked;
38
39         joinfloodsettings() : secs(0), joins(0) {};
40         joinfloodsettings(int b, int c) : secs(b), joins(c)
41         {
42                 reset = time(NULL) + secs;
43                 counter = 0;
44                 locked = false;
45                 log(DEBUG,"Create new joinfloodsettings: %lu %lu",time(NULL),reset);
46         };
47
48         void addjoin()
49         {
50                 counter++;
51                 log(DEBUG,"joinflood counter is %d",counter);
52                 if (time(NULL) > reset)
53                 {
54                         log(DEBUG,"joinflood counter reset");
55                         counter = 0;
56                         reset = time(NULL) + secs;
57                 }
58         }
59
60         bool shouldlock()
61         {
62                 return (counter >= this->joins);
63         }
64
65         void clear()
66         {
67                 log(DEBUG,"joinflood counter clear");
68                 counter = 0;
69         }
70
71         bool islocked()
72         {
73                 if (locked)
74                 {
75                         if (time(NULL) > unlocktime)
76                         {
77                                 locked = false;
78                                 return false;
79                         }
80                         else
81                         {
82                                 return true;
83                         }
84                 }
85                 return false;
86         }
87
88         void lock()
89         {
90                 log(DEBUG,"joinflood lock");
91                 locked = true;
92                 unlocktime = time(NULL) + 60;
93         }
94
95 };
96
97 class JoinFlood : public ModeHandler
98 {
99  public:
100         JoinFlood() : ModeHandler('j', 1, 0, false, MODETYPE_CHANNEL, false) { }
101
102         std::pair<bool,std::string> ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
103         {
104                 joinfloodsettings* x;
105                 if (channel->GetExt("joinflood",x))
106                         return std::make_pair(true, ConvToStr(x->joins)+":"+ConvToStr(x->secs));
107                 else
108                         return std::make_pair(false, parameter);
109         } 
110
111         ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
112         {
113                 joinfloodsettings* dummy;
114
115                 if (adding)
116                 {
117                         char ndata[MAXBUF];
118                         char* data = ndata;
119                         strlcpy(ndata,parameter.c_str(),MAXBUF);
120                         char* joins = data;
121                         char* secs = NULL;
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 njoins = atoi(joins);
137                                 int nsecs = atoi(secs);
138                                 if ((njoins<1) || (nsecs<1))
139                                 {
140                                         WriteServ(source->fd,"608 %s %s :Invalid flood parameter",source->nick,channel->name);
141                                         parameter = "";
142                                         return MODEACTION_DENY;
143                                 }
144                                 else
145                                 {
146                                         if (!channel->GetExt("joinflood", dummy))
147                                         {
148                                                 parameter = ConvToStr(njoins) + ":" +ConvToStr(nsecs);
149                                                 joinfloodsettings *f = new joinfloodsettings(nsecs,njoins);
150                                                 channel->Extend("joinflood", f);
151                                                 channel->SetMode('j', true);
152                                                 channel->SetModeParam('j', parameter.c_str(), true);
153                                                 return MODEACTION_ALLOW;
154                                         }
155                                 }
156                         }
157                         else
158                         {
159                                 WriteServ(source->fd,"608 %s %s :Invalid flood parameter",source->nick,channel->name);
160                                 return MODEACTION_DENY;
161                         }
162                 }
163                 else
164                 {
165                         if (channel->GetExt("joinflood", dummy))
166                         {
167                                 joinfloodsettings *f;
168                                 channel->GetExt("joinflood", f);
169                                 DELETE(f);
170                                 channel->Shrink("joinflood");
171                                 channel->SetMode('j', false);
172                                 return MODEACTION_ALLOW;
173                         }
174                 }
175                 return MODEACTION_DENY;
176         }
177 };
178
179 class ModuleJoinFlood : public Module
180 {
181         Server *Srv;
182         JoinFlood* jf;
183         
184  public:
185  
186         ModuleJoinFlood(Server* Me)
187                 : Module::Module(Me)
188         {
189                 Srv = Me;
190                 jf = new JoinFlood();
191                 Srv->AddMode(jf, 'j');
192         }
193         
194         virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname)
195         {
196                 if (chan)
197                 {
198                         joinfloodsettings *f;
199                         if (chan->GetExt("joinflood", f))
200                         {
201                                 if (f->islocked())
202                                 {
203                                         WriteServ(user->fd,"609 %s %s :This channel is temporarily unavailable (+j). Please try again later.",user->nick,chan->name);
204                                         return 1;
205                                 }
206                         }
207                 }
208                 return 0;
209         }
210
211         virtual void OnUserJoin(userrec* user, chanrec* channel)
212         {
213                 joinfloodsettings *f;
214                 if (channel->GetExt("joinflood",f))
215                 {
216                         f->addjoin();
217                         if (f->shouldlock())
218                         {
219                                 f->clear();
220                                 f->lock();
221                                 WriteChannelWithServ((char*)Srv->GetServerName().c_str(), channel, "NOTICE %s :This channel has been closed to new users for 60 seconds because there have been more than %d joins in %d seconds.",channel->name,f->joins,f->secs);
222                         }
223                 }
224         }
225
226         void OnChannelDelete(chanrec* chan)
227         {
228                 joinfloodsettings *f;
229                 if (chan->GetExt("joinflood",f))
230                 {
231                         DELETE(f);
232                         chan->Shrink("joinflood");
233                 }
234         }
235
236         void Implements(char* List)
237         {
238                 List[I_On005Numeric] = List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserJoin] = 1;
239         }
240
241         virtual void On005Numeric(std::string &output)
242         {
243                 InsertMode(output, "j", 3);
244         }
245
246         virtual ~ModuleJoinFlood()
247         {
248                 DELETE(jf);
249         }
250         
251         virtual Version GetVersion()
252         {
253                 return Version(1,0,0,0,VF_STATIC|VF_VENDOR);
254         }
255 };
256
257
258 class ModuleJoinFloodFactory : public ModuleFactory
259 {
260  public:
261         ModuleJoinFloodFactory()
262         {
263         }
264         
265         ~ModuleJoinFloodFactory()
266         {
267         }
268         
269         virtual Module * CreateModule(Server* Me)
270         {
271                 return new ModuleJoinFlood(Me);
272         }
273         
274 };
275
276
277 extern "C" void * init_module( void )
278 {
279         return new ModuleJoinFloodFactory;
280 }
281