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