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