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