]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_redirect.cpp
Use freenode's 470 numeric for redirection.
[user/henk/code/inspircd.git] / src / modules / m_redirect.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2008 InspIRCd Development Team
6  * See: http://www.inspircd.org/wiki/index.php/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15
16 /* $ModDesc: Provides channel mode +L (limit redirection) */
17
18 /** Handle channel mode +L
19  */
20 class Redirect : public ModeHandler
21 {
22  public:
23         Redirect(InspIRCd* Instance) : ModeHandler(Instance, 'L', 1, 0, false, MODETYPE_CHANNEL, false) { }
24
25         ModePair ModeSet(User* source, User* dest, Channel* channel, const std::string &parameter)
26         {
27                 if (channel->IsModeSet('L'))
28                         return std::make_pair(true, channel->GetModeParameter('L'));
29                 else
30                         return std::make_pair(false, parameter);
31         }
32
33         bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, Channel* channel)
34         {
35                 /* When TS is equal, the alphabetically later one wins */
36                 return (their_param < our_param);
37         }
38
39         ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, bool adding, bool)
40         {
41                 if (adding)
42                 {
43                         Channel* c = NULL;
44
45                         if (IS_LOCAL(source) && !ServerInstance->IsChannel(parameter.c_str(), ServerInstance->Config->Limits.ChanMax))
46                         {
47                                 source->WriteNumeric(403, "%s %s :Invalid channel name", source->nick.c_str(), parameter.c_str());
48                                 parameter.clear();
49                                 return MODEACTION_DENY;
50                         }
51
52                         c = ServerInstance->FindChan(parameter);
53                         if (!c && !IS_OPER(source))
54                         {
55                                 source->WriteNumeric(690, "%s :Target channel %s must exist to be set as a redirect.",source->nick.c_str(),parameter.c_str());
56                                 parameter.clear();
57                                 return MODEACTION_DENY;
58                         }
59
60                         if (c && c->GetStatus(source) < STATUS_OP && !IS_OPER(source))
61                         {
62                                 source->WriteNumeric(690, "%s :You must be opped on %s to set it as a redirect.",source->nick.c_str(),parameter.c_str());
63                                 parameter.clear();
64                                 return MODEACTION_DENY;
65                         }
66
67                         /*
68                          * We used to do some checking for circular +L here, but there is no real need for this any more especially as we
69                          * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t
70                          */
71                         channel->SetMode('L', true);
72                         channel->SetModeParam('L', parameter.c_str(), true);
73                         return MODEACTION_ALLOW;
74                 }
75                 else
76                 {
77                         if (channel->IsModeSet('L'))
78                         {
79                                 channel->SetMode('L', false);
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(InspIRCd* Me)
97                 : Module(Me)
98         {
99
100                 re = new Redirect(ServerInstance);
101                 if (!ServerInstance->Modes->AddMode(re))
102                         throw ModuleException("Could not add new modes!");
103                 Implementation eventlist[] = { I_OnUserPreJoin };
104                 ServerInstance->Modules->Attach(eventlist, this, 1);
105         }
106
107
108         virtual int OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
109         {
110                 if (chan)
111                 {
112                         if (chan->IsModeSet('L') && chan->modes[CM_LIMIT])
113                         {
114                                 if (chan->GetUserCounter() >= atoi(chan->GetModeParameter('l').c_str()))
115                                 {
116                                         std::string channel = chan->GetModeParameter('L');
117
118                                         /* sometimes broken ulines can make circular or chained +L, avoid this */
119                                         Channel* destchan = NULL;
120                                         destchan = ServerInstance->FindChan(channel);
121                                         if (destchan && destchan->IsModeSet('L'))
122                                         {
123                                                 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);
124                                                 return 1;
125                                         }
126
127                                         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());
128                                         Channel::JoinUser(ServerInstance, user, channel.c_str(), false, "", false, ServerInstance->Time());
129                                         return 1;
130                                 }
131                         }
132                 }
133                 return 0;
134         }
135
136         virtual ~ModuleRedirect()
137         {
138                 ServerInstance->Modes->DelMode(re);
139                 delete re;
140         }
141
142         virtual Version GetVersion()
143         {
144                 return Version("$Id$", VF_COMMON | VF_VENDOR, API_VERSION);
145         }
146 };
147
148 MODULE_INIT(ModuleRedirect)