]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/u_listmode.h
Proritise cached value above a search
[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         std::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                 if (el)
106                 {
107                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
108                         {
109                                 if(parameter == it->mask)
110                                 {
111                                         return std::make_pair(true, parameter);
112                                 }
113                         }
114                 }
115                 return std::make_pair(false, parameter);
116         }
117
118         virtual void DisplayList(userrec* user, chanrec* channel)
119         {
120                 modelist* el;
121                 channel->GetExt(infokey, el);
122                 if (el)
123                 {
124                         for(modelist::iterator it = el->begin(); it != el->end(); it++)
125                         {
126                                 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());
127                         }
128                 }
129                 user->WriteServ("%s %s %s :%s", endoflistnumeric.c_str(), user->nick, channel->name, endofliststring.c_str());
130         }
131
132         virtual void RemoveMode(chanrec* channel)
133         {
134                 ServerInstance->Log(DEBUG,"Removing listmode base from %s %s",channel->name,infokey.c_str());
135                 modelist* el;
136                 channel->GetExt(infokey, el);
137                 if (el)
138                 {
139                         ServerInstance->Log(DEBUG,"Channel is extended with a list");
140                         irc::modestacker modestack(false);
141                         std::deque<std::string> stackresult;
142                         const char* mode_junk[MAXMODES+1];
143                         mode_junk[0] = channel->name;
144                         userrec* n = new userrec(ServerInstance);
145                         n->SetFd(FD_MAGIC_NUMBER);
146                         for(modelist::iterator it = el->begin(); it != el->end(); it++)
147                         {
148                                 modestack.Push(this->GetModeChar(), it->mask);
149                         }
150                         while (modestack.GetStackedLine(stackresult))
151                         {
152                                 for (size_t j = 0; j < stackresult.size(); j++)
153                                 {
154                                         mode_junk[j+1] = stackresult[j].c_str();
155                                 }
156                                 ServerInstance->SendMode(mode_junk, stackresult.size() + 1, n);         
157                         }
158
159                         delete n;
160                 }
161         }
162
163         virtual void RemoveMode(userrec* user)
164         {
165                 /* Listmodes dont get set on users */
166         }
167
168         virtual void DoRehash()
169         {
170                 ConfigReader Conf(ServerInstance);
171
172                 chanlimits.clear();
173
174                 for(int i = 0; i < Conf.Enumerate(configtag); i++)
175                 {
176                         // For each <banlist> tag
177                         ListLimit limit;
178                         limit.mask = Conf.ReadValue(configtag, "chan", i);
179                         limit.limit = Conf.ReadInteger(configtag, "limit", i, true);
180
181                         if(limit.mask.size() && limit.limit > 0)
182                                 chanlimits.push_back(limit);
183                 }
184                 if(chanlimits.size() == 0)
185                 {
186                         ListLimit limit;
187                         limit.mask = "*";
188                         limit.limit = 64;
189                         chanlimits.push_back(limit);
190                 }
191         }
192
193         virtual void DoImplements(char* List)
194         {
195                 List[I_OnChannelDelete] = List[I_OnSyncChannel] = List[I_OnCleanup] = List[I_OnRehash] = 1;
196         }
197
198         virtual ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
199         {
200                 // Try and grab the list
201                 modelist* el;
202                 channel->GetExt(infokey, el);
203
204                 if (adding)
205                 {
206                         // If there was no list
207                         if (!el)
208                         {
209                                 // Make one
210                                 el = new modelist;
211                                 channel->Extend(infokey, el);
212                         }
213
214                         // Clean the mask up
215                         if (this->tidy)
216                                 ModeParser::CleanMask(parameter);
217
218                         // Check if the item already exists in the list
219                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
220                         {
221                                 if(parameter == it->mask)
222                                 {
223                                         /* Give a subclass a chance to error about this */
224                                         TellAlreadyOnList(source, channel, parameter);
225                                         
226                                         // it does, deny the change
227                                         return MODEACTION_DENY;
228                                 }
229                         }
230
231                         unsigned int maxsize = 0;
232
233                         for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
234                         {
235                                 if (match(channel->name, it->mask.c_str()))
236                                 {
237                                         // We have a pattern matching the channel...
238                                         maxsize = el->size();
239                                         if (maxsize < it->limit)
240                                         {
241                                                 /* Ok, it *could* be allowed, now give someone subclassing us
242                                                  * a chance to validate the parameter.
243                                                  * The param is passed by reference, so they can both modify it
244                                                  * and tell us if we allow it or not.
245                                                  *
246                                                  * eg, the subclass could:
247                                                  * 1) allow
248                                                  * 2) 'fix' parameter and then allow
249                                                  * 3) deny
250                                                  */
251                                                 if(ValidateParam(source, channel, parameter))
252                                                 {
253                                                         // And now add the mask onto the list...
254                                                         ListItem e;
255                                                         e.mask = parameter;
256                                                         e.nick = source->nick;
257                                                         e.time = stringtime();
258
259                                                         el->push_back(e);
260                                                         return MODEACTION_ALLOW;
261                                                 }
262                                                 else
263                                                 {
264                                                         /* If they deny it they have the job of giving an error message */
265                                                         return MODEACTION_DENY;
266                                                 }
267                                         }
268                                 }
269                         }
270
271                         /* List is full, give subclass a chance to send a custom message */
272                         if(!TellListTooLong(source, channel, parameter))
273                         {
274                                 source->WriteServ("478 %s %s %s :Channel ban/ignore list is full", source->nick, channel->name, parameter.c_str());
275                         }
276                         
277                         parameter = "";
278                         return MODEACTION_DENY; 
279                 }
280                 else
281                 {
282                         // We're taking the mode off
283                         if (el)
284                         {
285                                 for (modelist::iterator it = el->begin(); it != el->end(); it++)
286                                 {
287                                         if(parameter == it->mask)
288                                         {
289                                                 el->erase(it);
290                                                 if(el->size() == 0)
291                                                 {
292                                                         channel->Shrink(infokey);
293                                                         delete el;
294                                                 }
295                                                 return MODEACTION_ALLOW;
296                                         }
297                                 }
298                                 /* Tried to remove something that wasn't set */
299                                 TellNotSet(source, channel, parameter);
300                                 parameter = "";
301                                 return MODEACTION_DENY;
302                         }
303                         else
304                         {
305                                 /* Hmm, taking an exception off a non-existant list, DIE */
306                                 TellNotSet(source, channel, parameter);
307                                 parameter = "";
308                                 return MODEACTION_DENY;
309                         }
310                 }
311                 return MODEACTION_DENY;
312         }
313
314         virtual std::string& GetInfoKey()
315         {
316                 return infokey;
317         }
318
319         virtual void DoChannelDelete(chanrec* chan)
320         {
321                 modelist* list;
322                 chan->GetExt(infokey, list);
323
324                 if (list)
325                 {
326                         chan->Shrink(infokey);
327                         delete list;
328                 }
329         }
330
331         virtual void DoSyncChannel(chanrec* chan, Module* proto, void* opaque)
332         {
333                 modelist* list;
334                 chan->GetExt(infokey, list);
335                 irc::modestacker modestack(true);
336                 std::deque<std::string> stackresult;
337                 if (list)
338                 {
339                         for (modelist::iterator it = list->begin(); it != list->end(); it++)
340                         {
341                                 modestack.Push(std::string(1, mode)[0], it->mask);
342                         }
343                 }
344                 while (modestack.GetStackedLine(stackresult))
345                 {
346                         irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);
347                         std::string line = mode_join.GetJoined();
348                         proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, line);
349                 }
350         }
351
352         virtual void DoCleanup(int target_type, void* item)
353         {
354         }
355         
356         virtual bool ValidateParam(userrec* source, chanrec* channel, std::string &parameter)
357         {
358                 return true;
359         }
360         
361         virtual bool TellListTooLong(userrec* source, chanrec* channel, std::string &parameter)
362         {
363                 return false;
364         }
365         
366         virtual void TellAlreadyOnList(userrec* source, chanrec* channel, std::string &parameter)
367         {
368         }
369         
370         virtual void TellNotSet(userrec* source, chanrec* channel, std::string &parameter)
371         {
372                 
373         }
374 };
375
376 #endif