/*
* Anope IRC Services
*
* Copyright (C) 2005-2016 Anope Team <team@anope.org>
*
* This file is part of Anope. Anope is free software; you can
* redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software
* Foundation, version 2.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see see <http://www.gnu.org/licenses/>.
*/
/* Dependencies: anope_protocol.rfc1459,anope_protocol.ts6 */
#include "module.h"
#include "modules/sasl.h"
#include "modules/chanserv/mode.h"
#include "modules/chanserv/set.h"
#include "modules/protocol/rfc1459.h"
#include "modules/protocol/inspircd20.h"
struct SASLUser
{
Anope::string uid;
Anope::string acc;
time_t created;
};
static std::list<SASLUser> saslusers;
static Anope::string rsquit_server, rsquit_id;
static unsigned int spanningtree_proto_ver = 0;
void inspircd20::senders::Akill::Send(User* u, XLine* x)
{
// Calculate the time left before this would expire, capping it at 2 days
time_t timeleft = x->GetExpires() - Anope::CurTime;
if (timeleft > 172800 || !x->GetExpires())
timeleft = 172800;
/* InspIRCd may support regex bans, if they do we can send this and forget about it */
if (x->IsRegex() && Servers::Capab.count("RLINE"))
{
Anope::string mask = x->GetMask();
size_t h = mask.find('#');
if (h != Anope::string::npos)
mask = mask.replace(h, 1, ' ');
proto->SendAddLine("R", mask, timeleft, x->GetBy(), x->GetReason());
return;
}
else if (x->IsRegex() || x->HasNickOrReal())
{
if (!u)
{
/* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */
for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
if (x->GetManager()->Check(it->second, x))
this->Send(it->second, x);
return;
}
XLine *old = x;
if (old->GetManager()->HasEntry("*@" + u->host))
return;
/* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */
x = Serialize::New<XLine *>();
x->SetMask("*@" + u->host);
x->SetBy(old->GetBy());
x->SetExpires(old->GetExpires());
x->SetReason(old->GetReason());
old->GetManager()->AddXLine(x);
Anope::Logger.Bot("OperServ").Category("akill").Log(_("AKILL: Added an akill for {0} because {1}#{2} matches {3}"),
x->GetMask(), u->GetMask(), u->realname, old->GetMask());
}
/* ZLine if we can instead */
if (x->GetUser() == "*")
{
cidr addr(x->GetHost());
if (addr.valid())
{
IRCD->Send<messages::SZLine>(u, x);
return;
}
}
proto->SendAddLine("G", x->GetUser() + "@" + x->GetHost(), timeleft, x->GetBy(), x->GetReason());
}
void inspircd20::senders::AkillDel::Send(XLine* x)
{
/* InspIRCd may support regex bans */
if (x->IsRegex() && Servers::Capab.count("RLINE"))
{
Anope::string mask = x->GetMask();
size_t h = mask.find('#');
if (h != Anope::string::npos)
mask = mask.replace(h, 1, ' ');
proto->SendDelLine("R", mask);
return;
}
else if (x->IsRegex() || x->HasNickOrReal())
return;
/* ZLine if we can instead */
if (x->GetUser() == "*")
{
cidr addr(x->GetHost());
if (addr.valid())
{
IRCD->Send<messages::SZLineDel>(x);
return;
}
}
proto->SendDelLine("G", x->GetUser() + "@" + x->GetHost());
}
void inspircd20::senders::MessageChannel::Send(Channel* c)
{
Uplink::Send(Me, "FJOIN", c->name, c->creation_time, "+" + c->GetModes(true, true), "");
}
void inspircd20::senders::Join::Send(User* user, Channel* c, const ChannelStatus* status)
{
Uplink::Send(Me, "FJOIN", c->name, c->creation_time, "+" + c->GetModes(true, true), "," + user->GetUID());
/* Note that we can send this with the FJOIN but choose not to
* because the mode stacker will handle this and probably will
* merge these modes with +nrt and other mlocked modes
*/
if (status)
{
/* First save the channel status incase uc->Status == status */
ChannelStatus cs = *status;
/* If the user is internally on the channel with flags, kill them so that
* the stacker will allow this.
*/
ChanUserContainer *uc = c->FindUser(user);
if (uc != NULL)
uc->status.Clear();
ServiceBot *setter = ServiceBot::Find(user->nick);
for (size_t i = 0; i < cs.Modes().length(); ++i)
c->SetMode(setter, ModeManager::FindChannelModeByChar(cs.Modes()[i]), user->GetUID(), false);
if (uc != NULL)
uc->status = cs;
}
}
void inspircd20::senders::Login::Send(User *u, NickServ::Nick *na)
{
/* InspIRCd uses an account to bypass chmode +R, not umode +r, so we can't send this here */
if (na->GetAccount()->IsUnconfirmed())
return;
Uplink::Send(Me, "METADATA", u->GetUID(), "accountname", na->GetAccount()->GetDisplay());
}
void inspircd20::senders::Logout::Send(User *u)
{
Uplink::Send(Me, "METADATA", u->GetUID(), "accountname", "");
}
void inspircd20::senders::ModeChannel::Send(const MessageSource &source, Channel *channel, const Anope::string &modes)
{
IRCMessage message(source, "FMODE", channel->name, channel->creation_time);
message.TokenizeAndPush(modes);
Uplink::SendMessage(message);
}
void inspircd20::senders::NickIntroduction::Send(User *user)
{
Anope::string modes = "+" + user->GetModes();
Uplink::Send(Me, "UID", user->GetUID(), user->timestamp, user->nick, user->host, user->host, user->GetIdent(), "0.0.0.0", user->timestamp, modes, user->realname);
if (modes.find('o') != Anope::string::npos)
Uplink::Send(user, "OPERTYPE", "services");
}
void inspircd20::senders::SASL::Send(const ::SASL::Message& message)
{
if (!message.ext.empty())
Uplink::Send(Me, "ENCAP", message.target.substr(0, 3), "SASL",
message.source, message.target,
message.type, message.data, message.ext);
else
Uplink::Send(Me, "ENCAP", message.target.substr(0, 3), "SASL",
message.source, message.target,
message.type, message.data);
}
void inspircd20::senders::SASLMechanisms::Send(const std::vector<Anope::string>& mechanisms)
{
Anope::string mechlist;
for (unsigned int i = 0; i < mechanisms.size(); ++i)
mechlist += "," + mechanisms[i];
Uplink::Send(Me, "METADATA", "*", "saslmechlist", mechlist.empty() ? "" : mechlist.substr(1));
}
void inspircd20::senders::MessageServer::Send(Server* server)
{
/* if rsquit is set then we are waiting on a squit */
if (rsquit_id.empty() && rsquit_server.empty())
Uplink::Send("SERVER", server->GetName(), Config->Uplinks[Anope::CurrentUplink].password, server->GetHops(), server->GetSID(), server->GetDescription());
}
void inspircd20::senders::SQLine::Send(User*, XLine* x)
{
// C
|