]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/u_listmode.h
Port m_blockcaps to new api, remove OnExtendedMode and OnDisplayList events entirely
[user/henk/code/inspircd.git] / include / u_listmode.h
1 #ifndef INSPIRCD_LISTMODE_PROVIDER
2 #define INSPIRCD_LISTMODE_PROVIDER
3
4 #include <stdio.h>
5 #include <string>
6 #include <sstream>
7 #include <vector>
8 #include "users.h"
9 #include "channels.h"
10 #include "modules.h"
11 #include "helperfuncs.h"
12
13 /* $ModDesc: Provides support for easily creating listmodes, stores the time set, the user, and a parameter. */
14
15 /* Updated to use the <banlist> config tag if it exists */
16 /* Written by Om <omster@gmail.com>, December 2005. */
17 /* Based on code previously written by Om - April 2005 */
18 /* Updated to new API July 8th 2006 by Brain */
19 /* Originally based on m_chanprotect and m_silence */
20
21 inline std::string stringtime()
22 {
23         std::ostringstream TIME;
24         TIME << time(NULL); 
25         return TIME.str();
26 }
27
28 class ListItem
29 {
30 public:
31         std::string nick;
32         std::string mask;
33         std::string time;
34 };
35
36 class ListLimit
37 {
38 public:
39         std::string mask;
40         unsigned int limit;
41 };
42
43 // Just defining the type we use for the exception list here...
44 typedef std::vector<ListItem> modelist;
45 typedef std::vector<ListLimit> limitlist;
46
47 class ListModeBase : public ModeHandler
48 {
49  protected:
50         std::string infokey;
51         std::string listnumeric;
52         std::string endoflistnumeric;
53         std::string endofliststring;
54         limitlist chanlimits;
55
56         Server* Srv;
57         ConfigReader* Conf;
58  public:
59         ListModeBase(Server* serv, char modechar, const std::string &eolstr, const std::string &lnum, const std::string &eolnum) : ModeHandler(modechar, 1, 1, true, MODETYPE_CHANNEL, false)
60         {
61                 Srv = serv;
62                 Conf = new ConfigReader;
63                 mode = modechar;
64                 listnumeric = lnum;
65                 endoflistnumeric = eolnum;
66                 endofliststring = eolstr;
67                 this->DoRehash();
68                 infokey = "exceptionbase_mode_" + std::string(1, mode) + "_list";
69         }
70
71         virtual void DisplayList(userrec* user, chanrec* channel)
72         {
73                 modelist* el = (modelist*)channel->GetExt(infokey);
74                 if (el)
75                 {
76                         for(modelist::iterator it = el->begin(); it != el->end(); it++)
77                         {
78                                 WriteServ(user->fd, "%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());
79                         }
80                 }
81                 WriteServ(user->fd, "%s %s %s %s", endoflistnumeric.c_str(), user->nick, channel->name, endofliststring.c_str());
82         }
83
84         virtual void DoRehash()
85         {
86                 delete Conf;
87                 Conf = new ConfigReader;
88
89                 chanlimits.clear();
90
91                 for(int i = 0; i < Conf->Enumerate("banlist"); i++)
92                 {
93                         // For each <banlist> tag
94                         ListLimit limit;
95                         limit.mask = Conf->ReadValue("banlist", "chan", i);
96                         limit.limit = Conf->ReadInteger("banlist", "limit", i, true);
97
98                         if(limit.mask.size() && limit.limit > 0)
99                         {
100                                 chanlimits.push_back(limit);
101                                 log(DEBUG, "m_exceptionbase.so: Read channel listmode limit of %u for mask '%s'", limit.limit, limit.mask.c_str());
102                         }
103                         else
104                         {
105                                 log(DEBUG, "m_exceptionbase.so: Invalid tag");
106                         }
107                 }
108                 if(chanlimits.size() == 0)
109                 {
110                         ListLimit limit;
111                         limit.mask = "*";
112                         limit.limit = 64;
113                         chanlimits.push_back(limit);
114                 }
115         }
116
117         virtual void DoImplements(char* List)
118         {
119                 List[I_OnChannelDelete] = List[I_OnSyncChannel] = List[I_OnCleanup] = List[I_OnRehash] = 1;
120         }
121
122         virtual ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string &parameter, bool adding)
123         {
124                 // Try and grab the list
125                 modelist* el = (modelist*)channel->GetExt(infokey);
126
127                 if (adding)
128                 {
129                         // If there was no list
130                         if (!el)
131                         {
132                                 // Make one
133                                 el = new modelist;
134                                 channel->Extend(infokey, (char*)el);
135                         }
136
137                         // Clean the mask up
138                         ModeParser::CleanMask(parameter);
139
140                         // Check if the item already exists in the list
141                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
142                         {
143                                 if(parameter == it->mask)
144                                 {
145                                         // it does, deny the change
146                                         parameter = "";
147                                         return MODEACTION_DENY;
148                                 }
149                         }
150
151                         unsigned int maxsize = 0;
152
153                         for (limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
154                         {
155                                 if (Srv->MatchText(channel->name, it->mask))
156                                 {
157                                         // We have a pattern matching the channel...
158                                         maxsize = el->size();
159                                         if (maxsize < it->limit)
160                                         {
161                                                 // And now add the mask onto the list...
162                                                 ListItem e;
163                                                 e.mask = parameter;
164                                                 e.nick = source->nick;
165                                                 e.time = stringtime();
166
167                                                 el->push_back(e);
168                                                 return MODEACTION_ALLOW;
169                                         }
170                                 }
171                         }
172
173                         // List is full
174                         WriteServ(source->fd, "478 %s %s %s :Channel ban/ignore list is full", source->nick, channel->name, parameter.c_str());
175                         parameter = "";
176                         return MODEACTION_DENY;
177                 }
178                 else
179                 {
180                         // We're taking the mode off
181                         if (el)
182                         {
183                                 for (modelist::iterator it = el->begin(); it != el->end(); it++)
184                                 {
185                                         if(parameter == it->mask)
186                                         {
187                                                 el->erase(it);
188                                                 if(el->size() == 0)
189                                                 {
190                                                         channel->Shrink(infokey);
191                                                         delete el;
192                                                 }
193                                                 return MODEACTION_ALLOW;
194                                         }
195                                 }
196                                 parameter = "";
197                                 return MODEACTION_DENY;
198                         }
199                         else
200                         {
201                                 // Hmm, taking an exception off a non-existant list, DIE
202                                 parameter = "";
203                                 return MODEACTION_DENY;
204                         }
205                 }
206                 return MODEACTION_DENY;
207         }
208
209         virtual std::string& GetInfoKey()
210         {
211                 return infokey;
212         }
213
214         virtual void DoChannelDelete(chanrec* chan)
215         {
216                 modelist* list = (modelist*)chan->GetExt(infokey);
217
218                 if (list)
219                 {
220                         chan->Shrink(infokey);
221                         delete list;
222                 }
223         }
224
225         virtual void DoSyncChannel(chanrec* chan, Module* proto, void* opaque)
226         {
227                 modelist* list = (modelist*)chan->GetExt(infokey);
228                 if (list)
229                 {
230                         for (modelist::iterator it = list->begin(); it != list->end(); it++)
231                         {
232                                 proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, "+" + std::string(1, mode) + " " + it->mask);
233                         }
234                 }
235         }
236
237         virtual void DoCleanup(int target_type, void* item)
238         {
239                 if (target_type == TYPE_CHANNEL)
240                 {
241                         chanrec* chan = (chanrec*)item;
242
243                         modelist* list = (modelist*)chan->GetExt(infokey);
244
245                         if (list)
246                         {
247                                 chan->Shrink(infokey);
248                                 delete list;
249                         }
250                 }
251         }
252 };
253
254 #endif