]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/coremods/core_channel/core_channel.cpp
161f618d1359379f52831b0646c9023081e5ff52
[user/henk/code/inspircd.git] / src / coremods / core_channel / core_channel.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2014-2015 Attila Molnar <attilamolnar@hush.com>
5  *
6  * This file is part of InspIRCd.  InspIRCd is free software: you can
7  * redistribute it and/or modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation, version 2.
9  *
10  * This program is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
13  * details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19
20 #include "inspircd.h"
21 #include "core_channel.h"
22 #include "invite.h"
23 #include "listmode.h"
24
25 class CoreModChannel : public Module, public CheckExemption::EventListener
26 {
27         Invite::APIImpl invapi;
28         CommandInvite cmdinvite;
29         CommandJoin cmdjoin;
30         CommandKick cmdkick;
31         CommandNames cmdnames;
32         CommandTopic cmdtopic;
33
34         ModeChannelBan banmode;
35         SimpleChannelModeHandler inviteonlymode;
36         ModeChannelKey keymode;
37         ModeChannelLimit limitmode;
38         SimpleChannelModeHandler moderatedmode;
39         SimpleChannelModeHandler noextmsgmode;
40         ModeChannelOp opmode;
41         SimpleChannelModeHandler privatemode;
42         SimpleChannelModeHandler secretmode;
43         SimpleChannelModeHandler topiclockmode;
44         ModeChannelVoice voicemode;
45
46         insp::flat_map<std::string, char> exemptions;
47
48         ModResult IsInvited(User* user, Channel* chan)
49         {
50                 LocalUser* localuser = IS_LOCAL(user);
51                 if ((localuser) && (invapi.IsInvited(localuser, chan)))
52                         return MOD_RES_ALLOW;
53                 return MOD_RES_PASSTHRU;
54         }
55
56  public:
57         CoreModChannel()
58                 : CheckExemption::EventListener(this)
59                 , invapi(this)
60                 , cmdinvite(this, invapi)
61                 , cmdjoin(this)
62                 , cmdkick(this)
63                 , cmdnames(this)
64                 , cmdtopic(this)
65                 , banmode(this)
66                 , inviteonlymode(this, "inviteonly", 'i')
67                 , keymode(this)
68                 , limitmode(this)
69                 , moderatedmode(this, "moderated", 'm')
70                 , noextmsgmode(this, "noextmsg", 'n')
71                 , opmode(this)
72                 , privatemode(this, "private", 'p')
73                 , secretmode(this, "secret", 's')
74                 , topiclockmode(this, "topiclock", 't')
75                 , voicemode(this)
76         {
77         }
78
79         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
80         {
81                 ConfigTag* optionstag = ServerInstance->Config->ConfValue("options");
82                 Implementation events[] = { I_OnCheckKey, I_OnCheckLimit, I_OnCheckChannelBan };
83                 if (optionstag->getBool("invitebypassmodes", true))
84                         ServerInstance->Modules.Attach(events, this, sizeof(events)/sizeof(Implementation));
85                 else
86                 {
87                         for (unsigned int i = 0; i < sizeof(events)/sizeof(Implementation); i++)
88                                 ServerInstance->Modules.Detach(events[i], this);
89                 }
90
91                 std::string current;
92                 irc::spacesepstream defaultstream(optionstag->getString("exemptchanops"));
93                 insp::flat_map<std::string, char> exempts;
94                 while (defaultstream.GetToken(current))
95                 {
96                         std::string::size_type pos = current.find(':');
97                         if (pos == std::string::npos || (pos + 2) > current.size())
98                                 throw ModuleException("Invalid exemptchanops value '" + current + "' at " + optionstag->getTagLocation());
99
100                         const std::string restriction = current.substr(0, pos);
101                         const char prefix = current[pos + 1];
102
103                         ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Exempting prefix %c from %s", prefix, restriction.c_str());
104                         exempts[restriction] = prefix;
105                 }
106                 exemptions.swap(exempts);
107
108                 // In 2.0 we allowed limits of 0 to be set. This is non-standard behaviour
109                 // and will be removed in the next major release.
110                 limitmode.minlimit = optionstag->getBool("allowzerolimit", true) ? 0 : 1;
111
112                 banmode.DoRehash();
113         }
114
115         void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
116         {
117                 // Build a map of limits to their mode character.
118                 insp::flat_map<int, std::string> limits;
119                 const ModeParser::ListModeList& listmodes = ServerInstance->Modes->GetListModes();
120                 for (ModeParser::ListModeList::const_iterator iter = listmodes.begin(); iter != listmodes.end(); ++iter)
121                 {
122                         const unsigned int limit = (*iter)->GetLowerLimit();
123                         limits[limit].push_back((*iter)->GetModeChar());
124                 }
125
126                 // Generate the MAXLIST token from the limits map.
127                 std::string& buffer = tokens["MAXLIST"];
128                 for (insp::flat_map<int, std::string>::const_iterator iter = limits.begin(); iter != limits.end(); ++iter)
129                 {
130                         if (!buffer.empty())
131                                 buffer.push_back(',');
132
133                         buffer.append(iter->second);
134                         buffer.push_back(':');
135                         buffer.append(ConvToStr(iter->first));
136                 }
137         }
138
139         void OnPostJoin(Membership* memb) CXX11_OVERRIDE
140         {
141                 Channel* const chan = memb->chan;
142                 LocalUser* const localuser = IS_LOCAL(memb->user);
143                 if (localuser)
144                 {
145                         // Remove existing invite, if any
146                         invapi.Remove(localuser, chan);
147
148                         if (chan->topicset)
149                                 Topic::ShowTopic(localuser, chan);
150
151                         // Show all members of the channel, including invisible (+i) users
152                         cmdnames.SendNames(localuser, chan, true);
153                 }
154         }
155
156         ModResult OnCheckKey(User* user, Channel* chan, const std::string& keygiven) CXX11_OVERRIDE
157         {
158                 // Hook only runs when being invited bypasses +bkl
159                 return IsInvited(user, chan);
160         }
161
162         ModResult OnCheckChannelBan(User* user, Channel* chan) CXX11_OVERRIDE
163         {
164                 // Hook only runs when being invited bypasses +bkl
165                 return IsInvited(user, chan);
166         }
167
168         ModResult OnCheckLimit(User* user, Channel* chan) CXX11_OVERRIDE
169         {
170                 // Hook only runs when being invited bypasses +bkl
171                 return IsInvited(user, chan);
172         }
173
174         ModResult OnCheckInvite(User* user, Channel* chan) CXX11_OVERRIDE
175         {
176                 // Hook always runs
177                 return IsInvited(user, chan);
178         }
179
180         void OnUserDisconnect(LocalUser* user) CXX11_OVERRIDE
181         {
182                 invapi.RemoveAll(user);
183         }
184
185         void OnChannelDelete(Channel* chan) CXX11_OVERRIDE
186         {
187                 // Make sure the channel won't appear in invite lists from now on, don't wait for cull to unset the ext
188                 invapi.RemoveAll(chan);
189         }
190
191         ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) CXX11_OVERRIDE
192         {
193                 if (!exemptions.count(restriction))
194                         return MOD_RES_PASSTHRU;
195
196                 unsigned int mypfx = chan->GetPrefixValue(user);
197                 char minmode = exemptions[restriction];
198
199                 PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(minmode);
200                 if (mh && mypfx >= mh->GetPrefixRank())
201                         return MOD_RES_ALLOW;
202                 if (mh || minmode == '*')
203                         return MOD_RES_DENY;
204                 return MOD_RES_PASSTHRU;
205         }
206
207         void Prioritize() CXX11_OVERRIDE
208         {
209                 ServerInstance->Modules.SetPriority(this, I_OnPostJoin, PRIORITY_FIRST);
210         }
211
212         Version GetVersion() CXX11_OVERRIDE
213         {
214                 return Version("Provides the INVITE, JOIN, KICK, NAMES, and TOPIC commands", VF_VENDOR|VF_CORE);
215         }
216 };
217
218 MODULE_INIT(CoreModChannel)