]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/u_listmode.h
Adding the +e and +I modules m_banexception and m_inviteexception, also adding their...
[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 /* Written by Om <omster@gmail.com>, December 2005. */
16 /* Based on code previously written by Om - April 2005 */
17 /* Originally based on m_chanprotect and m_silence */
18
19 inline std::string stringtime()
20 {
21         std::ostringstream TIME;
22         TIME << time(NULL); 
23         return TIME.str();
24 }
25
26 class ListItem
27 {
28 public:
29         std::string nick;
30         std::string mask;
31         std::string time;
32 };
33
34 class ListLimit
35 {
36 public:
37         std::string mask;
38         unsigned int limit;
39 };
40
41 // Just defining the type we use for the excpetion list here...
42 typedef std::vector<ListItem> modelist;
43 typedef std::vector<ListLimit> limitlist;
44
45 class ListModeBaseModule : public Module
46 {
47 protected:
48         int maxlist;
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, std::string eolstr, std::string lnum, 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(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                                 for(limitlist::iterator it = chanlimits.begin(); it != chanlimits.end(); it++)
151                                 {
152                                         if(Srv->MatchText(chan->name, it->mask))
153                                         {
154                                                 // We have a pattern matching the channel...
155                                                 if(el->size() < it->limit)
156                                                 {
157                                                         // And now add the mask onto the list...
158                                                         ListItem e;
159                                                         e.mask = params[0];
160                                                         e.nick = user->nick;
161                                                         e.time = stringtime();
162                                 
163                                                         Srv->Log(DEBUG, "m_exceptionbase.so: All checks passed, adding exception mask to list and returning 1");
164                                                         el->push_back(e);
165                                                         return 1;
166                                                 }
167                                         }
168                                 }
169
170                                 // List is full
171                                 WriteServ(user->fd, "478 %s %s %s :Channel ban/ignore list is full", user->nick, chan->name, params[0].c_str());
172                                 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, maxlist);
173                                 return -1;
174                         }
175                         else
176                         {
177                                 // We're taking the mode off
178                                 if(el)
179                                 {
180                                         for (modelist::iterator it = el->begin(); it != el->end(); it++)
181                                         {
182                                                 Srv->Log(DEBUG, "m_exceptionbase.so: Removing mode, iterating over exception list, current mask: " + it->mask);
183                                                 if(params[0] == it->mask)
184                                                 {
185                                                         Srv->Log(DEBUG, "m_exceptionbase.so: Found match for removal of exception, removing and returning 1");
186                                                         el->erase(it);
187                                                         if(el->size() == 0)
188                                                         {
189                                                                 Srv->Log(DEBUG, "m_exceptionbase.so: Erased the last entry on the exception list, removing the list");
190                                                                 chan->Shrink(infokey);
191                                                                 delete el;
192                                                         }
193                                                         return 1;
194                                                 }
195                                         }
196                                         Srv->Log(DEBUG, "m_exceptionbase.so: No match found for attempted removing of exception, returning -1");
197                                         return -1;
198                                 }
199                                 else
200                                 {
201                                         // Hmm, taking an exception off a non-existant list, DIE
202                                         Srv->Log(DEBUG, "m_exceptionbase.so: Attempted removal of an exception, when there was no exception list created, returning -1");
203                                         return -1;
204                                 }
205                         }
206                 }
207                 
208                 return 0;
209         }
210         
211         virtual void OnSendList(userrec* user, chanrec* chan, char modechar)
212         {
213                 if(modechar == mode)
214                 {
215                         modelist* el = (modelist*)chan->GetExt(infokey);
216                         Srv->Log(DEBUG, "m_exceptionbase.so: " + std::string(user->nick)+" is listing listmodes on "+std::string(chan->name));
217                         if (el)
218                         {
219                                 for(modelist::iterator it = el->begin(); it != el->end(); it++)
220                                 {
221                                         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());
222                                 }
223                         }
224                         
225                         WriteServ(user->fd, "%s %s %s %s", endoflistnumeric.c_str(), user->nick, chan->name, endofliststring.c_str());
226                 }
227         }
228
229         virtual void OnChannelDelete(chanrec* chan)
230         {
231                 modelist* list = (modelist*)chan->GetExt(infokey);
232                         
233                 if(list)
234                 {
235                         chan->Shrink(infokey);
236                         delete list;
237                 }
238         }
239         
240         virtual void OnSyncChannel(chanrec* chan, Module* proto, void* opaque)
241         {
242                 modelist* list = (modelist*)chan->GetExt(infokey);              
243                 if(list)
244                 {
245                         for(modelist::iterator it = list->begin(); it != list->end(); it++)
246                         {
247                                 proto->ProtoSendMode(opaque, TYPE_CHANNEL, chan, "+" + std::string(1, mode) + " " + it->mask);
248                         }
249                 }
250         }
251         
252         virtual void OnCleanup(int target_type, void* item)
253         {
254                 if (target_type == TYPE_CHANNEL)
255                 {
256                         chanrec* chan = (chanrec*)item;
257                         
258                         modelist* list = (modelist*)chan->GetExt(infokey);
259                         
260                         if(list)
261                         {
262                                 chan->Shrink(infokey);
263                                 delete list;
264                         }
265                 }
266         }
267 };
268
269 #endif