]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/modules/m_redirect.cpp
Use loopCall to protect OnUserKick rather than the triggerevents hack
[user/henk/code/inspircd.git] / src / modules / m_redirect.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2009 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/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', parameter);
72                         return MODEACTION_ALLOW;
73                 }
74                 else
75                 {
76                         if (channel->IsModeSet('L'))
77                         {
78                                 channel->SetMode('L', "");
79                                 return MODEACTION_ALLOW;
80                         }
81                 }
82
83                 return MODEACTION_DENY;
84
85         }
86 };
87
88 class ModuleRedirect : public Module
89 {
90
91         Redirect* re;
92
93  public:
94
95         ModuleRedirect(InspIRCd* Me)
96                 : Module(Me)
97         {
98
99                 re = new Redirect(ServerInstance);
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 int 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->modes[CM_LIMIT])
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 1;
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(ServerInstance, user, channel.c_str(), false, "", false, ServerInstance->Time());
128                                         return 1;
129                                 }
130                         }
131                 }
132                 return 0;
133         }
134
135         virtual ~ModuleRedirect()
136         {
137                 ServerInstance->Modes->DelMode(re);
138                 delete re;
139         }
140
141         virtual Version GetVersion()
142         {
143                 return Version("$Id$", VF_COMMON | VF_VENDOR, API_VERSION);
144         }
145 };
146
147 MODULE_INIT(ModuleRedirect)