]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_chanprotect.cpp
Use FindMode instead of FindPrefix for OnUserPreJoin privs; makes it possible to...
[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(Creator, 'q', PARAM_ALWAYS, MODETYPE_CHANNEL),
123                   FounderProtectBase(Instance, 'q', "founder", 386, 387, depriv_self, depriv_others)
124         {
125                 ModeHandler::list = true;
126                 prefix = my_prefix;
127                 levelrequired = FOUNDER_VALUE;
128                 m_paramtype = TR_NICK;
129         }
130
131         unsigned int GetPrefixRank()
132         {
133                 return FOUNDER_VALUE;
134         }
135
136         ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
137         {
138                 return FounderProtectBase::ModeSet(source, dest, channel, parameter);
139         }
140
141         void RemoveMode(Channel* channel, irc::modestacker* stack)
142         {
143                 FounderProtectBase::RemoveMode(channel, stack);
144         }
145
146         void RemoveMode(User* user, irc::modestacker* stack)
147         {
148         }
149
150         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
151         {
152                 User* theuser = ServerInstance->FindNick(parameter);
153
154                 if (!theuser)
155                 {
156                         return MODEACTION_DENY;
157                 }
158
159                 if ((!adding) && FounderProtectBase::CanRemoveOthers(source, channel))
160                 {
161                         return MODEACTION_ALLOW;
162                 }
163
164                 char isoverride=0;
165                 Module *Override = ServerInstance->Modules->FindFeature("Override");
166                 if (Override)
167                 {
168                         OVRrequest ovr(NULL,Override,source,"OTHERMODE");
169                         const char * tmp = ovr.Send();
170                         isoverride = tmp[0];
171                 }
172                  // source is a server, or ulined, we'll let them +-q the user.
173                 if (!IS_LOCAL(source) ||
174                                 ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) ||
175                                 (ServerInstance->ULine(source->nick.c_str())) ||
176                                 (ServerInstance->ULine(source->server)) ||
177                                 (!*source->server) ||
178                                 isoverride)
179                 {
180                         return MODEACTION_ALLOW;
181                 }
182                 else
183                 {
184                         // whoops, someones being naughty!
185                         source->WriteNumeric(468, "%s %s :Only servers may set channel mode +q", source->nick.c_str(), channel->name.c_str());
186                         parameter.clear();
187                         return MODEACTION_DENY;
188                 }
189         }
190
191         void DisplayList(User* user, Channel* channel)
192         {
193                 FounderProtectBase::DisplayList(user,channel);
194         }
195 };
196
197 /** Abstraction of FounderProtectBase for channel mode +a
198  */
199 class ChanProtect : public ModeHandler, public FounderProtectBase
200 {
201  public:
202         ChanProtect(InspIRCd* Instance, Module* Creator, char my_prefix, bool &depriv_self, bool &depriv_others)
203                 : ModeHandler(Creator, 'a', PARAM_ALWAYS, MODETYPE_CHANNEL),
204                   FounderProtectBase(Instance,'a',"protected user", 388, 389, depriv_self, depriv_others)
205         {
206                 ModeHandler::list = true;
207                 prefix = my_prefix;
208                 levelrequired = PROTECT_VALUE;
209                 m_paramtype = TR_NICK;
210         }
211
212         unsigned int GetPrefixRank()
213         {
214                 return PROTECT_VALUE;
215         }
216
217         ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
218         {
219                 return FounderProtectBase::ModeSet(source, dest, channel, parameter);
220         }
221
222         void RemoveMode(Channel* channel, irc::modestacker* stack)
223         {
224                 FounderProtectBase::RemoveMode(channel, stack);
225         }
226
227         void RemoveMode(User* user, irc::modestacker* stack)
228         {
229         }
230
231         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
232         {
233                 User* theuser = ServerInstance->FindNick(parameter);
234
235                 if (!theuser)
236                         return MODEACTION_DENY;
237
238                 if ((!adding) && FounderProtectBase::CanRemoveOthers(source, channel))
239                 {
240                         return MODEACTION_ALLOW;
241                 }
242
243                 char isoverride=0;
244                 Module *Override = ServerInstance->Modules->FindFeature("Override");
245                 if (Override)
246                 {
247                         OVRrequest ovr(NULL,Override,source,"OTHERMODE");
248                         const char * tmp = ovr.Send();
249                         isoverride = tmp[0];
250                 }
251                 // source has +q, is a server, or ulined, we'll let them +-a the user.
252                 if (!IS_LOCAL(source) ||
253                         ((source == theuser) && (!adding) && (FounderProtectBase::remove_own_privs)) ||
254                         (ServerInstance->ULine(source->nick.c_str())) ||
255                         (ServerInstance->ULine(source->server)) ||
256                         (!*source->server) ||
257                         (channel->GetPrefixValue(source) > PROTECT_VALUE) ||
258                         isoverride
259                         )
260                 {
261                         return MODEACTION_ALLOW;
262                 }
263                 else
264                 {
265                         // bzzzt, wrong answer!
266                         source->WriteNumeric(482, "%s %s :You are not a channel founder", source->nick.c_str(), channel->name.c_str());
267                         return MODEACTION_DENY;
268                 }
269         }
270
271         void DisplayList(User* user, Channel* channel)
272         {
273                 FounderProtectBase::DisplayList(user, channel);
274         }
275
276 };
277
278 class ModuleChanProtect : public Module
279 {
280
281         bool FirstInGetsFounder;
282         char QPrefix;
283         char APrefix;
284         bool DeprivSelf;
285         bool DeprivOthers;
286         bool booting;
287         ChanProtect* cp;
288         ChanFounder* cf;
289
290  public:
291
292         ModuleChanProtect(InspIRCd* Me)
293                 : Module(Me), FirstInGetsFounder(false), QPrefix(0), APrefix(0), DeprivSelf(false), DeprivOthers(false), booting(true), cp(NULL), cf(NULL)
294         {
295                 /* Load config stuff */
296                 LoadSettings();
297                 booting = false;
298
299                 /* Initialise module variables */
300
301                 cp = new ChanProtect(ServerInstance, this, APrefix, DeprivSelf, DeprivOthers);
302                 cf = new ChanFounder(ServerInstance, this, QPrefix, DeprivSelf, DeprivOthers);
303
304                 if (!ServerInstance->Modes->AddMode(cp) || !ServerInstance->Modes->AddMode(cf))
305                 {
306                         delete cp;
307                         delete cf;
308                         throw ModuleException("Could not add new modes!");
309                 }
310
311                 Implementation eventlist[] = { I_OnUserKick, I_OnUserPart, I_OnUserPreJoin };
312                 ServerInstance->Modules->Attach(eventlist, this, 3);
313         }
314
315         void LoadSettings()
316         {
317                 ConfigReader Conf(ServerInstance);
318
319                 FirstInGetsFounder = Conf.ReadFlag("chanprotect", "noservices", 0);
320
321                 std::string qpre = Conf.ReadValue("chanprotect", "qprefix", 0);
322                 QPrefix = qpre.empty() ? 0 : qpre[0];
323
324                 std::string apre = Conf.ReadValue("chanprotect", "aprefix", 0);
325                 APrefix = apre.empty() ? 0 : apre[0];
326
327                 if ((APrefix && QPrefix) && APrefix == QPrefix)
328                         throw ModuleException("What the smeg, why are both your +q and +a prefixes the same character?");
329
330                 if (cp && ServerInstance->Modes->FindPrefix(APrefix) == cp)
331                         throw ModuleException("Looks like the +a prefix you picked for m_chanprotect is already in use. Pick another.");
332
333                 if (cf && ServerInstance->Modes->FindPrefix(QPrefix) == cf)
334                         throw ModuleException("Looks like the +q prefix you picked for m_chanprotect is already in use. Pick another.");
335
336                 DeprivSelf = Conf.ReadFlag("chanprotect","deprotectself", "yes", 0);
337                 DeprivOthers = Conf.ReadFlag("chanprotect","deprotectothers", "yes", 0);
338         }
339
340         ModResult OnUserPreJoin(User *user, Channel *chan, const char *cname, std::string &privs, const std::string &keygiven)
341         {
342                 // if the user is the first user into the channel, mark them as the founder, but only if
343                 // the config option for it is set
344
345                 if (FirstInGetsFounder && !chan)
346                         privs += 'q';
347
348                 return MOD_RES_PASSTHRU;
349         }
350
351         ~ModuleChanProtect()
352         {
353                 ServerInstance->Modes->DelMode(cp);
354                 ServerInstance->Modes->DelMode(cf);
355                 delete cp;
356                 delete cf;
357         }
358
359         Version GetVersion()
360         {
361                 return Version("Founder and Protect modes (+qa)", VF_COMMON | VF_VENDOR);
362         }
363 };
364
365 MODULE_INIT(ModuleChanProtect)