cs_ban.cpp

Go to the documentation of this file.
00001 /* ChanServ core functions
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  */
00011 
00012 /*************************************************************************/
00013 
00014 #include "module.h"
00015 
00016 static Module *me;
00017 
00018 class TempBan : public CallBack
00019 {
00020  private:
00021         Anope::string channel;
00022         Anope::string mask;
00023 
00024  public:
00025         TempBan(time_t seconds, Channel *c, const Anope::string &banmask) : CallBack(me, seconds), channel(c->name), mask(banmask) { }
00026 
00027         void Tick(time_t ctime) anope_override
00028         {
00029                 Channel *c = Channel::Find(this->channel);
00030                 if (c)
00031                         c->RemoveMode(NULL, "BAN", this->mask);
00032         }
00033 };
00034 
00035 class CommandCSBan : public Command
00036 {
00037  public:
00038         CommandCSBan(Module *creator) : Command(creator, "chanserv/ban", 2, 4)
00039         {
00040                 this->SetDesc(_("Bans a given nick or mask on a channel"));
00041                 this->SetSyntax(_("\037channel\037 [+\037expiry\037] \037nick\037 [\037reason\037]"));
00042                 this->SetSyntax(_("\037channel\037 [+\037expiry\037] \037mask\037 [\037reason\037]"));
00043         }
00044 
00045         void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
00046         {
00047                 const Anope::string &chan = params[0];
00048 
00049                 ChannelInfo *ci = ChannelInfo::Find(chan);
00050                 if (ci == NULL)
00051                 {
00052                         source.Reply(CHAN_X_NOT_REGISTERED, chan.c_str());
00053                         return;
00054                 }
00055 
00056                 Anope::string expiry, target, reason;
00057                 time_t ban_time;
00058                 if (params[1][0] == '+')
00059                 {
00060                         ban_time = Anope::DoTime(params[1]);
00061                         if (params.size() < 3)
00062                         {
00063                                 this->SendSyntax(source);
00064                                 return;
00065                         }
00066                         target = params[2];
00067                         reason = "Requested";
00068                         if (params.size() > 3)
00069                                 reason = params[3];
00070                 }
00071                 else
00072                 {
00073                         ban_time = 0;
00074                         target = params[1];
00075                         reason = "Requested";
00076                         if (params.size() > 2)
00077                                 reason = params[2];
00078                         if (params.size() > 3)
00079                                 reason += " " + params[3];
00080                 }
00081 
00082                 if (reason.length() > Config->CSReasonMax)
00083                         reason = reason.substr(0, Config->CSReasonMax);
00084 
00085                 Channel *c = ci->c;
00086                 User *u = source.GetUser();
00087                 User *u2 = User::Find(target, true);
00088 
00089                 AccessGroup u_access = source.AccessFor(ci);
00090 
00091                 if (!c)
00092                         source.Reply(CHAN_X_NOT_IN_USE, chan.c_str());
00093                 else if (!u_access.HasPriv("BAN") && !source.HasPriv("chanserv/kick"))
00094                         source.Reply(ACCESS_DENIED);
00095                 else if (u2)
00096                 {
00097                         AccessGroup u2_access = ci->AccessFor(u2);
00098 
00099                         if (u != u2 && ci->HasExt("PEACE") && u2_access >= u_access && !source.HasPriv("chanserv/kick"))
00100                                 source.Reply(ACCESS_DENIED);
00101                         /*
00102                          * Dont ban/kick the user on channels where he is excepted
00103                          * to prevent services <-> server wars.
00104                          */
00105                         else if (ci->c->MatchesList(u2, "EXCEPT"))
00106                                 source.Reply(CHAN_EXCEPTED, u2->nick.c_str(), ci->name.c_str());
00107                         else if (u2->IsProtected())
00108                                 source.Reply(ACCESS_DENIED);
00109                         else
00110                         {
00111                                 Anope::string mask = ci->GetIdealBan(u2);
00112 
00113                                 bool override = !u_access.HasPriv("BAN") || (u != u2 && ci->HasExt("PEACE") && u2_access >= u_access);
00114                                 Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << mask;
00115 
00116                                 if (!c->HasMode("BAN", mask))
00117                                 {
00118                                         c->SetMode(NULL, "BAN", mask);
00119                                         if (ban_time)
00120                                         {
00121                                                 new TempBan(ban_time, c, mask);
00122                                                 source.Reply(_("Ban on \002%s\002 expires in %s."), mask.c_str(), Anope::Duration(ban_time, source.GetAccount()).c_str());
00123                                         }
00124                                 }
00125 
00126                                 /* We still allow host banning while not allowing to kick */
00127                                 if (!c->FindUser(u2))
00128                                         return;
00129 
00130                                 if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !source.AccessFor(ci).HasPriv("SIGNKICK")))
00131                                         c->Kick(ci->WhoSends(), u2, "%s (%s)", reason.c_str(), source.GetNick().c_str());
00132                                 else
00133                                         c->Kick(ci->WhoSends(), u2, "%s", reason.c_str());
00134                         }
00135                 }
00136                 else if (u_access.HasPriv("FOUNDER"))
00137                 {
00138                         Log(LOG_COMMAND, source, this, ci) << "for " << target;
00139 
00140                         if (!c->HasMode("BAN", target))
00141                         {
00142                                 c->SetMode(NULL, "BAN", target);
00143                                 if (ban_time)
00144                                 {
00145                                         new TempBan(ban_time, c, target);
00146                                         source.Reply(_("Ban on \002%s\002 expires in %s."), target.c_str(), Anope::Duration(ban_time, source.GetAccount()).c_str());
00147                                 }
00148                         }
00149 
00150                         int matched = 0, kicked = 0;
00151                         for (Channel::ChanUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end;)
00152                         {
00153                                 ChanUserContainer *uc = *it++;
00154 
00155                                 if (Anope::Match(uc->user->nick, target) || Anope::Match(uc->user->GetDisplayedMask(), target))
00156                                 {
00157                                         ++matched;
00158 
00159                                         AccessGroup u2_access = ci->AccessFor(uc->user);
00160 
00161                                         if (u != uc->user && ci->HasExt("PEACE") && u2_access >= u_access)
00162                                                 continue;
00163                                         else if (ci->c->MatchesList(uc->user, "EXCEPT"))
00164                                                 continue;
00165                                         else if (uc->user->IsProtected())
00166                                                 continue;
00167 
00168                                         ++kicked;
00169                                         if (ci->HasExt("SIGNKICK") || (ci->HasExt("SIGNKICK_LEVEL") && !u_access.HasPriv("SIGNKICK")))
00170                                                 c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s) (%s)", reason.c_str(), target.c_str(), source.GetNick().c_str());
00171                                         else
00172                                                 c->Kick(ci->WhoSends(), uc->user, "%s (Matches %s)", reason.c_str(), target.c_str());
00173                                 }
00174                         }
00175 
00176                         if (matched)
00177                                 source.Reply(_("Kicked %d/%d users matching %s from %s."), kicked, matched, target.c_str(), c->name.c_str());
00178                         else
00179                                 source.Reply(_("No users on %s match %s."), c->name.c_str(), target.c_str());
00180                 }
00181                 else
00182                         source.Reply(NICK_X_NOT_IN_USE, target.c_str());
00183         }
00184 
00185         bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
00186         {
00187                 this->SendSyntax(source);
00188                 source.Reply(" ");
00189                 source.Reply(_("Bans a given nick or mask on a channel. An optional expiry may\n"
00190                                 "be given to cause services to remove the ban after a set amount\n"
00191                                 "of time.\n"
00192                                 " \n"
00193                                 "By default, limited to AOPs or those with level 5 access\n"
00194                                 "and above on the channel. Channel founders may ban masks."));
00195                 return true;
00196         }
00197 };
00198 
00199 class CSBan : public Module
00200 {
00201         CommandCSBan commandcsban;
00202 
00203  public:
00204         CSBan(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, CORE), commandcsban(this)
00205         {
00206                 this->SetAuthor("Anope");
00207                 me = this;
00208         }
00209 };
00210 
00211 MODULE_INIT(CSBan)