]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_redirect.cpp
Convert WriteNumeric() calls to pass the parameters of the numeric as method parameters
[user/henk/code/inspircd.git] / src / modules / m_redirect.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2012 Shawn Smith <ShawnSmith0828@gmail.com>
5  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
6  *   Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
7  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
8  *   Copyright (C) 2004, 2006 Craig Edwards <craigedwards@brainbox.cc>
9  *   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
10  *
11  * This file is part of InspIRCd.  InspIRCd is free software: you can
12  * redistribute it and/or modify it under the terms of the GNU General Public
13  * License as published by the Free Software Foundation, version 2.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24
25 #include "inspircd.h"
26
27 /** Handle channel mode +L
28  */
29 class Redirect : public ParamMode<Redirect, LocalStringExt>
30 {
31  public:
32         Redirect(Module* Creator)
33                 : ParamMode<Redirect, LocalStringExt>(Creator, "redirect", 'L') { }
34
35         ModeAction OnSet(User* source, Channel* channel, std::string& parameter)
36         {
37                 if (IS_LOCAL(source))
38                 {
39                         if (!ServerInstance->IsChannel(parameter))
40                         {
41                                 source->WriteNumeric(ERR_NOSUCHCHANNEL, parameter, "Invalid channel name");
42                                 return MODEACTION_DENY;
43                         }
44                 }
45
46                 if (IS_LOCAL(source) && !source->IsOper())
47                 {
48                         Channel* c = ServerInstance->FindChan(parameter);
49                         if (!c)
50                         {
51                                 source->WriteNumeric(690, InspIRCd::Format("Target channel %s must exist to be set as a redirect.", parameter.c_str()));
52                                 return MODEACTION_DENY;
53                         }
54                         else if (c->GetPrefixValue(source) < OP_VALUE)
55                         {
56                                 source->WriteNumeric(690, InspIRCd::Format("You must be opped on %s to set it as a redirect.", parameter.c_str()));
57                                 return MODEACTION_DENY;
58                         }
59                 }
60
61                 /*
62                  * We used to do some checking for circular +L here, but there is no real need for this any more especially as we
63                  * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t
64                  */
65                 ext.set(channel, parameter);
66                 return MODEACTION_ALLOW;
67         }
68
69         void SerializeParam(Channel* chan, const std::string* str, std::string& out)
70         {
71                 out += *str;
72         }
73 };
74
75 /** Handles usermode +L to stop forced redirection and print an error.
76 */
77 class AntiRedirect : public SimpleUserModeHandler
78 {
79         public:
80                 AntiRedirect(Module* Creator) : SimpleUserModeHandler(Creator, "antiredirect", 'L')
81                 {
82                         if (!ServerInstance->Config->ConfValue("redirect")->getBool("antiredirect"))
83                                 DisableAutoRegister();
84                 }
85 };
86
87 class ModuleRedirect : public Module
88 {
89         Redirect re;
90         AntiRedirect re_u;
91         ChanModeReference limitmode;
92         bool UseUsermode;
93
94  public:
95         ModuleRedirect()
96                 : re(this)
97                 , re_u(this)
98                 , limitmode(this, "limit")
99         {
100         }
101
102         void init() CXX11_OVERRIDE
103         {
104                 /* Setting this here so it isn't changable by rehasing the config later. */
105                 UseUsermode = ServerInstance->Config->ConfValue("redirect")->getBool("antiredirect");
106         }
107
108         ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE
109         {
110                 if (chan)
111                 {
112                         if (chan->IsModeSet(re) && chan->IsModeSet(limitmode))
113                         {
114                                 if (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter(limitmode)))
115                                 {
116                                         const std::string& channel = *re.ext.get(chan);
117
118                                         /* sometimes broken ulines can make circular or chained +L, avoid this */
119                                         Channel* destchan = ServerInstance->FindChan(channel);
120                                         if (destchan && destchan->IsModeSet(re))
121                                         {
122                                                 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.");
123                                                 return MOD_RES_DENY;
124                                         }
125                                         /* We check the bool value here to make sure we have it enabled, if we don't then
126                                                 usermode +L might be assigned to something else. */
127                                         if (UseUsermode && user->IsModeSet(re_u))
128                                         {
129                                                 user->WriteNumeric(470, cname, channel, "Force redirection stopped.");
130                                                 return MOD_RES_DENY;
131                                         }
132                                         else
133                                         {
134                                                 user->WriteNumeric(470, cname, channel, "You may not join this channel, so you are automatically being transferred to the redirect channel.");
135                                                 Channel::JoinUser(user, channel);
136                                                 return MOD_RES_DENY;
137                                         }
138                                 }
139                         }
140                 }
141                 return MOD_RES_PASSTHRU;
142         }
143
144         Version GetVersion() CXX11_OVERRIDE
145         {
146                 return Version("Provides channel mode +L (limit redirection) and user mode +L (no forced redirection)", VF_VENDOR);
147         }
148 };
149
150 MODULE_INIT(ModuleRedirect)