]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_redirect.cpp
Sync helpop chmodes s and p with docs
[user/henk/code/inspircd.git] / src / modules / m_redirect.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2017 B00mX0r <b00mx0r@aureus.pw>
5  *   Copyright (C) 2013, 2017, 2019 Sadie Powell <sadie@witchery.services>
6  *   Copyright (C) 2012-2014, 2016 Attila Molnar <attilamolnar@hush.com>
7  *   Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
8  *   Copyright (C) 2012, 2014 Shawn Smith <ShawnSmith0828@gmail.com>
9  *   Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
10  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
11  *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
12  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
13  *   Copyright (C) 2004, 2006, 2010 Craig Edwards <brain@inspircd.org>
14  *
15  * This file is part of InspIRCd.  InspIRCd is free software: you can
16  * redistribute it and/or modify it under the terms of the GNU General Public
17  * License as published by the Free Software Foundation, version 2.
18  *
19  * This program is distributed in the hope that it will be useful, but WITHOUT
20  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
22  * details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
26  */
27
28
29 #include "inspircd.h"
30
31 /** Handle channel mode +L
32  */
33 class Redirect : public ParamMode<Redirect, LocalStringExt>
34 {
35  public:
36         Redirect(Module* Creator)
37                 : ParamMode<Redirect, LocalStringExt>(Creator, "redirect", 'L')
38         {
39                 syntax = "<target>";
40         }
41
42         ModeAction OnSet(User* source, Channel* channel, std::string& parameter) CXX11_OVERRIDE
43         {
44                 if (IS_LOCAL(source))
45                 {
46                         if (!ServerInstance->IsChannel(parameter))
47                         {
48                                 source->WriteNumeric(Numerics::NoSuchChannel(parameter));
49                                 return MODEACTION_DENY;
50                         }
51                 }
52
53                 if (IS_LOCAL(source) && !source->IsOper())
54                 {
55                         Channel* c = ServerInstance->FindChan(parameter);
56                         if (!c)
57                         {
58                                 source->WriteNumeric(690, InspIRCd::Format("Target channel %s must exist to be set as a redirect.", parameter.c_str()));
59                                 return MODEACTION_DENY;
60                         }
61                         else if (c->GetPrefixValue(source) < OP_VALUE)
62                         {
63                                 source->WriteNumeric(690, InspIRCd::Format("You must be opped on %s to set it as a redirect.", parameter.c_str()));
64                                 return MODEACTION_DENY;
65                         }
66                 }
67
68                 /*
69                  * We used to do some checking for circular +L here, but there is no real need for this any more especially as we
70                  * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t
71                  */
72                 ext.set(channel, parameter);
73                 return MODEACTION_ALLOW;
74         }
75
76         void SerializeParam(Channel* chan, const std::string* str, std::string& out)
77         {
78                 out += *str;
79         }
80 };
81
82 class ModuleRedirect : public Module
83 {
84         Redirect re;
85         SimpleUserModeHandler antiredirectmode;
86         ChanModeReference limitmode;
87
88  public:
89         ModuleRedirect()
90                 : re(this)
91                 , antiredirectmode(this, "antiredirect", 'L')
92                 , limitmode(this, "limit")
93         {
94         }
95
96         ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
97         {
98                 if (chan)
99                 {
100                         if (chan->IsModeSet(re) && chan->IsModeSet(limitmode))
101                         {
102                                 if (chan->GetUserCounter() >= ConvToNum<size_t>(chan->GetModeParameter(limitmode)))
103                                 {
104                                         const std::string& channel = *re.ext.get(chan);
105
106                                         /* sometimes broken ulines can make circular or chained +L, avoid this */
107                                         Channel* destchan = ServerInstance->FindChan(channel);
108                                         if (destchan && destchan->IsModeSet(re))
109                                         {
110                                                 user->WriteNumeric(470, cname, '*', "You may not join this channel. A redirect is set, but you may not be redirected as it is a circular loop.");
111                                                 return MOD_RES_DENY;
112                                         }
113
114                                         if (user->IsModeSet(antiredirectmode))
115                                         {
116                                                 user->WriteNumeric(470, cname, channel, "Force redirection stopped.");
117                                                 return MOD_RES_DENY;
118                                         }
119                                         else
120                                         {
121                                                 user->WriteNumeric(470, cname, channel, "You may not join this channel, so you are automatically being transferred to the redirected channel.");
122                                                 Channel::JoinUser(user, channel);
123                                                 return MOD_RES_DENY;
124                                         }
125                                 }
126                         }
127                 }
128                 return MOD_RES_PASSTHRU;
129         }
130
131         Version GetVersion() CXX11_OVERRIDE
132         {
133                 return Version("Allows users to be redirected to another channel when the user limit is reached.", VF_VENDOR);
134         }
135 };
136
137 MODULE_INIT(ModuleRedirect)