]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_cban.cpp
cf2be71d16fad1518e2b2cfc09d1bd057d55263d
[user/henk/code/inspircd.git] / src / modules / m_cban.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  *                <omster@gmail.com>
10  * 
11  * Written by Craig Edwards, Craig McLure, and others.
12  * This program is free but copyrighted software; see
13  * the file COPYING for details.
14  *
15  * ---------------------------------------------------
16  */
17
18 #include <algorithm>
19 #include <vector>
20 #include <string>
21 #include <sstream>
22 #include "users.h"
23 #include "channels.h"
24 #include "modules.h"
25 #include "helperfuncs.h"
26 #include "hashcomp.h"
27 #include "commands.h"
28 #include "configreader.h"
29 #include "inspircd.h"
30
31 /* $ModDesc: Gives /cban, aka C:lines. Think Q:lines, for channels. */
32
33 class CBan : public classbase
34 {
35 public:
36         irc::string chname;
37         std::string set_by;
38         time_t set_on;
39         long length;
40         std::string reason;
41
42         CBan()
43         {
44         }
45
46         CBan(irc::string cn, std::string sb, time_t so, long ln, std::string rs) : chname(cn), set_by(sb), set_on(so), length(ln), reason(rs)
47         {
48         }
49 };
50
51 bool CBanComp(const CBan &ban1, const CBan &ban2);
52
53 typedef std::vector<CBan> cbanlist;
54
55 /* cbans is declared here, as our type is right above. Don't try move it. */
56 cbanlist cbans;
57
58 class cmd_cban : public command_t
59 {
60  public:
61         cmd_cban(InspIRCd* Me) : command_t(Me, "CBAN", 'o', 1)
62         {
63                 this->source = "m_cban.so";
64                 this->
65                 syntax = "<channel> [<duration> :<reason>]";
66         }
67
68         void Handle(const char** parameters, int pcnt, userrec *user)
69         {
70                 /* syntax: CBAN #channel time :reason goes here */
71                 /* 'time' is a human-readable timestring, like 2d3h2s. */
72
73                 if(pcnt == 1)
74                 {
75                         /* form: CBAN #channel removes a CBAN */
76                         for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
77                         {
78                                 if (parameters[0] == iter->chname)
79                                 {
80                                         unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time();
81                                         user->WriteServ( "386 %s %s :Removed CBAN with %lu seconds left before expiry (%s)", user->nick, iter->chname.c_str(), remaining, iter->reason.c_str());
82                                         cbans.erase(iter);
83                                         break;
84                                 }
85                         }
86                 }
87                 else if (pcnt >= 2)
88                 {
89                         /* full form to add a CBAN */
90                         if (ServerInstance->IsChannel(parameters[0]))
91                         {
92                                 // parameters[0] = #channel
93                                 // parameters[1] = 1h3m2s
94                                 // parameters[2] = Tortoise abuser
95                                 long length = ServerInstance->duration(parameters[1]);
96                                 std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";
97                                 
98                                 cbans.push_back(CBan(parameters[0], user->nick, ServerInstance->Time(), length, reason));
99                                         
100                                 std::sort(cbans.begin(), cbans.end(), CBanComp);
101                                 
102                                 if(length > 0)
103                                 {
104                                         user->WriteServ( "385 %s %s :Added %lu second channel ban (%s)", user->nick, parameters[0], length, reason.c_str());
105                                         ServerInstance->WriteOpers("*** %s added %lu second channel ban on %s (%s)", user->nick, length, parameters[0], reason.c_str());
106                                 }
107                                 else
108                                 {
109                                         user->WriteServ( "385 %s %s :Added permenant channel ban (%s)", user->nick, parameters[0], reason.c_str());
110                                         ServerInstance->WriteOpers("*** %s added permenant channel ban on %s (%s)", user->nick, parameters[0], reason.c_str());
111                                 }
112                         }
113                         else
114                         {
115                                 user->WriteServ( "403 %s %s :Invalid channel name", user->nick, parameters[0]);
116                         }
117                 }
118         }
119 };
120
121 bool CBanComp(const CBan &ban1, const CBan &ban2)
122 {
123         return ((ban1.set_on + ban1.length) < (ban2.set_on + ban2.length));
124 }
125
126 class ModuleCBan : public Module
127 {
128         cmd_cban* mycommand;
129         
130
131  public:
132         ModuleCBan(InspIRCd* Me) : Module::Module(Me)
133         {
134                 
135                 mycommand = new cmd_cban(Me);
136                 ServerInstance->AddCommand(mycommand);
137         }
138
139         void Implements(char* List)
140         {
141                 List[I_OnUserPreJoin] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1;
142         }
143         
144         virtual int OnStats(char symbol, userrec* user, string_list &results)
145         {
146                 ExpireBans();
147         
148                 if(symbol == 'C')
149                 {
150                         for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
151                         {
152                                 unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time();
153                                 results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+iter->chname.c_str()+" "+iter->set_by+" "+ConvToStr(iter->set_on)+" "+ConvToStr(iter->length)+" "+ConvToStr(remaining)+" :"+iter->reason);
154                         }
155                 }
156                 
157                 return 0;
158         }
159
160         virtual int OnUserPreJoin(userrec *user, chanrec *chan, const char *cname)
161         {
162                 ExpireBans();
163         
164                 /* check cbans in here, and apply as necessary. */
165                 for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
166                 {
167                         if(iter->chname == cname && !user->modes[UM_OPERATOR])
168                         {
169                                 // Channel is banned.
170                                 user->WriteServ( "384 %s %s :Cannot join channel, CBANed (%s)", user->nick, cname, iter->reason.c_str());
171                                 ServerInstance->WriteOpers("*** %s tried to join %s which is CBANed (%s)", user->nick, cname, iter->reason.c_str());
172                                 return 1;
173                         }
174                 }
175                 return 0;
176         }
177         
178         virtual void OnSyncOtherMetaData(Module* proto, void* opaque)
179         {
180                 for(cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
181                 {
182                         proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "cban", EncodeCBan(*iter));
183                 }
184         }
185         
186         virtual void OnDecodeMetaData(int target_type, void* target, const std::string &extname, const std::string &extdata)
187         {
188                 if((target_type == TYPE_OTHER) && (extname == "cban"))
189                 {
190                         cbans.push_back(DecodeCBan(extdata));
191                         std::sort(cbans.begin(), cbans.end(), CBanComp);
192                 }
193         }
194
195         virtual ~ModuleCBan()
196         {
197         }
198         
199         virtual Version GetVersion()
200         {
201                 return Version(1,0,0,1,VF_VENDOR);
202         }
203
204         std::string EncodeCBan(const CBan &ban)
205         {
206                 std::ostringstream stream;      
207                 stream << ban.chname << " " << ban.set_by << " " << ban.set_on << " " << ban.length << " " << ban.reason;
208                 return stream.str();    
209         }
210
211         CBan DecodeCBan(const std::string &data)
212         {
213                 CBan res;
214                 std::istringstream stream(data);
215                 stream >> res.chname;
216                 stream >> res.set_by;
217                 stream >> res.set_on;
218                 stream >> res.length;
219                 res.reason = stream.str();
220         
221                 return res;
222         }
223
224         void ExpireBans()
225         {
226                 bool go_again = true;
227
228                 while (go_again)
229                 {
230                         go_again = false;
231         
232                         for (cbanlist::iterator iter = cbans.begin(); iter != cbans.end(); iter++)
233                         {
234                                 /* 0 == permanent, don't mess with them! -- w00t */
235                                 if (iter->length != 0)
236                                 {
237                                         if (iter->set_on + iter->length <= ServerInstance->Time())
238                                         {
239                                                 ServerInstance->Log(DEBUG, "m_cban.so: Ban on %s expired, removing...", iter->chname.c_str());
240                                                 ServerInstance->WriteOpers("*** %li second CBAN on %s (%s) set %u seconds ago expired", iter->length, iter->chname.c_str(), iter->reason.c_str(), ServerInstance->Time() - iter->set_on);
241                                                 cbans.erase(iter);
242                                                 go_again = true;
243                                         }
244                                 }
245         
246                                 if (go_again == true)
247                                         break;
248                         }
249                 }
250         }
251 };
252
253 class ModuleCBanFactory : public ModuleFactory
254 {
255  public:
256         ModuleCBanFactory()
257         {
258         }
259         
260         ~ModuleCBanFactory()
261         {
262         }
263         
264         virtual Module * CreateModule(InspIRCd* Me)
265         {
266                 return new ModuleCBan(Me);
267         }
268         
269 };
270
271
272 extern "C" void * init_module( void )
273 {
274         return new ModuleCBanFactory;
275 }