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