]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/u_listmode.h
Change mask variable to irc::string to allow for case insensitive removal/addition
[user/henk/code/inspircd.git] / include / u_listmode.h
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2007 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 #ifndef INSPIRCD_LISTMODE_PROVIDER
15 #define INSPIRCD_LISTMODE_PROVIDER
16
17 #include <stdio.h>
18 #include <string>
19 #include <sstream>
20 #include <vector>
21 #include "users.h"
22 #include "channels.h"
23 #include "modules.h"
24 #include "wildcard.h"
25 #include "inspircd.h"
26
27 /* $ModDesc: Provides support for easily creating listmodes, stores the time set, the user, and a parameter. */
28
29 /* Updated to use the <banlist> config tag if it exists */
30 /* Written by Om <omster@gmail.com>, December 2005. */
31 /* Based on code previously written by Om - April 2005 */
32 /* Updated to new API July 8th 2006 by Brain */
33 /* Originally based on m_chanprotect and m_silence */
34
35 inline std::string stringtime()
36 {
37         std::ostringstream TIME;
38         TIME << time(NULL); 
39         return TIME.str();
40 }
41
42 /** An item in a listmode's list
43  */
44 class ListItem : public classbase
45 {
46 public:
47         std::string nick;
48         irc::string mask;
49         std::string time;
50 };
51
52 /** The number of items a listmode's list may contain
53  */
54 class ListLimit : public classbase
55 {
56 public:
57         std::string mask;
58         unsigned int limit;
59 };
60
61 // Just defining the type we use for the exception list here...
62 typedef std::vector<ListItem> modelist;
63 typedef std::vector<ListLimit> limitlist;
64
65 class ListModeRequest : public Request
66 {
67  public:
68         userrec* user;
69         chanrec* chan;
70
71         ListModeRequest(Module* sender, Module* target, userrec* u, chanrec* c) : Request(sender, target, "LM_CHECKLIST"), user(u), chan(c)
72         {
73         }
74
75         ~ListModeRequest()
76         {
77         }
78 };
79
80 /** The base class for listmodes defined by u_listmode.h
81  */
82 class ListModeBase : public ModeHandler
83 {
84  protected:
85         std::string infokey;
86         std::string listnumeric;
87         std::string endoflistnumeric;
88         std::string endofliststring;
89         bool tidy;
90         std::string configtag;
91         limitlist chanlimits;
92  
93  public:
94         ListModeBase(InspIRCd* Instance, char modechar, const std::string &eolstr, const std::string &lnum, const std::string &eolnum, bool autotidy, const std::string &ctag = "banlist")
95         : ModeHandler(Instance, modechar, 1, 1, true, MODETYPE_CHANNEL, false), listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), configtag(ctag)
96         {
97                 this->DoRehash();
98                 infokey = "listbase_mode_" + std::string(1, mode) + "_list";
99         }
100
101         std::pair<bool,std::string> ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string &parameter)
102         {
103                 modelist* el;
104                 channel->GetExt(infokey, el);
105                 irc::string csp(assign(parameter));
106                 if (el)
107                 {
108                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
109                         {
110                                 if(csp == it->mask)
111                                 {
112                                         return std::make_pair(true, parameter);
113                                 }
114                         }
115                 }
116                 return std::make_pair(false, parameter);
117         }
118
119         virtual void DisplayList(userrec* user, chanrec* channel)
120         {
121                 modelist* el;
122                 channel->GetExt(infokey, el);
123                 if (el)
124                 {
125                         for(modelist::iterator it = el->begin(); it != el->end(); it++)
126                         {
127                                 user->WriteServ("%s %s %s %s %s %s", listnumeric.c_str(), user->nick, channel->name, it->mask.c_str(), it->nick.c_str(), it->time.c_str());
128                         }
129                 }
130                 user->WriteServ("%s %s %s :%s", endoflistnumeric.c_str(), user->nick, channel->name, endofliststring.c_str());
131         }
132
133         virtual void RemoveMode(chanrec* channel)
134         {
135                 ServerInstance->Log(DEBUG,"Removing listmode base from %s %s",channel->name,infokey.c_str());
136                 modelist* el;
137                 channel->GetExt(infokey, el);
138                 if (el)
139                 {
140                         ServerInstance->Log(DEBUG,"Channel is extended with a list");
141                         irc::modestacker modestack(false);
142                         std::deque<std::string> stackresult;
143                         const char* mode_junk[MAXMODES+1];
144                         mode_junk[0] = channel->name;
145                         userrec* n = new userrec(ServerInstance);
146                         n->SetFd(FD_MAGIC_NUMBER);
147                         for(modelist::iterator it = el->begin(); it != el->end(); it++)
148                         {
149                                 modestack.Push(this->GetModeChar(), assign(it->mask));
150                         }
151                         while (modestack.GetStackedLine(stackresult))
152                         {
153                                 for (size_t j = 0; j < stackresult.size(); j++)
154                                 {
155                                         mode_junk[j+1] = stackresult[j].c_str();
156                                 }
157                                 ServerInstance->SendMode(mode_junk, stackresult.size() + 1, n);         
158                         }
159
160                         delete n;
161                 }
162         }
163
164         virtual void RemoveMode(userrec* user)
165         {
166                 /* Listmodes dont get set on users */
167         }
168
169         virtual void DoRehash()
170         {
171                 ConfigReader Conf(ServerInstance);
172
173                 chanlimits.clear();
174
175                 for(int i = 0; i < Conf.Enumerate(configtag); i++)
176                 {
177                         // For each <banlist> tag
178                         ListLimit limit;
179                         limit.mask = Conf.ReadValue(configtag, "chan", i);
180                         limit.limit = Conf.ReadInteger(configtag, "limit", i, true);
181
182                         if(limit.mask.size() && limit.limit > 0)
183                                 chanlimits.push_back(limit);
184                 }
185                 if(chanlimits.size() == 0)
186                 {
187                         ListLimit limit;
188                         limit.mask = "*";
189                         limit.limit = 64;
190                         chanlimits.push_back(limit);
191                 }
192         }
193
194         virtual void DoImplements(char* List)
195         {
196                 List[I_OnChannelDelete] = List[I_OnSyncChannel] = List[I_OnCleanup] = List[I_OnRehash] = 1;
197         }
198
199         virtual ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
200         {
201                 // Try and grab the list
202                 modelist* el;
203                 channel->GetExt(infokey, el);
204
205                 if (adding)
206                 {
207                         // If there was no list
208                         if (!el)
209                         {
210                                 // Make one
211                                 el = new modelist;
212                                 channel->Extend(infokey, el);
213                         }
214
215                         // Clean the mask up
216                         if (this->tidy)
217                                 ModeParser::CleanMask(parameter);
218
219                         // Check if the item already exists in the list
220                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
221                         {
222                                 if(parameter == it->mask)
223                                 {
224                                         /* Give a subclass a chance to error about this */
225                                         TellAlreadyOnList(source, channel, parameter);
226                                         
227                                         // it does, deny the change
228                                         return MODEACTION_DENY;
229                                 }
230                         }
231
232                         unsigned int maxsize = 0;
233
234                         for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
235                         {
236                                 if (match(channel->name, it->mask.c_str()))
237                                 {
238                                         // We have a pattern matching the channel...
239                                         maxsize = el->size();
240                                         if (maxsize < it->limit)
241                                         {
242                                                 /* Ok, it *could* be allowed, now give someone subclassing us
243                                                  * a chance to validate the parameter.
244                                                  * The param is passed by reference, so they can both modify it
245                                                  * and tell us if we allow it or not.
246                                                  *
247                                                  * eg, the subclass could:
248                                                  * 1) allow
249                                                  * 2) 'fix' parameter and then allow
250                                                  * 3) deny
251                                                  */
252                                                 if(ValidateParam(source, channel, parameter))
253                                                 {
254                                                         // And now add the mask onto the list...
255                                                         ListItem e;
256                                                         e.mask = assign(parameter);
257                                                         e.nick = source->nick;
258                                                         e.time = stringtime();
259
260                                                         el->push_back(e);
261                                                         return MODEACTION_ALLOW;
262                                                 }
263                                                 else
264                                                 {
265                                                         /* If they deny it they have the job of giving an error message */
266                                                         return MODEACTION_DENY;
267                                                 }
268                                         }
269                                 }
270                         }
271
272                         /* List is full, give subclass a chance to send a custom message */
273                         if(!TellListTooLong(source, channel, parameter))
274                         {
275                                 source->WriteServ("478 %s %s %s :Channel ban/ignore list is full", source->nick, channel->name, parameter.c_str());
276                         }
277                         
278                         parameter = "";
279                         return MODEACTION_DENY; 
280                 }
281                 else
282                 {
283                         // We're taking the mode off
284                         if (el)
285                         {
286                                 for (modelist::iterator it = el->begin(); it != el->end(); it++)
287                                 {
288                                         if(parameter == it->mask)
289                                         {
290                                                 el->erase(it);
291                                                 if(el->size() == 0)
292                                                 {
293                                                         channel->Shrink(infokey);
294                                                         delete el;
295                                                 }
296                                                 return MODEACTION_ALLOW;
297                                         }
298                                 }
299                                 /* Tried to remove something that wasn't set */
300                                 TellNotSet(source, channel, parameter);
301                                 parameter = "";
302                                 return MODEACTION_DENY;
303                         }
304                         else
305                         {
306                                 /* Hmm, taking an exception off a non-existant list, DIE */
307                                 TellNotSet(source, channel, parameter);
308                                 parameter = "";
309                                 return MODEACTION_DENY;
310                         }
311                 }
312                 return MODEACTION_DENY;
313         }
314
315         virtual std::string& GetInfoKey()
316         {
317                 return infokey;
318         }
319
320         virtual void DoChannelDelete(chanrec* chan)
321         {
322                 modelist* list;
323                 chan->GetExt(infokey, list);
324
325                 if (list)
326                 {
327                         chan->Shrink(infokey);
328                         delete list;
329                 }
330         }
331
332         virtual void DoSyncChannel(chanrec* chan, Module* proto, void* opaque)
333         {
334                 modelist* list;
335                 chan->GetExt(infokey, list);
336                 irc::modestacker modestack(true);
337                 std::deque<std::string> stackresult;
338                 if (list)
339                 {
340                         for (modelist::iterator it = list->begin(); it != list->end(); it++)
341                         {
342                                 modestack.Push(std::string(1, mode)[0], assign(it->mask));
343                         }
344                 }
345                 while (modestack.GetStackedLine(stackresult))
346                 {
347                         irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);
348                         std::string line = mode_join.GetJoined();
349                         proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, line);
350                 }
351         }
352
353         virtual void DoCleanup(int target_type, void* item)
354         {
355         }
356         
357         virtual bool ValidateParam(userrec* source, chanrec* channel, std::string &parameter)
358         {
359                 return true;
360         }
361         
362         virtual bool TellListTooLong(userrec* source, chanrec* channel, std::string &parameter)
363         {
364                 return false;
365         }
366         
367         virtual void TellAlreadyOnList(userrec* source, chanrec* channel, std::string &parameter)
368         {
369         }
370         
371         virtual void TellNotSet(userrec* source, chanrec* channel, std::string &parameter)
372         {
373                 
374         }
375 };
376
377 #endif