]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_svshold.cpp
81dcacd0c5a66a67651f673520056fa422c7e6f3
[user/henk/code/inspircd.git] / src / modules / m_svshold.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 "users.h"
20 #include "channels.h"
21 #include "modules.h"
22 #include "configreader.h"
23 #include "inspircd.h"
24
25 /* $ModDesc: Implements SVSHOLD. Like Q:Lines, but can only be added/removed by Services. */
26
27 /** Holds a SVSHold item
28  */
29 class SVSHold : public classbase
30 {
31 public:
32         std::string nickname;
33         std::string set_by;
34         time_t set_on;
35         long length;
36         std::string reason;
37
38         SVSHold()
39         {
40         }
41
42         SVSHold(const std::string &nn, const std::string &sb, const time_t so, const long ln, const std::string &rs) : nickname(nn), set_by(sb), set_on(so), length(ln), reason(rs)
43         {
44         }
45 };
46
47
48 bool SVSHoldComp(const SVSHold &ban1, const SVSHold &ban2);
49
50 typedef std::vector<SVSHold> SVSHoldlist;
51
52 /* SVSHolds is declared here, as our type is right above. Don't try move it. */
53 SVSHoldlist SVSHolds;
54
55 /** Handle /SVSHold
56  */
57 class cmd_svshold : public command_t
58 {
59  public:
60         cmd_svshold(InspIRCd* Me) : command_t(Me, "SVSHOLD", 'o', 1)
61         {
62                 this->source = "m_svshold.so";
63                 this->
64                 syntax = "<nickname> [<duration> :<reason>]";
65         }
66
67         CmdResult Handle(const char** parameters, int pcnt, userrec *user)
68         {
69                 /* syntax: svshold nickname time :reason goes here */
70                 /* 'time' is a human-readable timestring, like 2d3h2s. */
71
72                 if (pcnt == 1)
73                 {
74                         /* form: svshold nickname removes a hold. */
75                         for (SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
76                         {
77                                 if (irc::string(parameters[0]) == irc::string(iter->nickname.c_str()))
78                                 {
79                                         unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time();
80                                         user->WriteServ( "386 %s %s :Removed SVSHOLD with %lu seconds left before expiry (%s)", user->nick, iter->nickname.c_str(), remaining, iter->reason.c_str());
81                                         SVSHolds.erase(iter);
82                                         break;
83                                 }
84                         }
85                 }
86                 else if (pcnt >= 2)
87                 {
88                         /* full form to add a SVSHold */
89                         if (ServerInstance->IsNick(parameters[0]))
90                         {
91                                 // parameters[0] = w00t
92                                 // parameters[1] = 1h3m2s
93                                 // parameters[2] = Registered nickname
94                                 long length = ServerInstance->Duration(parameters[1]);
95                                 std::string reason = (pcnt > 2) ? parameters[2] : "No reason supplied";
96                                 
97                                 SVSHolds.push_back(SVSHold(parameters[0], user->nick, ServerInstance->Time(), length, reason));
98                                         
99                                 std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp);
100                                 
101                                 if(length > 0)
102                                 {
103                                         user->WriteServ( "385 %s %s :Added %lu second SVSHOLD (%s)", user->nick, parameters[0], length, reason.c_str());
104                                         ServerInstance->WriteOpers("*** %s added %lu second SVSHOLD on %s (%s)", user->nick, length, parameters[0], reason.c_str());
105                                 }
106                                 else
107                                 {
108                                         user->WriteServ( "385 %s %s :Added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], reason.c_str());
109                                         ServerInstance->WriteOpers("*** %s added permanent SVSHOLD on %s (%s)", user->nick, parameters[0], reason.c_str());
110                                 }
111                         }
112                         else
113                         {
114                                 /* as this is primarily a Services command, do not provide an error */
115                                 return CMD_FAILURE;
116                         }
117                 }
118
119                 return CMD_SUCCESS;
120         }
121 };
122
123 bool SVSHoldComp(const SVSHold &ban1, const SVSHold &ban2)
124 {
125         return ((ban1.set_on + ban1.length) < (ban2.set_on + ban2.length));
126 }
127
128 class ModuleSVSHold : public Module
129 {
130         cmd_svshold *mycommand;
131         
132
133  public:
134         ModuleSVSHold(InspIRCd* Me) : Module::Module(Me)
135         {
136                 mycommand = new cmd_svshold(Me);
137                 ServerInstance->AddCommand(mycommand);
138         }
139
140         void Implements(char* List)
141         {
142                 List[I_OnUserPreNick] = List[I_OnSyncOtherMetaData] = List[I_OnDecodeMetaData] = List[I_OnStats] = 1;
143         }
144         
145         virtual int OnStats(char symbol, userrec* user, string_list &results)
146         {
147                 ExpireBans();
148         
149                 if(symbol == 'S')
150                 {
151                         for(SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
152                         {
153                                 unsigned long remaining = (iter->set_on + iter->length) - ServerInstance->Time();
154                                 results.push_back(std::string(ServerInstance->Config->ServerName)+" 210 "+user->nick+" "+iter->nickname.c_str()+" "+iter->set_by+" "+ConvToStr(iter->set_on)+" "+ConvToStr(iter->length)+" "+ConvToStr(remaining)+" :"+iter->reason);
155                         }
156                 }
157                 
158                 return 0;
159         }
160
161         virtual int OnUserPreNick(userrec *user, const std::string &newnick)
162         {
163                 ExpireBans();
164         
165                 /* check SVSHolds in here, and apply as necessary. */
166                 for(SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
167                 {
168                         if (irc::string(iter->nickname.c_str()) == irc::string(newnick.c_str()))
169                         {
170                                 // nope, boned.
171                                 user->WriteServ( "432 %s %s :Reserved nickname: %s", user->nick, newnick.c_str(), 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(SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.end(); iter++)
181                 {
182                         proto->ProtoSendMetaData(opaque, TYPE_OTHER, NULL, "SVSHold", EncodeSVSHold(*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 == "SVSHold"))
189                 {
190                         SVSHolds.push_back(DecodeSVSHold(extdata));
191                         std::sort(SVSHolds.begin(), SVSHolds.end(), SVSHoldComp);
192                 }
193         }
194
195         virtual ~ModuleSVSHold()
196         {
197         }
198         
199         virtual Version GetVersion()
200         {
201                 return Version(1,1,0,1,VF_VENDOR|VF_COMMON,API_VERSION);
202         }
203
204         std::string EncodeSVSHold(const SVSHold &ban)
205         {
206                 std::ostringstream stream;      
207                 stream << ban.nickname << " " << ban.set_by << " " << ban.set_on << " " << ban.length << " " << ban.reason;
208                 return stream.str();    
209         }
210
211         SVSHold DecodeSVSHold(const std::string &data)
212         {
213                 SVSHold res;
214                 std::istringstream stream(data);
215                 stream >> res.nickname;
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 (SVSHoldlist::iterator iter = SVSHolds.begin(); iter != SVSHolds.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_svshold.so: hold on %s expired, removing...", iter->nickname.c_str());
240                                                 ServerInstance->WriteOpers("*** %li second SVSHOLD on %s (%s) set %u seconds ago expired", iter->length, iter->nickname.c_str(), iter->reason.c_str(), ServerInstance->Time() - iter->set_on);
241                                                 SVSHolds.erase(iter);
242                                                 go_again = true;
243                                         }
244                                 }
245         
246                                 if (go_again == true)
247                                         break;
248                         }
249                 }
250         }
251 };
252
253 class ModuleSVSHoldFactory : public ModuleFactory
254 {
255  public:
256         ModuleSVSHoldFactory()
257         {
258         }
259         
260         ~ModuleSVSHoldFactory()
261         {
262         }
263         
264         virtual Module * CreateModule(InspIRCd* Me)
265         {
266                 return new ModuleSVSHold(Me);
267         }
268         
269 };
270
271
272 extern "C" void * init_module( void )
273 {
274         return new ModuleSVSHoldFactory;
275 }