]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_rline.cpp
Fix /STATS output to show the regex module in use
[user/henk/code/inspircd.git] / src / modules / m_rline.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "m_regex.h"
16 #include "xline.h"
17
18 static Module* rxengine = 0;
19 static Module* mymodule = 0; /* Needed to let RLine send request! */
20
21 /* $ModDesc: RLINE: Regexp user banning. */
22
23 class CoreExport RLine : public XLine
24 {
25  public:
26
27         /** Create a R-Line.
28          * @param s_time The set time
29          * @param d The duration of the xline
30          * @param src The sender of the xline
31          * @param re The reason of the xline
32          * @param regex Pattern to match with
33          * @
34          */
35         RLine(InspIRCd* Instance, time_t s_time, long d, const char* src, const char* re, const char* regexs) : XLine(Instance, s_time, d, src, re, "R")
36         {
37                 matchtext = regexs;
38
39                 if (!rxengine)
40                 {
41                         ServerInstance->SNO->WriteToSnoMask('x', "Cannot create regexes until engine is set to a loaded provider!");
42                         throw ModuleException("Regex engine not set or loaded!");
43                 }
44
45                 /* This can throw on failure, but if it does we DONT catch it here, we catch it and display it
46                  * where the object is created, we might not ALWAYS want it to output stuff to snomask x all the time
47                  */
48                 regex = RegexFactoryRequest(mymodule, rxengine, regexs).Create();
49         }
50
51         /** Destructor
52          */
53         ~RLine()
54         {
55                 delete regex;
56         }
57
58         bool Matches(User *u)
59         {
60                 std::string compare = u->nick + "!" + u->ident + "@" + u->host + " " + u->fullname;
61                 return regex->Matches(compare);
62         }
63
64         bool Matches(const std::string &compare)
65         {
66                 return regex->Matches(compare);
67         }
68
69         void Apply(User* u)
70         {
71                 DefaultApply(u, "R", true);
72         }
73
74         void DisplayExpiry()
75         {
76                 ServerInstance->SNO->WriteToSnoMask('x',"Expiring timed R-Line %s (set by %s %ld seconds ago)", this->matchtext.c_str(), this->source, this->duration);
77         }
78
79         const char* Displayable()
80         {
81                 return matchtext.c_str();
82         }
83
84         std::string matchtext;
85
86         Regex *regex;
87 };
88
89
90 /** An XLineFactory specialized to generate RLine* pointers
91  */
92 class CoreExport RLineFactory : public XLineFactory
93 {
94  public:
95         RLineFactory(InspIRCd* Instance) : XLineFactory(Instance, "R") { }
96
97         /** Generate a RLine
98          */
99         XLine* Generate(time_t set_time, long duration, const char* source, const char* reason, const char* xline_specific_mask)
100         {
101                 return new RLine(ServerInstance, set_time, duration, source, reason, xline_specific_mask);
102         }
103 };
104
105 /** Handle /RLINE
106  * Syntax is same as other lines: RLINE regex_goes_here 1d :reason
107  */
108 class CommandRLine : public Command
109 {
110         std::string rxengine;
111
112  public:
113         CommandRLine (InspIRCd* Instance) : Command(Instance,"RLINE", "o", 1)
114         {
115                 this->source = "m_rline.so";
116         }
117
118         CmdResult Handle (const std::vector<std::string>& parameters, User *user)
119         {
120
121                 if (parameters.size() >= 3)
122                 {
123                         // Adding - XXX todo make this respect <insane> tag perhaps..
124
125                         long duration = ServerInstance->Duration(parameters[1]);
126                         RLine *r = NULL;
127
128                         try
129                         {
130                                 r = new RLine(ServerInstance, ServerInstance->Time(), duration, user->nick.c_str(), parameters[2].c_str(), parameters[0].c_str());
131                         }
132                         catch (ModuleException &e)
133                         {
134                                 ServerInstance->SNO->WriteToSnoMask('x',"Could not add RLINE: %s", e.GetReason());
135                         }
136
137                         if (r)
138                         {
139                                 if (ServerInstance->XLines->AddLine(r, user))
140                                 {
141                                         if (!duration)
142                                         {
143                                                 ServerInstance->SNO->WriteToSnoMask('x',"%s added permanent R-Line for %s.", user->nick.c_str(), parameters[0].c_str());
144                                         }
145                                         else
146                                         {
147                                                 time_t c_requires_crap = duration + ServerInstance->Time();
148                                                 ServerInstance->SNO->WriteToSnoMask('x', "%s added timed R-Line for %s, expires on %s", user->nick.c_str(), parameters[0].c_str(),
149                                                                 ServerInstance->TimeString(c_requires_crap).c_str());
150                                         }
151
152                                         ServerInstance->XLines->ApplyLines();
153                                 }
154                                 else
155                                 {
156                                         delete r;
157                                         user->WriteServ("NOTICE %s :*** R-Line for %s already exists", user->nick.c_str(), parameters[0].c_str());
158                                 }
159                         }
160                 }
161                 else
162                 {
163                         if (ServerInstance->XLines->DelLine(parameters[0].c_str(), "R", user))
164                         {
165                                 ServerInstance->SNO->WriteToSnoMask('x',"%s Removed R-Line on %s.",user->nick.c_str(),parameters[0].c_str());
166                         }
167                         else
168                         {
169                                 user->WriteServ("NOTICE %s :*** R-Line %s not found in list, try /stats R.",user->nick.c_str(),parameters[0].c_str());
170                         }
171                 }
172
173                 return CMD_SUCCESS;
174         }
175 };
176
177 class ModuleRLine : public Module
178 {
179  private:
180         CommandRLine *r;
181         RLineFactory *f;
182         bool MatchOnNickChange;
183         std::string RegexEngine;
184
185  public:
186         ModuleRLine(InspIRCd* Me) : Module(Me)
187         {
188                 mymodule = this;
189                 OnRehash(NULL, "");
190
191                 Me->Modules->UseInterface("RegularExpression");
192
193                 // Create a new command
194                 r = new CommandRLine(ServerInstance);
195                 ServerInstance->AddCommand(r);
196
197                 f = new RLineFactory(ServerInstance);
198                 ServerInstance->XLines->RegisterFactory(f);
199
200                 Implementation eventlist[] = { I_OnUserConnect, I_OnRehash, I_OnUserPostNick, I_OnLoadModule, I_OnStats };
201                 ServerInstance->Modules->Attach(eventlist, this, 5);
202
203         }
204
205         virtual ~ModuleRLine()
206         {
207                 ServerInstance->Modules->DoneWithInterface("RegularExpression");
208                 ServerInstance->XLines->DelAll("R");
209                 ServerInstance->XLines->UnregisterFactory(f);
210         }
211
212         virtual Version GetVersion()
213         {
214                 return Version("$Id$", VF_COMMON | VF_VENDOR, API_VERSION);
215         }
216
217         virtual void OnUserConnect(User* user)
218         {
219                 // Apply lines on user connect
220                 XLine *rl = ServerInstance->XLines->MatchesLine("R", user);
221
222                 if (rl)
223                 {
224                         // Bang. :P
225                         rl->Apply(user);
226                 }
227         }
228
229         virtual void OnRehash(User *user, const std::string &parameter)
230         {
231                 ConfigReader Conf(ServerInstance);
232
233                 MatchOnNickChange = Conf.ReadFlag("rline", "matchonnickchange", 0);
234                 std::string newrxengine = Conf.ReadValue("rline", "engine", 0);
235
236                 if (!RegexEngine.empty())
237                 {
238                         if (RegexEngine == newrxengine)
239                                 return;
240
241                         ServerInstance->SNO->WriteToSnoMask('x', "Dumping all R-Lines due to regex engine change (was '%s', now '%s')", RegexEngine.c_str(), newrxengine.c_str());
242                         ServerInstance->XLines->DelAll("R");
243                 }
244                 rxengine = 0;
245                 RegexEngine = newrxengine;
246                 modulelist* ml = ServerInstance->Modules->FindInterface("RegularExpression");
247                 if (ml)
248                 {
249                         for (modulelist::iterator i = ml->begin(); i != ml->end(); ++i)
250                         {
251                                 if (RegexNameRequest(this, *i).Send() == newrxengine)
252                                 {
253                                         ServerInstance->SNO->WriteToSnoMask('x', "R-Line now using engine '%s'", RegexEngine.c_str());
254                                         rxengine = *i;
255                                 }
256                         }
257                 }
258                 if (!rxengine)
259                 {
260                         ServerInstance->SNO->WriteToSnoMask('x', "WARNING: Regex engine '%s' is not loaded - R-Line functionality disabled until this is corrected.", RegexEngine.c_str());
261                 }
262         }
263
264         virtual int OnStats(char symbol, User* user, string_list &results)
265         {
266                 if (symbol != 'R')
267                         return 0;
268
269                 ServerInstance->XLines->InvokeStats("R", 223, user, results);
270                 return 1;
271         }
272
273         virtual void OnLoadModule(Module* mod, const std::string& name)
274         {
275                 if (ServerInstance->Modules->ModuleHasInterface(mod, "RegularExpression"))
276                 {
277                         std::string rxname = RegexNameRequest(this, mod).Send();
278                         if (rxname == RegexEngine)
279                         {
280                                 ServerInstance->SNO->WriteToSnoMask('x', "R-Line now using engine '%s'", RegexEngine.c_str());
281                                 rxengine = mod;
282                         }
283                 }
284         }
285
286         virtual void OnUserPostNick(User *user, const std::string &oldnick)
287         {
288                 if (!IS_LOCAL(user))
289                         return;
290
291                 if (!MatchOnNickChange)
292                         return;
293
294                 XLine *rl = ServerInstance->XLines->MatchesLine("R", user);
295
296                 if (rl)
297                 {
298                         // Bang! :D
299                         rl->Apply(user);
300                 }
301         }
302
303 };
304
305 MODULE_INIT(ModuleRLine)
306