]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/u_listmode.h
Mode +b stuff, probably wont work yet
[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 /* Originally based on m_chanprotect and m_silence */
19
20 inline std::string stringtime()
21 {
22         std::ostringstream TIME;
23         TIME << time(NULL); 
24         return TIME.str();
25 }
26
27 class ListItem
28 {
29 public:
30         std::string nick;
31         std::string mask;
32         std::string time;
33 };
34
35 class ListLimit
36 {
37 public:
38         std::string mask;
39         unsigned int limit;
40 };
41
42 // Just defining the type we use for the exception list here...
43 typedef std::vector<ListItem> modelist;
44 typedef std::vector<ListLimit> limitlist;
45
46 class ListModeBaseModule : public Module
47 {
48 protected:
49         char mode;
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         ListModeBaseModule(Server* serv, char modechar, const std::string &eolstr, const std::string &lnum, const std::string &eolnum) : Module::Module(serv)
60         {
61                 Srv = serv;
62                 Conf = new ConfigReader;
63                 mode = modechar;
64                 listnumeric = lnum;
65                 endoflistnumeric = eolnum;
66                 endofliststring = eolstr;
67                 
68                 OnRehash("");
69                 infokey = "exceptionbase_mode_" + std::string(1, mode) + "_list";
70                 Srv->AddExtendedListMode(modechar);             
71         }
72         
73         virtual void OnRehash(const std::string &param)
74         {
75                 delete Conf;
76                 Conf = new ConfigReader;
77                 
78                 chanlimits.clear();
79                 
80                 for(int i = 0; i < Conf->Enumerate("banlist"); i++)
81                 {
82                         // For each <banlist> tag
83                         ListLimit limit;
84                         limit.mask = Conf->ReadValue("banlist", "chan", i);
85                         limit.limit = Conf->ReadInteger("banlist", "limit", i, true);
86                         
87                         if(limit.mask.size() && limit.limit > 0)
88                         {
89                                 chanlimits.push_back(limit);
90                                 log(DEBUG, "m_exceptionbase.so: Read channel listmode limit of %u for mask '%s'", limit.limit, limit.mask.c_str());
91                         }
92                         else
93                         {
94                                 log(DEBUG, "m_exceptionbase.so: Invalid tag");
95                         }
96                 }
97                 
98                 if(chanlimits.size() == 0)
99                 {
100                         ListLimit limit;
101                         limit.mask = "*";
102                         limit.limit = 64;
103                         chanlimits.push_back(limit);
104                 }
105         }
106         
107         void DoImplements(char* List)
108         {
109                 List[I_OnExtendedMode] = List[I_OnSendList] = List[I_OnChannelDelete] = List[I_OnSyncChannel] = List[I_OnCleanup] = List[I_OnRehash] = 1;
110         }
111         
112         virtual int OnExtendedMode(userrec *user, void *target, char modechar, int type, bool mode_on, string_list &params)
113         {
114                 // First, check it's our mode
115                 if ((modechar == mode) && (type == MT_CHANNEL))
116                 {
117                         Srv->Log(DEBUG, "m_exceptionbase.so: General listmode handler called, handling mode '" + std::string(1, mode) + "'");
118                         chanrec* chan = (chanrec*)target;
119
120                         // Try and grab the list
121                         modelist* el = (modelist*)chan->GetExt(infokey);
122
123                         if(mode_on)
124                         {
125                                 // If there was no list
126                                 if(!el)
127                                 {
128                                         // Make one
129                                         Srv->Log(DEBUG, "m_exceptionbase.so: Creating new list");
130                                         el = new modelist;
131                                         chan->Extend(infokey, (char*)el);
132                                 }
133                                 
134                                 if(!Srv->IsValidMask(params[0]))
135                                 {       
136                                         Srv->Log(DEBUG, "m_exceptionbase.so: Banmask was invalid, returning -1");
137                                         return -1;
138                                 }
139                                         
140                                 for (modelist::iterator it = el->begin(); it != el->end(); it++)
141                                 {
142                                         Srv->Log(DEBUG, "m_exceptionbase.so: Iterating over exception list, current mask: " + it->mask);
143                                         if(params[0] == it->mask)
144                                         {
145                                                 Srv->Log(DEBUG, "m_exceptionbase.so: Someone tried to set an exception which was already set, returning -1");
146                                                 return -1;
147                                         }
148                                 }
149                                 
150                                 unsigned int maxsize = 0;
151                                 
152                                 for(limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
153                                 {
154                                         if(Srv->MatchText(chan->name, it->mask))
155                                         {
156                                                 // We have a pattern matching the channel...
157                                                 maxsize = el->size();
158                                                 if(maxsize < it->limit)
159                                                 {
160                                                         // And now add the mask onto the list...
161                                                         ListItem e;
162                                                         e.mask = params[0];
163                                                         e.nick = user->nick;
164                                                         e.time = stringtime();
165                                 
166                                                         Srv->Log(DEBUG, "m_exceptionbase.so: All checks passed, adding exception mask to list and returning 1");
167                                                         el->push_back(e);
168                                                         return 1;
169                                                 }
170                                         }
171                                 }
172
173                                 // List is full
174                                 WriteServ(user->fd, "478 %s %s %s :Channel ban/ignore list is full", user->nick, chan->name, params[0].c_str());
175                                 log(DEBUG, "m_exceptionbase.so: %s tried to set mask %s on %s but the list is full (max %d)", user->nick, params[0].c_str(), chan->name, maxsize);
176                                 return -1;
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                                                 Srv->Log(DEBUG, "m_exceptionbase.so: Removing mode, iterating over exception list, current mask: " + it->mask);
186                                                 if(params[0] == it->mask)
187                                                 {
188                                                         Srv->Log(DEBUG, "m_exceptionbase.so: Found match for removal of exception, removing and returning 1");
189                                                         el->erase(it);
190                                                         if(el->size() == 0)
191                                                         {
192                                                                 Srv->Log(DEBUG, "m_exceptionbase.so: Erased the last entry on the exception list, removing the list");
193                                                                 chan->Shrink(infokey);
194                                                                 delete el;
195                                                         }
196                                                         return 1;
197                                                 }
198                                         }
199                                         Srv->Log(DEBUG, "m_exceptionbase.so: No match found for attempted removing of exception, returning -1");
200                                         return -1;
201                                 }
202                                 else
203                                 {
204                                         // Hmm, taking an exception off a non-existant list, DIE
205                                         Srv->Log(DEBUG, "m_exceptionbase.so: Attempted removal of an exception, when there was no exception list created, returning -1");
206                                         return -1;
207                                 }
208                         }
209                 }
210                 
211                 return 0;
212         }
213         
214         virtual void OnSendList(userrec* user, chanrec* chan, char modechar)
215         {
216                 if(modechar == mode)
217                 {
218                         modelist* el = (modelist*)chan->GetExt(infokey);
219                         Srv->Log(DEBUG, "m_exceptionbase.so: " + std::string(user->nick)+" is listing listmodes on "+std::string(chan->name));
220                         if (el)
221                         {
222                                 for(modelist::iterator it = el->begin(); it != el->end(); it++)
223                                 {
224                                         WriteServ(user->fd, "%s %s %s %s %s %s", listnumeric.c_str(), user->nick, chan->name, it->mask.c_str(), it->nick.c_str(), it->time.c_str());
225                                 }
226                         }
227                         
228                         WriteServ(user->fd, "%s %s %s %s", endoflistnumeric.c_str(), user->nick, chan->name, endofliststring.c_str());
229                 }
230         }
231
232         virtual void OnChannelDelete(chanrec* chan)
233         {
234                 modelist* list = (modelist*)chan->GetExt(infokey);
235                         
236                 if(list)
237                 {
238                         chan->Shrink(infokey);
239                         delete list;
240                 }
241         }
242         
243         virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
244         {
245                 modelist* list = (modelist*)chan->GetExt(infokey);              
246                 if(list)
247                 {
248                         for(modelist::iterator it = list->begin(); it != list->end(); it++)
249                         {
250                                 proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, "+" + std::string(1, mode) + " " + it->mask);
251                         }
252                 }
253         }
254         
255         virtual void OnCleanup(int target_type, void* item)
256         {
257                 if (target_type == TYPE_CHANNEL)
258                 {
259                         chanrec* chan = (chanrec*)item;
260                         
261                         modelist* list = (modelist*)chan->GetExt(infokey);
262                         
263                         if(list)
264                         {
265                                 chan->Shrink(infokey);
266                                 delete list;
267                         }
268                 }
269         }
270 };
271
272 #endif