]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_chanprotect.cpp
Replace OnAccessCheck with OnPreMode to remove a number of redundant checks
[user/henk/code/inspircd.git] / src / modules / m_chanprotect.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "m_override.h"
16
17 /* $ModDesc: Provides channel modes +a and +q */
18
19 #define PROTECT_VALUE 40000
20 #define FOUNDER_VALUE 50000
21
22 /** Handles basic operation of +qa channel modes
23  */
24 class FounderProtectBase
25 {
26  private:
27         InspIRCd* const MyInstance;
28         const std::string type;
29         const char mode;
30         const int list;
31         const int end;
32  protected:
33         bool& remove_own_privs;
34         bool& remove_other_privs;
35  public:
36         FounderProtectBase(InspIRCd* Instance, char Mode, const std::string &mtype, int l, int e, bool &remove_own, bool &remove_others) :
37                 MyInstance(Instance), type(mtype), mode(Mode), list(l), end(e), remove_own_privs(remove_own), remove_other_privs(remove_others)
38         {
39         }
40
41         ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
42         {
43                 User* x = MyInstance->FindNick(parameter);
44                 if (x)
45                 {
46                         Membership* memb = channel->GetUser(x);
47                         if (!memb)
48                         {
49                                 return std::make_pair(false, parameter);
50                         }
51                         else
52                         {
53                                 if (memb->hasMode(mode))
54                                 {
55                                         return std::make_pair(true, x->nick);
56                                 }
57                                 else
58                                 {
59                                         return std::make_pair(false, parameter);
60                                 }
61                         }
62                 }
63                 return std::make_pair(false, parameter);
64         }
65
66         void RemoveMode(Channel* channel, irc::modestacker* stack)
67         {
68                 const UserMembList* cl = channel->GetUsers();
69                 std::vector<std::string> mode_junk;
70                 mode_junk.push_back(channel->name);
71                 irc::modestacker modestack(MyInstance, false);
72                 std::deque<std::string> stackresult;
73
74                 for (UserMembCIter i = cl->begin(); i != cl->end(); i++)
75                 {
76                         if (i->second->hasMode(mode))
77                         {
78                                 if (stack)
79                                         stack->Push(mode, i->first->nick);
80                                 else
81                                         modestack.Push(mode, i->first->nick);
82                         }
83                 }
84
85                 if (stack)
86                         return;
87
88                 while (modestack.GetStackedLine(stackresult))
89                 {
90                         mode_junk.insert(mode_junk.end(), stackresult.begin(), stackresult.end());
91                         MyInstance->SendMode(mode_junk, MyInstance->FakeClient);
92                         mode_junk.erase(mode_junk.begin() + 1, mode_junk.end());
93                 }
94         }
95
96         void DisplayList(User* user, Channel* channel)
97         {
98                 const UserMembList* cl = channel->GetUsers();
99                 for (UserMembCIter i = cl->begin(); i != cl->end(); ++i)
100                 {
101                         if (i->second->hasMode(mode))
102                         {
103                                 user->WriteServ("%d %s %s %s", list, user->nick.c_str(), channel->name.c_str(), i->first->nick.c_str());
104                         }
105                 }
106                 user->WriteServ("%d %s %s :End of channel %s list", end, user->nick.c_str(), channel->name.c_str(), type.c_str());
107         }
108
109         bool CanRemoveOthers(User* u1, Channel* c)
110         {
111                 Membership* m1 = c->GetUser(u1);
112                 return (remove_other_privs && m1 && m1->hasMode(mode));
113         }
114 };
115
116 /** Abstraction of FounderProtectBase for channel mode +q
117  */
118 class ChanFounder : public ModeHandler, public FounderProtectBase
119 {
120  public:
121         ChanFounder(InspIRCd* Instance, Module* Creator, char my_prefix, bool &depriv_self, bool &depriv_others)
122                 : ModeHandler(Instance, Creator, 'q', 1, 1, true, MODETYPE_CHANNEL, false, my_prefix, 0, TR_NICK),
123                   FounderProtectBase(Instance, 'q', "founder", 386, 387, depriv_self, depriv_others) { }
124
125         unsigned int GetPrefixRank()
126         {
127                 return FOUNDER_VALUE;
128         }
129
130         ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
131         {
132                 return FounderProtectBase::ModeSet(source, dest, channel, parameter);
133         }
134
135         void RemoveMode(Channel* channel, irc::modestacker* stack)
136         {
137                 FounderProtectBase::RemoveMode(channel, stack);
138         }
139
140         void RemoveMode(User* user, irc::modestacker* stack)
141         {
142         }
143
144         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
145         {
146                 User* theuser = ServerInstance->FindNick(parameter);
147
148                 if (!theuser)
149                 {
150                         return MODEACTION_DENY;
151                 }
152
153                 if ((!adding) && FounderProtectBase::CanRemoveOthers(source, channel))
154                 {
155                         return MODEACTION_ALLOW;
156                 }
157
158                 char isoverride=0;
159                 Module *Override = ServerInstance->Modules->FindFeature("Override");
160                 if (Override)
161                 {
162                         OVRrequest ovr(NULL,Override,source,"OTHERMODE");
163                         const char * tmp = ovr.Send();
164                         isoverride = tmp[0];
165                 }
166                  // source is a server, or ulined, we'll let them +-q the user.
167                 if (!IS_LOCAL(source) ||
168                                 ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) ||
169                                 (ServerInstance->ULine(source->nick.c_str())) ||
170                                 (ServerInstance->ULine(source->server)) ||
171                                 (!*source->server) ||
172                                 isoverride)
173                 {
174                         return MODEACTION_ALLOW;
175                 }
176                 else
177                 {
178                         // whoops, someones being naughty!
179                         source->WriteNumeric(468, "%s %s :Only servers may set channel mode +q", source->nick.c_str(), channel->name.c_str());
180                         parameter.clear();
181                         return MODEACTION_DENY;
182                 }
183         }
184
185         void DisplayList(User* user, Channel* channel)
186         {
187                 FounderProtectBase::DisplayList(user,channel);
188         }
189 };
190
191 /** Abstraction of FounderProtectBase for channel mode +a
192  */
193 class ChanProtect : public ModeHandler, public FounderProtectBase
194 {
195  public:
196         ChanProtect(InspIRCd* Instance, Module* Creator, char my_prefix, bool &depriv_self, bool &depriv_others)
197                 : ModeHandler(Instance, Creator, 'a', 1, 1, true, MODETYPE_CHANNEL, false, my_prefix, 0, TR_NICK),
198                   FounderProtectBase(Instance,'a',"protected user", 388, 389, depriv_self, depriv_others) { }
199
200         unsigned int GetPrefixRank()
201         {
202                 return PROTECT_VALUE;
203         }
204
205         ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
206         {
207                 return FounderProtectBase::ModeSet(source, dest, channel, parameter);
208         }
209
210         void RemoveMode(Channel* channel, irc::modestacker* stack)
211         {
212                 FounderProtectBase::RemoveMode(channel, stack);
213         }
214
215         void RemoveMode(User* user, irc::modestacker* stack)
216         {
217         }
218
219         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
220         {
221                 User* theuser = ServerInstance->FindNick(parameter);
222
223                 if (!theuser)
224                         return MODEACTION_DENY;
225
226                 if ((!adding) && FounderProtectBase::CanRemoveOthers(source, channel))
227                 {
228                         return MODEACTION_ALLOW;
229                 }
230
231                 char isoverride=0;
232                 Module *Override = ServerInstance->Modules->FindFeature("Override");
233                 if (Override)
234                 {
235                         OVRrequest ovr(NULL,Override,source,"OTHERMODE");
236                         const char * tmp = ovr.Send();
237                         isoverride = tmp[0];
238                 }
239                 // source has +q, is a server, or ulined, we'll let them +-a the user.
240                 if (!IS_LOCAL(source) ||
241                         ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) ||
242                         (ServerInstance->ULine(source->nick.c_str())) ||
243                         (ServerInstance->ULine(source->server)) ||
244                         (!*source->server) ||
245                         (channel->GetPrefixValue(source) > PROTECT_VALUE) ||
246                         isoverride
247                         )
248                 {
249                         return MODEACTION_ALLOW;
250                 }
251                 else
252                 {
253                         // bzzzt, wrong answer!
254                         source->WriteNumeric(482, "%s %s :You are not a channel founder", source->nick.c_str(), channel->name.c_str());
255                         return MODEACTION_DENY;
256                 }
257         }
258
259         void DisplayList(User* user, Channel* channel)
260         {
261                 FounderProtectBase::DisplayList(user, channel);
262         }
263
264 };
265
266 class ModuleChanProtect : public Module
267 {
268
269         bool FirstInGetsFounder;
270         char QPrefix;
271         char APrefix;
272         bool DeprivSelf;
273         bool DeprivOthers;
274         bool booting;
275         ChanProtect* cp;
276         ChanFounder* cf;
277
278  public:
279
280         ModuleChanProtect(InspIRCd* Me)
281                 : Module(Me), FirstInGetsFounder(false), QPrefix(0), APrefix(0), DeprivSelf(false), DeprivOthers(false), booting(true), cp(NULL), cf(NULL)
282         {
283                 /* Load config stuff */
284                 LoadSettings();
285                 booting = false;
286
287                 /* Initialise module variables */
288
289                 cp = new ChanProtect(ServerInstance, this, APrefix, DeprivSelf, DeprivOthers);
290                 cf = new ChanFounder(ServerInstance, this, QPrefix, DeprivSelf, DeprivOthers);
291
292                 if (!ServerInstance->Modes->AddMode(cp) || !ServerInstance->Modes->AddMode(cf))
293                 {
294                         delete cp;
295                         delete cf;
296                         throw ModuleException("Could not add new modes!");
297                 }
298
299                 Implementation eventlist[] = { I_OnUserKick, I_OnUserPart, I_OnUserPreJoin };
300                 ServerInstance->Modules->Attach(eventlist, this, 3);
301         }
302
303         void LoadSettings()
304         {
305                 ConfigReader Conf(ServerInstance);
306
307                 FirstInGetsFounder = Conf.ReadFlag("chanprotect", "noservices", 0);
308
309                 std::string qpre = Conf.ReadValue("chanprotect", "qprefix", 0);
310                 QPrefix = qpre.empty() ? 0 : qpre[0];
311
312                 std::string apre = Conf.ReadValue("chanprotect", "aprefix", 0);
313                 APrefix = apre.empty() ? 0 : apre[0];
314
315                 if ((APrefix && QPrefix) && APrefix == QPrefix)
316                         throw ModuleException("What the smeg, why are both your +q and +a prefixes the same character?");
317
318                 if (cp && ServerInstance->Modes->FindPrefix(APrefix) == cp)
319                         throw ModuleException("Looks like the +a prefix you picked for m_chanprotect is already in use. Pick another.");
320
321                 if (cf && ServerInstance->Modes->FindPrefix(QPrefix) == cf)
322                         throw ModuleException("Looks like the +q prefix you picked for m_chanprotect is already in use. Pick another.");
323
324                 DeprivSelf = Conf.ReadFlag("chanprotect","deprotectself", "yes", 0);
325                 DeprivOthers = Conf.ReadFlag("chanprotect","deprotectothers", "yes", 0);
326         }
327
328         ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven)
329         {
330                 // if the user is the first user into the channel, mark them as the founder, but only if
331                 // the config option for it is set
332
333                 if (FirstInGetsFounder && !chan)
334                         privs += std::string(1, QPrefix);
335
336                 return MOD_RES_PASSTHRU;
337         }
338
339         ~ModuleChanProtect()
340         {
341                 ServerInstance->Modes->DelMode(cp);
342                 ServerInstance->Modes->DelMode(cf);
343                 delete cp;
344                 delete cf;
345         }
346
347         Version GetVersion()
348         {
349                 return Version("Founder and Protect modes (+qa)", VF_COMMON | VF_VENDOR);
350         }
351 };
352
353 MODULE_INIT(ModuleChanProtect)