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