]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_redirect.cpp
Merge pull request #109 from Justasic/insp20
[user/henk/code/inspircd.git] / src / modules / m_redirect.cpp
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2009 Daniel De Graaf <danieldg@inspircd.org>
5  *   Copyright (C) 2007-2008 Robin Burchell <robin+git@viroteck.net>
6  *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
7  *   Copyright (C) 2004, 2006 Craig Edwards <craigedwards@brainbox.cc>
8  *   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
9  *
10  * This file is part of InspIRCd.  InspIRCd is free software: you can
11  * redistribute it and/or modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation, version 2.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23
24 #include "inspircd.h"
25
26 /* $ModDesc: Provides channel mode +L (limit redirection) */
27
28 /** Handle channel mode +L
29  */
30 class Redirect : public ModeHandler
31 {
32  public:
33         Redirect(Module* Creator) : ModeHandler(Creator, "redirect", 'L', PARAM_SETONLY, MODETYPE_CHANNEL) { }
34
35         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding)
36         {
37                 if (adding)
38                 {
39                         if (IS_LOCAL(source))
40                         {
41                                 if (!ServerInstance->IsChannel(parameter.c_str(), ServerInstance->Config->Limits.ChanMax))
42                                 {
43                                         source->WriteNumeric(403, "%s %s :Invalid channel name", source->nick.c_str(), parameter.c_str());
44                                         parameter.clear();
45                                         return MODEACTION_DENY;
46                                 }
47                         }
48
49                         if (IS_LOCAL(source) && !IS_OPER(source))
50                         {
51                                 Channel* c = ServerInstance->FindChan(parameter);
52                                 if (!c)
53                                 {
54                                         source->WriteNumeric(690, "%s :Target channel %s must exist to be set as a redirect.",source->nick.c_str(),parameter.c_str());
55                                         parameter.clear();
56                                         return MODEACTION_DENY;
57                                 }
58                                 else if (c->GetPrefixValue(source) < OP_VALUE)
59                                 {
60                                         source->WriteNumeric(690, "%s :You must be opped on %s to set it as a redirect.",source->nick.c_str(),parameter.c_str());
61                                         parameter.clear();
62                                         return MODEACTION_DENY;
63                                 }
64                         }
65
66                         if (channel->GetModeParameter('L') == parameter)
67                                 return MODEACTION_DENY;
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                         channel->SetModeParam('L', parameter);
73                         return MODEACTION_ALLOW;
74                 }
75                 else
76                 {
77                         if (channel->IsModeSet('L'))
78                         {
79                                 channel->SetModeParam('L', "");
80                                 return MODEACTION_ALLOW;
81                         }
82                 }
83
84                 return MODEACTION_DENY;
85
86         }
87 };
88
89 class ModuleRedirect : public Module
90 {
91
92         Redirect re;
93
94  public:
95
96         ModuleRedirect()
97                 : re(this)
98         {
99
100                 if (!ServerInstance->Modes->AddMode(&re))
101                         throw ModuleException("Could not add new modes!");
102                 Implementation eventlist[] = { I_OnUserPreJoin };
103                 ServerInstance->Modules->Attach(eventlist, this, 1);
104         }
105
106
107         virtual ModResult OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
108         {
109                 if (chan)
110                 {
111                         if (chan->IsModeSet('L') && chan->IsModeSet('l'))
112                         {
113                                 if (chan->GetUserCounter() >= atoi(chan->GetModeParameter('l').c_str()))
114                                 {
115                                         std::string channel = chan->GetModeParameter('L');
116
117                                         /* sometimes broken ulines can make circular or chained +L, avoid this */
118                                         Channel* destchan = NULL;
119                                         destchan = ServerInstance->FindChan(channel);
120                                         if (destchan && destchan->IsModeSet('L'))
121                                         {
122                                                 user->WriteNumeric(470, "%s %s * :You may not join this channel. A redirect is set, but you may not be redirected as it is a circular loop.", user->nick.c_str(), cname);
123                                                 return MOD_RES_DENY;
124                                         }
125
126                                         user->WriteNumeric(470, "%s %s %s :You may not join this channel, so you are automatically being transferred to the redirect channel.", user->nick.c_str(), cname, channel.c_str());
127                                         Channel::JoinUser(user, channel.c_str(), false, "", false, ServerInstance->Time());
128                                         return MOD_RES_DENY;
129                                 }
130                         }
131                 }
132                 return MOD_RES_PASSTHRU;
133         }
134
135         virtual ~ModuleRedirect()
136         {
137         }
138
139         virtual Version GetVersion()
140         {
141                 return Version("Provides channel mode +L (limit redirection)", VF_VENDOR);
142         }
143 };
144
145 MODULE_INIT(ModuleRedirect)