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