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