]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_auditorium.cpp
m_check: remove unnecessary usage of CheckContext::List.
[user/henk/code/inspircd.git] / src / modules / m_auditorium.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007-2008 Craig Edwards <craigedwards@brainbox.cc>
6  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
7  *   Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
8  *
9  * This file is part of InspIRCd.  InspIRCd is free software: you can
10  * redistribute it and/or modify it under the terms of the GNU General Public
11  * License as published by the Free Software Foundation, version 2.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22
23 #include "inspircd.h"
24 #include "modules/exemption.h"
25 #include "modules/who.h"
26
27 class AuditoriumMode : public SimpleChannelModeHandler
28 {
29  public:
30         AuditoriumMode(Module* Creator) : SimpleChannelModeHandler(Creator, "auditorium", 'u')
31         {
32                 ranktoset = ranktounset = OP_VALUE;
33         }
34 };
35
36 class ModuleAuditorium;
37
38 namespace
39 {
40
41 /** Hook handler for join client protocol events.
42  * This allows us to block join protocol events completely, including all associated messages (e.g. MODE, away-notify AWAY).
43  * This is not the same as OnUserJoin() because that runs only when a real join happens but this runs also when a module
44  * such as delayjoin or hostcycle generates a join.
45  */
46 class JoinHook : public ClientProtocol::EventHook
47 {
48         ModuleAuditorium* const parentmod;
49         bool active;
50
51  public:
52         JoinHook(ModuleAuditorium* mod);
53         void OnEventInit(const ClientProtocol::Event& ev) CXX11_OVERRIDE;
54         ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE;
55 };
56
57 }
58
59 class ModuleAuditorium
60         : public Module
61         , public Who::EventListener
62 {
63         CheckExemption::EventProvider exemptionprov;
64         AuditoriumMode aum;
65         bool OpsVisible;
66         bool OpsCanSee;
67         bool OperCanSee;
68         JoinHook joinhook;
69
70  public:
71         ModuleAuditorium()
72                 : Who::EventListener(this)
73                 , exemptionprov(this)
74                 , aum(this)
75                 , joinhook(this)
76         {
77         }
78
79         void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
80         {
81                 ConfigTag* tag = ServerInstance->Config->ConfValue("auditorium");
82                 OpsVisible = tag->getBool("opvisible");
83                 OpsCanSee = tag->getBool("opcansee");
84                 OperCanSee = tag->getBool("opercansee", true);
85         }
86
87         Version GetVersion() CXX11_OVERRIDE
88         {
89                 return Version("Allows for auditorium channels (+u) where nobody can see others joining and parting or the nick list", VF_VENDOR);
90         }
91
92         /* Can they be seen by everyone? */
93         bool IsVisible(Membership* memb)
94         {
95                 if (!memb->chan->IsModeSet(&aum))
96                         return true;
97
98                 ModResult res = CheckExemption::Call(exemptionprov, memb->user, memb->chan, "auditorium-vis");
99                 return res.check(OpsVisible && memb->getRank() >= OP_VALUE);
100         }
101
102         /* Can they see this specific membership? */
103         bool CanSee(User* issuer, Membership* memb)
104         {
105                 // If user is oper and operoverride is on, don't touch the list
106                 if (OperCanSee && issuer->HasPrivPermission("channels/auspex"))
107                         return true;
108
109                 // You can always see yourself
110                 if (issuer == memb->user)
111                         return true;
112
113                 // Can you see the list by permission?
114                 ModResult res = CheckExemption::Call(exemptionprov, issuer, memb->chan, "auditorium-see");
115                 if (res.check(OpsCanSee && memb->chan->GetPrefixValue(issuer) >= OP_VALUE))
116                         return true;
117
118                 return false;
119         }
120
121         ModResult OnNamesListItem(User* issuer, Membership* memb, std::string& prefixes, std::string& nick) CXX11_OVERRIDE
122         {
123                 if (IsVisible(memb))
124                         return MOD_RES_PASSTHRU;
125
126                 if (CanSee(issuer, memb))
127                         return MOD_RES_PASSTHRU;
128
129                 // Don't display this user in the NAMES list
130                 return MOD_RES_DENY;
131         }
132
133         /** Build CUList for showing this join/part/kick */
134         void BuildExcept(Membership* memb, CUList& excepts)
135         {
136                 if (IsVisible(memb))
137                         return;
138
139                 const Channel::MemberMap& users = memb->chan->GetUsers();
140                 for (Channel::MemberMap::const_iterator i = users.begin(); i != users.end(); ++i)
141                 {
142                         if (IS_LOCAL(i->first) && !CanSee(i->first, memb))
143                                 excepts.insert(i->first);
144                 }
145         }
146
147         void OnUserPart(Membership* memb, std::string &partmessage, CUList& excepts) CXX11_OVERRIDE
148         {
149                 BuildExcept(memb, excepts);
150         }
151
152         void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE
153         {
154                 BuildExcept(memb, excepts);
155         }
156
157         void OnBuildNeighborList(User* source, IncludeChanList& include, std::map<User*, bool>& exception) CXX11_OVERRIDE
158         {
159                 for (IncludeChanList::iterator i = include.begin(); i != include.end(); )
160                 {
161                         Membership* memb = *i;
162                         if (IsVisible(memb))
163                         {
164                                 ++i;
165                                 continue;
166                         }
167
168                         // this channel should not be considered when listing my neighbors
169                         i = include.erase(i);
170                         // however, that might hide me from ops that can see me...
171                         const Channel::MemberMap& users = memb->chan->GetUsers();
172                         for(Channel::MemberMap::const_iterator j = users.begin(); j != users.end(); ++j)
173                         {
174                                 if (IS_LOCAL(j->first) && CanSee(j->first, memb))
175                                         exception[j->first] = true;
176                         }
177                 }
178         }
179
180         ModResult OnWhoLine(const Who::Request& request, LocalUser* source, User* user, Membership* memb, Numeric::Numeric& numeric) CXX11_OVERRIDE
181         {
182                 if (!memb)
183                         return MOD_RES_PASSTHRU;
184                 if (IsVisible(memb))
185                         return MOD_RES_PASSTHRU;
186                 if (CanSee(source, memb))
187                         return MOD_RES_PASSTHRU;
188                 return MOD_RES_DENY;
189         }
190 };
191
192 JoinHook::JoinHook(ModuleAuditorium* mod)
193         : ClientProtocol::EventHook(mod, "JOIN", 10)
194         , parentmod(mod)
195 {
196 }
197
198 void JoinHook::OnEventInit(const ClientProtocol::Event& ev)
199 {
200         const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev);
201         active = !parentmod->IsVisible(join.GetMember());
202 }
203
204 ModResult JoinHook::OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist)
205 {
206         if (!active)
207                 return MOD_RES_PASSTHRU;
208
209         const ClientProtocol::Events::Join& join = static_cast<const ClientProtocol::Events::Join&>(ev);
210         return ((parentmod->CanSee(user, join.GetMember())) ? MOD_RES_PASSTHRU : MOD_RES_DENY);
211 }
212
213 MODULE_INIT(ModuleAuditorium)