]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/u_listmode.h
62093fdd4f242c53bfda89ad1f9bc0ec4d7b2a73
[user/henk/code/inspircd.git] / src / modules / u_listmode.h
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 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                 ConfigTagList tags = ServerInstance->Config->ConfTags(configtag);
186
187                 chanlimits.clear();
188
189                 for (ConfigIter i = tags.first; i != tags.second; i++)
190                 {
191                         // For each <banlist> tag
192                         ConfigTag* c = i->second;
193                         ListLimit limit;
194                         limit.mask = c->getString("chan");
195                         limit.limit = c->getInt("limit");
196
197                         if (limit.mask.size() && limit.limit > 0)
198                                 chanlimits.push_back(limit);
199                 }
200                 if (chanlimits.size() == 0)
201                 {
202                         ListLimit limit;
203                         limit.mask = "*";
204                         limit.limit = 64;
205                         chanlimits.push_back(limit);
206                 }
207         }
208
209         /** Populate the Implements list with the correct events for a List Mode
210          */
211         virtual void DoImplements(Module* m)
212         {
213                 Implementation eventlist[] = { I_OnSyncChannel, I_OnRehash };
214                 ServerInstance->Modules->Attach(eventlist, m, 2);
215         }
216
217         /** Handle the list mode.
218          * See mode.h
219          */
220         virtual ModeAction OnModeChange(User* source, User*, Channel* channel, std::string &parameter, bool adding)
221         {
222                 // Try and grab the list
223                 modelist* el = extItem.get(channel);
224
225                 if (adding)
226                 {
227                         // If there was no list
228                         if (!el)
229                         {
230                                 // Make one
231                                 el = new modelist;
232                                 extItem.set(channel, el);
233                         }
234
235                         // Clean the mask up
236                         if (this->tidy)
237                                 ModeParser::CleanMask(parameter);
238
239                         // Check if the item already exists in the list
240                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
241                         {
242                                 if (parameter == it->mask)
243                                 {
244                                         /* Give a subclass a chance to error about this */
245                                         TellAlreadyOnList(source, channel, parameter);
246
247                                         // it does, deny the change
248                                         return MODEACTION_DENY;
249                                 }
250                         }
251
252                         unsigned int maxsize = 0;
253
254                         for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
255                         {
256                                 if (InspIRCd::Match(channel->name, it->mask))
257                                 {
258                                         // We have a pattern matching the channel...
259                                         maxsize = el->size();
260                                         if (!IS_LOCAL(source) || (maxsize < it->limit))
261                                         {
262                                                 /* Ok, it *could* be allowed, now give someone subclassing us
263                                                  * a chance to validate the parameter.
264                                                  * The param is passed by reference, so they can both modify it
265                                                  * and tell us if we allow it or not.
266                                                  *
267                                                  * eg, the subclass could:
268                                                  * 1) allow
269                                                  * 2) 'fix' parameter and then allow
270                                                  * 3) deny
271                                                  */
272                                                 if (ValidateParam(source, channel, parameter))
273                                                 {
274                                                         // And now add the mask onto the list...
275                                                         ListItem e;
276                                                         e.mask = parameter;
277                                                         e.nick = source->nick;
278                                                         e.time = stringtime();
279
280                                                         el->push_back(e);
281                                                         return MODEACTION_ALLOW;
282                                                 }
283                                                 else
284                                                 {
285                                                         /* If they deny it they have the job of giving an error message */
286                                                         return MODEACTION_DENY;
287                                                 }
288                                         }
289                                 }
290                         }
291
292                         /* List is full, give subclass a chance to send a custom message */
293                         if (!TellListTooLong(source, channel, parameter))
294                         {
295                                 source->WriteNumeric(478, "%s %s %s :Channel ban/ignore list is full", source->nick.c_str(), channel->name.c_str(), parameter.c_str());
296                         }
297
298                         parameter = "";
299                         return MODEACTION_DENY;
300                 }
301                 else
302                 {
303                         // We're taking the mode off
304                         if (el)
305                         {
306                                 for (modelist::iterator it = el->begin(); it != el->end(); it++)
307                                 {
308                                         if (parameter == it->mask)
309                                         {
310                                                 el->erase(it);
311                                                 if (el->size() == 0)
312                                                 {
313                                                         extItem.unset(channel);
314                                                 }
315                                                 return MODEACTION_ALLOW;
316                                         }
317                                 }
318                                 /* Tried to remove something that wasn't set */
319                                 TellNotSet(source, channel, parameter);
320                                 parameter = "";
321                                 return MODEACTION_DENY;
322                         }
323                         else
324                         {
325                                 /* Hmm, taking an exception off a non-existant list, DIE */
326                                 TellNotSet(source, channel, parameter);
327                                 parameter = "";
328                                 return MODEACTION_DENY;
329                         }
330                 }
331                 return MODEACTION_DENY;
332         }
333
334         /** Syncronize channel item list with another server.
335          * See modules.h
336          * @param chan Channel to syncronize
337          * @param proto Protocol module pointer
338          * @param opaque Opaque connection handle
339          */
340         virtual void DoSyncChannel(Channel* chan, Module* proto, void* opaque)
341         {
342                 modelist* mlist = extItem.get(chan);
343                 irc::modestacker modestack(true);
344                 std::vector<std::string> stackresult;
345                 std::vector<TranslateType> types;
346                 types.push_back(TR_TEXT);
347                 if (mlist)
348                 {
349                         for (modelist::iterator it = mlist->begin(); it != mlist->end(); it++)
350                         {
351                                 modestack.Push(std::string(1, mode)[0], it->mask);
352                         }
353                 }
354                 while (modestack.GetStackedLine(stackresult))
355                 {
356                         types.assign(stackresult.size(), this->GetTranslateType());
357                         proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, stackresult, types);
358                         stackresult.clear();
359                 }
360         }
361
362         /** Clean up module on unload
363          * @param target_type Type of target to clean
364          * @param item Item to clean
365          */
366         virtual void DoCleanup(int, void*)
367         {
368         }
369
370         /** Validate parameters.
371          * Overridden by implementing module.
372          * @param source Source user adding the parameter
373          * @param channel Channel the parameter is being added to
374          * @param parameter The actual parameter being added
375          * @return true if the parameter is valid
376          */
377         virtual bool ValidateParam(User*, Channel*, std::string&)
378         {
379                 return true;
380         }
381
382         /** Tell the user the list is too long.
383          * Overridden by implementing module.
384          * @param source Source user adding the parameter
385          * @param channel Channel the parameter is being added to
386          * @param parameter The actual parameter being added
387          * @return Ignored
388          */
389         virtual bool TellListTooLong(User*, Channel*, std::string&)
390         {
391                 return false;
392         }
393
394         /** Tell the user an item is already on the list.
395          * Overridden by implementing module.
396          * @param source Source user adding the parameter
397          * @param channel Channel the parameter is being added to
398          * @param parameter The actual parameter being added
399          */
400         virtual void TellAlreadyOnList(User*, Channel*, std::string&)
401         {
402         }
403
404         /** Tell the user that the parameter is not in the list.
405          * Overridden by implementing module.
406          * @param source Source user removing the parameter
407          * @param channel Channel the parameter is being removed from
408          * @param parameter The actual parameter being removed
409          */
410         virtual void TellNotSet(User*, Channel*, std::string&)
411         {
412         }
413 };
414
415 #endif