00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "inspircd.h"
00015 #include "u_listmode.h"
00016
00017
00018
00019
00020
00021
00022
00023 class BanRedirectEntry : public classbase
00024 {
00025 public:
00026 std::string targetchan;
00027 std::string banmask;
00028
00029 BanRedirectEntry(const std::string &target = "", const std::string &mask = "")
00030 : targetchan(target), banmask(mask)
00031 {
00032 }
00033 };
00034
00035 typedef std::vector<BanRedirectEntry> BanRedirectList;
00036 typedef std::deque<std::string> StringDeque;
00037
00038 class BanRedirect : public ModeWatcher
00039 {
00040 private:
00041 InspIRCd* Srv;
00042 public:
00043 BanRedirect(InspIRCd* Instance)
00044 : ModeWatcher(Instance, 'b', MODETYPE_CHANNEL), Srv(Instance)
00045 {
00046 }
00047
00048 bool BeforeMode(User* source, User* dest, Channel* channel, std::string ¶m, bool adding, ModeType type, bool)
00049 {
00050
00051
00052
00053
00054
00055
00056
00057 if(channel && (type == MODETYPE_CHANNEL) && param.length())
00058 {
00059 BanRedirectList* redirects;
00060
00061 std::string mask[4];
00062 enum { NICK, IDENT, HOST, CHAN } current = NICK;
00063 std::string::iterator start_pos = param.begin();
00064 long maxbans = channel->GetMaxBans();
00065
00066 if (param.length() >= 2 && param[1] == ':')
00067 return true;
00068
00069 if(adding && (channel->bans.size() > static_cast<unsigned>(maxbans)))
00070 {
00071 source->WriteNumeric(478, "%s %s :Channel ban list for %s is full (maximum entries for this channel is %ld)", source->nick.c_str(), channel->name.c_str(), channel->name.c_str(), maxbans);
00072 return false;
00073 }
00074
00075 for(std::string::iterator curr = start_pos; curr != param.end(); curr++)
00076 {
00077 switch(*curr)
00078 {
00079 case '!':
00080 mask[current].assign(start_pos, curr);
00081 current = IDENT;
00082 start_pos = curr+1;
00083 break;
00084 case '@':
00085 mask[current].assign(start_pos, curr);
00086 current = HOST;
00087 start_pos = curr+1;
00088 break;
00089 case '#':
00090 mask[current].assign(start_pos, curr);
00091 current = CHAN;
00092 start_pos = curr;
00093 break;
00094 }
00095 }
00096
00097 if(mask[current].empty())
00098 {
00099 mask[current].assign(start_pos, param.end());
00100 }
00101
00102
00103 if(mask[NICK].length() && mask[HOST].length() && mask[IDENT].empty())
00104 {
00105
00106 mask[NICK].swap(mask[IDENT]);
00107 }
00108
00109 for(int i = 0; i < 3; i++)
00110 {
00111 if(mask[i].empty())
00112 {
00113 mask[i].assign("*");
00114 }
00115 }
00116
00117 param.assign(mask[NICK]).append(1, '!').append(mask[IDENT]).append(1, '@').append(mask[HOST]);
00118
00119 if(mask[CHAN].length())
00120 {
00121 if(!IS_LOCAL(source) || Srv->IsChannel(mask[CHAN].c_str(), ServerInstance->Config->Limits.ChanMax))
00122 {
00123 if (assign(channel->name) == mask[CHAN])
00124 {
00125 source->WriteNumeric(690, "%s %s :You cannot set a ban redirection to the channel the ban is on", source->nick.c_str(), channel->name.c_str());
00126 return false;
00127 }
00128 else
00129 {
00130 if(adding)
00131 {
00132
00133 if(!channel->GetExt("banredirects", redirects))
00134 {
00135 redirects = new BanRedirectList;
00136 channel->Extend("banredirects", redirects);
00137 }
00138
00139
00140 redirects->push_back(BanRedirectEntry(mask[CHAN].c_str(), param.c_str()));
00141
00142
00143 param.append(mask[CHAN]);
00144 }
00145 else
00146 {
00147
00148 if(channel->GetExt("banredirects", redirects))
00149 {
00150
00151
00152 for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)
00153 {
00154
00155 if((irc::string(redir->targetchan.c_str()) == irc::string(mask[CHAN].c_str())) && (irc::string(redir->banmask.c_str()) == irc::string(param.c_str())))
00156 {
00157 redirects->erase(redir);
00158
00159 if(redirects->empty())
00160 {
00161 delete redirects;
00162 channel->Shrink("banredirects");
00163 }
00164
00165 break;
00166 }
00167 }
00168 }
00169
00170
00171 param.append(mask[CHAN]);
00172 }
00173 }
00174 }
00175 else
00176 {
00177 source->WriteNumeric(403, "%s %s :Invalid channel name in redirection (%s)", source->nick.c_str(), channel->name.c_str(), mask[CHAN].c_str());
00178 return false;
00179 }
00180 }
00181 }
00182
00183 return true;
00184 }
00185 };
00186
00187 class ModuleBanRedirect : public Module
00188 {
00189 BanRedirect* re;
00190 bool nofollow;
00191 Module* ExceptionModule;
00192
00193 public:
00194 ModuleBanRedirect(InspIRCd* Me)
00195 : Module(Me)
00196 {
00197 re = new BanRedirect(Me);
00198 nofollow = false;
00199
00200 if(!ServerInstance->Modes->AddModeWatcher(re))
00201 {
00202 delete re;
00203 throw ModuleException("Could not add mode watcher");
00204 }
00205
00206 OnRehash(NULL, "");
00207
00208 Implementation list[] = { I_OnRehash, I_OnUserPreJoin, I_OnChannelDelete, I_OnCleanup };
00209 Me->Modules->Attach(list, this, 4);
00210
00211 }
00212
00213 virtual void OnChannelDelete(Channel* chan)
00214 {
00215 OnCleanup(TYPE_CHANNEL, chan);
00216 }
00217
00218 virtual void OnCleanup(int target_type, void* item)
00219 {
00220 if(target_type == TYPE_CHANNEL)
00221 {
00222 Channel* chan = static_cast<Channel*>(item);
00223 BanRedirectList* redirects;
00224
00225 if(chan->GetExt("banredirects", redirects))
00226 {
00227 irc::modestacker modestack(ServerInstance, false);
00228 StringDeque stackresult;
00229 std::vector<std::string> mode_junk;
00230 mode_junk.push_back(chan->name);
00231
00232 for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
00233 {
00234 modestack.Push('b', i->targetchan.insert(0, i->banmask));
00235 }
00236
00237 for(BanRedirectList::iterator i = redirects->begin(); i != redirects->end(); i++)
00238 {
00239 modestack.PushPlus();
00240 modestack.Push('b', i->banmask);
00241 }
00242
00243 while(modestack.GetStackedLine(stackresult))
00244 {
00245 for(StringDeque::size_type i = 0; i < stackresult.size(); i++)
00246 {
00247 mode_junk.push_back(stackresult[i]);
00248 }
00249
00250 ServerInstance->SendMode(mode_junk, ServerInstance->FakeClient);
00251 }
00252
00253 delete redirects;
00254 chan->Shrink("banredirects");
00255 }
00256 }
00257 }
00258
00259 virtual void OnRehash(User* user, const std::string ¶m)
00260 {
00261 ExceptionModule = ServerInstance->Modules->Find("m_banexception.so");
00262 }
00263
00264 virtual int OnUserPreJoin(User* user, Channel* chan, const char* cname, std::string &privs, const std::string &keygiven)
00265 {
00266
00267
00268
00269 if (nofollow)
00270 return 0;
00271
00272
00273 if (chan)
00274 {
00275 BanRedirectList* redirects;
00276
00277 if(chan->GetExt("banredirects", redirects))
00278 {
00279
00280
00281
00282
00283
00284
00285 if (ExceptionModule)
00286 {
00287 ListModeRequest n(this, ExceptionModule, user, chan);
00288
00289 if (n.Send())
00290 return 0;
00291 }
00292
00293 std::string ipmask(user->nick);
00294 ipmask.append(1, '!').append(user->MakeHostIP());
00295
00296 for(BanRedirectList::iterator redir = redirects->begin(); redir != redirects->end(); redir++)
00297 {
00298 if(InspIRCd::Match(user->GetFullRealHost(), redir->banmask) || InspIRCd::Match(user->GetFullHost(), redir->banmask) || InspIRCd::MatchCIDR(ipmask, redir->banmask))
00299 {
00300
00301 Channel* destchan = ServerInstance->FindChan(redir->targetchan);
00302 std::string destlimit;
00303
00304 if (destchan)
00305 destlimit = destchan->GetModeParameter('l');
00306
00307 if(destchan && ServerInstance->Modules->Find("m_redirect.so") && destchan->IsModeSet('L') && !destlimit.empty() && (destchan->GetUserCounter() >= atoi(destlimit.c_str())))
00308 {
00309 user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str());
00310 return 1;
00311 }
00312 else
00313 {
00314 user->WriteNumeric(474, "%s %s :Cannot join channel (You are banned)", user->nick.c_str(), chan->name.c_str());
00315 user->WriteNumeric(470, "%s :You are being automatically redirected to %s", user->nick.c_str(), redir->targetchan.c_str());
00316 nofollow = true;
00317 Channel::JoinUser(ServerInstance, user, redir->targetchan.c_str(), false, "", false, ServerInstance->Time());
00318 nofollow = false;
00319 return 1;
00320 }
00321 }
00322 }
00323 }
00324 }
00325 return 0;
00326 }
00327
00328 virtual ~ModuleBanRedirect()
00329 {
00330 ServerInstance->Modes->DelModeWatcher(re);
00331 delete re;
00332 }
00333
00334 virtual Version GetVersion()
00335 {
00336 return Version("$Id: m_banredirect.cpp 10415 2008-09-06 13:36:09Z brain $", VF_COMMON | VF_VENDOR, API_VERSION);
00337 }
00338
00339 void Prioritize()
00340 {
00341 Module* banex = ServerInstance->Modules->Find("m_banexception.so");
00342 ServerInstance->Modules->SetPriority(this, I_OnUserPreJoin, PRIO_BEFORE, &banex);
00343 }
00344 };
00345
00346 MODULE_INIT(ModuleBanRedirect)