]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_chanprotect.cpp
Switch <stdint.h> test to use a test file too.
[user/henk/code/inspircd.git] / src / modules / m_chanprotect.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2006-2009 Robin Burchell <robin+git@viroteck.net>
6  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
7  *   Copyright (C) 2008 Pippijn van Steenhoven <pip88nl@gmail.com>
8  *   Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc>
9  *   Copyright (C) 2007 John Brooks <john.brooks@dereferenced.net>
10  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
11  *
12  * This file is part of InspIRCd.  InspIRCd is free software: you can
13  * redistribute it and/or modify it under the terms of the GNU General Public
14  * License as published by the Free Software Foundation, version 2.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25
26 #include "inspircd.h"
27
28 /* $ModDesc: Provides channel modes +a and +q */
29
30 #define PROTECT_VALUE 40000
31 #define FOUNDER_VALUE 50000
32
33 struct ChanProtectSettings
34 {
35         bool DeprivSelf;
36         bool DeprivOthers;
37         bool FirstInGetsFounder;
38         bool booting;
39         ChanProtectSettings() : booting(true) {}
40 };
41
42 static ChanProtectSettings settings;
43
44 /** Handles basic operation of +qa channel modes
45  */
46 class FounderProtectBase
47 {
48  private:
49         const std::string type;
50         const char mode;
51         const int list;
52         const int end;
53  public:
54         FounderProtectBase(char Mode, const std::string &mtype, int l, int e) :
55                 type(mtype), mode(Mode), list(l), end(e)
56         {
57         }
58
59         void RemoveMode(Channel* channel, irc::modestacker* stack)
60         {
61                 const UserMembList* cl = channel->GetUsers();
62                 std::vector<std::string> mode_junk;
63                 mode_junk.push_back(channel->name);
64                 irc::modestacker modestack(false);
65                 std::deque<std::string> stackresult;
66
67                 for (UserMembCIter i = cl->begin(); i != cl->end(); i++)
68                 {
69                         if (i->second->hasMode(mode))
70                         {
71                                 if (stack)
72                                         stack->Push(mode, i->first->nick);
73                                 else
74                                         modestack.Push(mode, i->first->nick);
75                         }
76                 }
77
78                 if (stack)
79                         return;
80
81                 while (modestack.GetStackedLine(stackresult))
82                 {
83                         mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
84                         ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);
85                         mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
86                 }
87         }
88
89         void DisplayList(User* user, Channel* channel)
90         {
91                 const UserMembList* cl = channel->GetUsers();
92                 for (UserMembCIter i = cl->begin(); i != cl->end(); ++i)
93                 {
94                         if (i->second->hasMode(mode))
95                         {
96                                 user->WriteServ("%d %s %s %s", list, user->nick.c_str(), channel->name.c_str(), i->first->nick.c_str());
97                         }
98                 }
99                 user->WriteServ("%d %s %s :End of channel %s list", end, user->nick.c_str(), channel->name.c_str(), type.c_str());
100         }
101
102         bool CanRemoveOthers(User* u1, Channel* c)
103         {
104                 Membership* m1 = c->GetUser(u1);
105                 return (settings.DeprivOthers && m1 && m1->hasMode(mode));
106         }
107 };
108
109 /** Abstraction of FounderProtectBase for channel mode +q
110  */
111 class ChanFounder : public ModeHandler, public FounderProtectBase
112 {
113  public:
114         ChanFounder(Module* Creator)
115                 : ModeHandler(Creator, "founder", 'q', PARAM_ALWAYS, MODETYPE_CHANNEL),
116                   FounderProtectBase('q', "founder", 386, 387)
117         {
118                 ModeHandler::list = true;
119                 levelrequired = FOUNDER_VALUE;
120                 m_paramtype = TR_NICK;
121         }
122
123         void setPrefix(int pfx)
124         {
125                 prefix = pfx;
126         }
127
128         unsigned int GetPrefixRank()
129         {
130                 return FOUNDER_VALUE;
131         }
132
133         void RemoveMode(Channel* channel, irc::modestacker* stack)
134         {
135                 FounderProtectBase::RemoveMode(channel, stack);
136         }
137
138         void RemoveMode(User* user, irc::modestacker* stack)
139         {
140         }
141         
142         ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding)
143         {
144                 User* theuser = ServerInstance->FindNick(parameter);
145                 // remove own privs?
146                 if (source == theuser && !adding && settings.DeprivSelf)
147                         return MOD_RES_ALLOW;
148
149                 if (!adding && FounderProtectBase::CanRemoveOthers(source, channel))
150                 {
151                         return MOD_RES_PASSTHRU;
152                 }
153                 else
154                 {
155                         source->WriteNumeric(468, "%s %s :Only servers may set channel mode +q", source->nick.c_str(), channel->name.c_str());
156                         return MOD_RES_DENY;
157                 }
158         }
159
160         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
161         {
162                 return MODEACTION_ALLOW;
163         }
164
165         void DisplayList(User* user, Channel* channel)
166         {
167                 FounderProtectBase::DisplayList(user,channel);
168         }
169 };
170
171 /** Abstraction of FounderProtectBase for channel mode +a
172  */
173 class ChanProtect : public ModeHandler, public FounderProtectBase
174 {
175  public:
176         ChanProtect(Module* Creator)
177                 : ModeHandler(Creator, "admin", 'a', PARAM_ALWAYS, MODETYPE_CHANNEL),
178                   FounderProtectBase('a',"protected user", 388, 389)
179         {
180                 ModeHandler::list = true;
181                 levelrequired = PROTECT_VALUE;
182                 m_paramtype = TR_NICK;
183         }
184
185         void setPrefix(int pfx)
186         {
187                 prefix = pfx;
188         }
189
190
191         unsigned int GetPrefixRank()
192         {
193                 return PROTECT_VALUE;
194         }
195
196         void RemoveMode(Channel* channel, irc::modestacker* stack)
197         {
198                 FounderProtectBase::RemoveMode(channel, stack);
199         }
200
201         void RemoveMode(User* user, irc::modestacker* stack)
202         {
203         }
204
205         ModResult AccessCheck(User* source, Channel* channel, std::string &parameter, bool adding)
206         {
207                 User* theuser = ServerInstance->FindNick(parameter);
208                 // source has +q
209                 if (channel->GetPrefixValue(source) > PROTECT_VALUE)
210                         return MOD_RES_ALLOW;
211
212                 // removing own privs?
213                 if (source == theuser && !adding && settings.DeprivSelf)
214                         return MOD_RES_ALLOW;
215
216                 if (!adding && FounderProtectBase::CanRemoveOthers(source, channel))
217                 {
218                         return MOD_RES_PASSTHRU;
219                 }
220                 else
221                 {
222                         source->WriteNumeric(482, "%s %s :You are not a channel founder", source->nick.c_str(), channel->name.c_str());
223                         return MOD_RES_DENY;
224                 }
225         }
226
227         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
228         {
229                 return MODEACTION_ALLOW;
230         }
231
232         void DisplayList(User* user, Channel* channel)
233         {
234                 FounderProtectBase::DisplayList(user, channel);
235         }
236
237 };
238
239 class ModuleChanProtect : public Module
240 {
241         ChanProtect cp;
242         ChanFounder cf;
243  public:
244         ModuleChanProtect() : cp(this), cf(this)
245         {
246         }
247
248         void init()
249         {
250                 /* Load config stuff */
251                 LoadSettings();
252                 settings.booting = false;
253
254                 ServerInstance->Modules->AddService(cf);
255                 ServerInstance->Modules->AddService(cp);
256
257                 Implementation eventlist[] = { I_OnUserPreJoin };
258                 ServerInstance->Modules->Attach(eventlist, this, sizeof(eventlist)/sizeof(Implementation));
259         }
260
261         void LoadSettings()
262         {
263                 ConfigTag* tag = ServerInstance->Config->ConfValue("chanprotect");
264
265                 settings.FirstInGetsFounder = tag->getBool("noservices");
266
267                 std::string qpre = tag->getString("qprefix");
268                 char QPrefix = qpre.empty() ? 0 : qpre[0];
269
270                 std::string apre = tag->getString("aprefix");
271                 char APrefix = apre.empty() ? 0 : apre[0];
272
273                 if ((APrefix && QPrefix) && APrefix == QPrefix)
274                         throw ModuleException("What the smeg, why are both your +q and +a prefixes the same character?");
275
276                 if (settings.booting)
277                 {
278                         if (APrefix && ServerInstance->Modes->FindPrefix(APrefix) && ServerInstance->Modes->FindPrefix(APrefix) != &cp)
279                                 throw ModuleException("Looks like the +a prefix you picked for m_chanprotect is already in use. Pick another.");
280
281                         if (QPrefix && ServerInstance->Modes->FindPrefix(QPrefix) && ServerInstance->Modes->FindPrefix(QPrefix) != &cf)
282                                 throw ModuleException("Looks like the +q prefix you picked for m_chanprotect is already in use. Pick another.");
283
284                         cp.setPrefix(APrefix);
285                         cf.setPrefix(QPrefix);
286                 }
287                 settings.DeprivSelf = tag->getBool("deprotectself", true);
288                 settings.DeprivOthers = tag->getBool("deprotectothers", true);
289         }
290
291         ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven)
292         {
293                 // if the user is the first user into the channel, mark them as the founder, but only if
294                 // the config option for it is set
295
296                 if (settings.FirstInGetsFounder && !chan)
297                         privs += 'q';
298
299                 return MOD_RES_PASSTHRU;
300         }
301
302         Version GetVersion()
303         {
304                 return Version("Founder and Protect modes (+qa)", VF_VENDOR);
305         }
306 };
307
308 MODULE_INIT(ModuleChanProtect)