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