]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/u_listmode.h
xline gutting, once more. There is no longer an active_lines vector, and no requireme...
[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 /** Get the time as a string
28  */
29 inline std::string stringtime()
30 {
31         std::ostringstream TIME;
32         TIME << time(NULL); 
33         return TIME.str();
34 }
35
36 /** An item in a listmode's list
37  */
38 class ListItem : public classbase
39 {
40 public:
41         std::string nick;
42         irc::string mask;
43         std::string time;
44 };
45
46 /** The number of items a listmode's list may contain
47  */
48 class ListLimit : public classbase
49 {
50 public:
51         std::string mask;
52         unsigned int limit;
53 };
54
55 /** Items stored in the channel's list
56  */
57 typedef std::vector<ListItem> modelist;
58 /** Max items per channel by name
59  */
60 typedef std::vector<ListLimit> limitlist;
61
62 /** A request used to check if a user is on a channel's list or not
63  */
64 class ListModeRequest : public Request
65 {
66  public:
67         User* user;
68         Channel* chan;
69
70         /** Check if a user is on a channel's list.
71          * The Event::Send() event returns true if the user is on the channel's list.
72          * @param sender Sending module
73          * @param target Target module
74          * @param u User to check against
75          * @param c Channel to check against
76          */
77         ListModeRequest(Module* sender, Module* target, User* u, Channel* c) : Request(sender, target, "LM_CHECKLIST"), user(u), chan(c)
78         {
79         }
80
81         /** Destructor
82          */
83         ~ListModeRequest()
84         {
85         }
86 };
87
88 /** The base class for list modes, should be inherited.
89  */
90 class ListModeBase : public ModeHandler
91 {
92  protected:
93         /** Storage key
94          */
95         std::string infokey;
96         /** Numeric to use when outputting the list
97          */
98         std::string listnumeric;
99         /** Numeric to indicate end of list
100          */
101         std::string endoflistnumeric;
102         /** String to send for end of list
103          */
104         std::string endofliststring;
105         /** Automatically tidy up entries
106          */
107         bool tidy;
108         /** Config tag to check for max items per channel
109          */
110         std::string configtag;
111         /** Limits on a per-channel basis read from the tag
112          * specified in ListModeBase::configtag
113          */
114         limitlist chanlimits;
115  
116  public:
117         /** Constructor.
118          * @param Instance The creator of this class
119          * @param modechar Mode character
120          * @param eolstr End of list string
121          * @pram lnum List numeric
122          * @param eolnum End of list numeric
123          * @param autotidy Automatically tidy list entries on add
124          * @param ctag Configuration tag to get limits from
125          */
126         ListModeBase(InspIRCd* Instance, char modechar, const std::string &eolstr, const std::string &lnum, const std::string &eolnum, bool autotidy, const std::string &ctag = "banlist")
127         : ModeHandler(Instance, modechar, 1, 1, true, MODETYPE_CHANNEL, false), listnumeric(lnum), endoflistnumeric(eolnum), endofliststring(eolstr), tidy(autotidy), configtag(ctag)
128         {
129                 this->DoRehash();
130                 infokey = "listbase_mode_" + std::string(1, mode) + "_list";
131         }
132
133         /** See mode.h 
134          */
135         std::pair<bool,std::string> ModeSet(User*, User*, Channel* channel, const std::string &parameter)
136         {
137                 modelist* el;
138                 channel->GetExt(infokey, el);
139                 if (el)
140                 {
141                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
142                         {
143                                 if(parameter == it->mask)
144                                 {
145                                         return std::make_pair(true, parameter);
146                                 }
147                         }
148                 }
149                 return std::make_pair(false, parameter);
150         }
151
152         /** Display the list for this mode
153          * @param user The user to send the list to
154          * @param channel The channel the user is requesting the list for
155          */
156         virtual void DisplayList(User* user, Channel* channel)
157         {
158                 modelist* el;
159                 channel->GetExt(infokey, el);
160                 if (el)
161                 {
162                         for (modelist::reverse_iterator it = el->rbegin(); it != el->rend(); ++it)
163                         {
164                                 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());
165                         }
166                 }
167                 user->WriteServ("%s %s %s :%s", endoflistnumeric.c_str(), user->nick, channel->name, endofliststring.c_str());
168         }
169
170         virtual void DisplayEmptyList(User* user, Channel* channel)
171         {
172                 user->WriteServ("%s %s %s :%s", endoflistnumeric.c_str(), user->nick, channel->name, endofliststring.c_str());
173         }
174
175         /** Remove all instances of the mode from a channel.
176          * See mode.h
177          * @param channel The channel to remove all instances of the mode from
178          */
179         virtual void RemoveMode(Channel* channel)
180         {
181                 modelist* el;
182                 channel->GetExt(infokey, el);
183                 if (el)
184                 {
185                         irc::modestacker modestack(false);
186                         std::deque<std::string> stackresult;
187                         const char* mode_junk[MAXMODES+2];
188                         mode_junk[0] = channel->name;
189
190                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
191                         {
192                                 modestack.Push(this->GetModeChar(), assign(it->mask));
193                         }
194
195                         while (modestack.GetStackedLine(stackresult))
196                         {
197                                 for (size_t j = 0; j < stackresult.size(); j++)
198                                 {
199                                         mode_junk[j+1] = stackresult[j].c_str();
200                                 }
201
202                                 ServerInstance->SendMode(mode_junk, stackresult.size() + 1, ServerInstance->FakeClient);                
203                         }
204                 }
205         }
206
207         /** See mode.h
208          */
209         virtual void RemoveMode(User*)
210         {
211                 /* Listmodes dont get set on users */
212         }
213
214         /** Perform a rehash of this mode's configuration data
215          */
216         virtual void DoRehash()
217         {
218                 ConfigReader Conf(ServerInstance);
219
220                 chanlimits.clear();
221
222                 for (int i = 0; i < Conf.Enumerate(configtag); i++)
223                 {
224                         // For each <banlist> tag
225                         ListLimit limit;
226                         limit.mask = Conf.ReadValue(configtag, "chan", i);
227                         limit.limit = Conf.ReadInteger(configtag, "limit", i, true);
228
229                         if (limit.mask.size() && limit.limit > 0)
230                                 chanlimits.push_back(limit);
231                 }
232                 if (chanlimits.size() == 0)
233                 {
234                         ListLimit limit;
235                         limit.mask = "*";
236                         limit.limit = 64;
237                         chanlimits.push_back(limit);
238                 }
239         }
240
241         /** Populate the Implements list with the correct events for a List Mode
242          */
243         virtual void DoImplements(char* List)
244         {
245                 List[I_OnChannelDelete] = List[I_OnSyncChannel] = List[I_OnCleanup] = List[I_OnRehash] = 1;
246         }
247
248         /** Handle the list mode.
249          * See mode.h
250          */
251         virtual ModeAction OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
252         {
253                 // Try and grab the list
254                 modelist* el;
255                 channel->GetExt(infokey, el);
256
257                 if (adding)
258                 {
259                         // If there was no list
260                         if (!el)
261                         {
262                                 // Make one
263                                 el = new modelist;
264                                 channel->Extend(infokey, el);
265                         }
266
267                         // Clean the mask up
268                         if (this->tidy)
269                                 ModeParser::CleanMask(parameter);
270
271                         // Check if the item already exists in the list
272                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
273                         {
274                                 if (parameter == it->mask)
275                                 {
276                                         /* Give a subclass a chance to error about this */
277                                         TellAlreadyOnList(source, channel, parameter);
278                                         
279                                         // it does, deny the change
280                                         return MODEACTION_DENY;
281                                 }
282                         }
283
284                         unsigned int maxsize = 0;
285
286                         for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
287                         {
288                                 if (match(channel->name, it->mask.c_str()))
289                                 {
290                                         // We have a pattern matching the channel...
291                                         maxsize = el->size();
292                                         if (maxsize < it->limit)
293                                         {
294                                                 /* Ok, it *could* be allowed, now give someone subclassing us
295                                                  * a chance to validate the parameter.
296                                                  * The param is passed by reference, so they can both modify it
297                                                  * and tell us if we allow it or not.
298                                                  *
299                                                  * eg, the subclass could:
300                                                  * 1) allow
301                                                  * 2) 'fix' parameter and then allow
302                                                  * 3) deny
303                                                  */
304                                                 if (ValidateParam(source, channel, parameter))
305                                                 {
306                                                         // And now add the mask onto the list...
307                                                         ListItem e;
308                                                         e.mask = assign(parameter);
309                                                         e.nick = source->nick;
310                                                         e.time = stringtime();
311
312                                                         el->push_back(e);
313                                                         return MODEACTION_ALLOW;
314                                                 }
315                                                 else
316                                                 {
317                                                         /* If they deny it they have the job of giving an error message */
318                                                         return MODEACTION_DENY;
319                                                 }
320                                         }
321                                 }
322                         }
323
324                         /* List is full, give subclass a chance to send a custom message */
325                         if (!TellListTooLong(source, channel, parameter))
326                         {
327                                 source->WriteServ("478 %s %s %s :Channel ban/ignore list is full", source->nick, channel->name, parameter.c_str());
328                         }
329                         
330                         parameter = "";
331                         return MODEACTION_DENY; 
332                 }
333                 else
334                 {
335                         // We're taking the mode off
336                         if (el)
337                         {
338                                 for (modelist::iterator it = el->begin(); it != el->end(); it++)
339                                 {
340                                         if (parameter == it->mask)
341                                         {
342                                                 el->erase(it);
343                                                 if (el->size() == 0)
344                                                 {
345                                                         channel->Shrink(infokey);
346                                                         delete el;
347                                                 }
348                                                 return MODEACTION_ALLOW;
349                                         }
350                                 }
351                                 /* Tried to remove something that wasn't set */
352                                 TellNotSet(source, channel, parameter);
353                                 parameter = "";
354                                 return MODEACTION_DENY;
355                         }
356                         else
357                         {
358                                 /* Hmm, taking an exception off a non-existant list, DIE */
359                                 TellNotSet(source, channel, parameter);
360                                 parameter = "";
361                                 return MODEACTION_DENY;
362                         }
363                 }
364                 return MODEACTION_DENY;
365         }
366
367         /** Get Extensible key for this mode
368          */
369         virtual std::string& GetInfoKey()
370         {
371                 return infokey;
372         }
373
374         /** Handle channel deletion.
375          * See modules.h.
376          * @param chan Channel being deleted
377          */
378         virtual void DoChannelDelete(Channel* chan)
379         {
380                 modelist* list;
381                 chan->GetExt(infokey, list);
382
383                 if (list)
384                 {
385                         chan->Shrink(infokey);
386                         delete list;
387                 }
388         }
389
390         /** Syncronize channel item list with another server.
391          * See modules.h
392          * @param chan Channel to syncronize
393          * @param proto Protocol module pointer
394          * @param opaque Opaque connection handle
395          */
396         virtual void DoSyncChannel(Channel* chan, Module* proto, void* opaque)
397         {
398                 modelist* list;
399                 chan->GetExt(infokey, list);
400                 irc::modestacker modestack(true);
401                 std::deque<std::string> stackresult;
402                 if (list)
403                 {
404                         for (modelist::iterator it = list->begin(); it != list->end(); it++)
405                         {
406                                 modestack.Push(std::string(1, mode)[0], assign(it->mask));
407                         }
408                 }
409                 while (modestack.GetStackedLine(stackresult))
410                 {
411                         irc::stringjoiner mode_join(" ", stackresult, 0, stackresult.size() - 1);
412                         std::string line = mode_join.GetJoined();
413                         proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, line);
414                 }
415         }
416
417         /** Clean up module on unload
418          * @param target_type Type of target to clean
419          * @param item Item to clean
420          */
421         virtual void DoCleanup(int, void*)
422         {
423         }
424         
425         /** Validate parameters.
426          * Overridden by implementing module.
427          * @param source Source user adding the parameter
428          * @param channel Channel the parameter is being added to
429          * @param parameter The actual parameter being added
430          * @return true if the parameter is valid
431          */
432         virtual bool ValidateParam(User*, Channel*, std::string&)
433         {
434                 return true;
435         }
436         
437         /** Tell the user the list is too long.
438          * Overridden by implementing module.
439          * @param source Source user adding the parameter
440          * @param channel Channel the parameter is being added to
441          * @param parameter The actual parameter being added
442          * @return Ignored
443          */
444         virtual bool TellListTooLong(User*, Channel*, std::string&)
445         {
446                 return false;
447         }
448         
449         /** Tell the user an item is already on the list.
450          * Overridden by implementing module.
451          * @param source Source user adding the parameter
452          * @param channel Channel the parameter is being added to
453          * @param parameter The actual parameter being added
454          */
455         virtual void TellAlreadyOnList(User*, Channel*, std::string&)
456         {
457         }
458         
459         /** Tell the user that the parameter is not in the list.
460          * Overridden by implementing module.
461          * @param source Source user removing the parameter
462          * @param channel Channel the parameter is being removed from
463          * @param parameter The actual parameter being removed
464          */
465         virtual void TellNotSet(User*, Channel*, std::string&)
466         {
467         }
468 };
469
470 #endif
471