anope

- supernets anope source code & configuration
git clone git://git.acid.vegas/anope.git
Log | Files | Refs | Archive | README

protocol.cpp (13463B)

      1 /*
      2  *
      3  * (C) 2003-2022 Anope Team
      4  * Contact us at team@anope.org
      5  *
      6  * Please read COPYING and README for further details.
      7  *
      8  * Based on the original code of Epona by Lara.
      9  * Based on the original code of Services by Andy Church.
     10  */
     11 
     12 #include "services.h"
     13 #include "modules.h"
     14 #include "protocol.h"
     15 #include "users.h"
     16 #include "servers.h"
     17 #include "config.h"
     18 #include "uplink.h"
     19 #include "bots.h"
     20 #include "channels.h"
     21 
     22 IRCDProto *IRCD = NULL;
     23 
     24 IRCDProto::IRCDProto(Module *creator, const Anope::string &p) : Service(creator, "IRCDProto", creator->name), proto_name(p)
     25 {
     26 	DefaultPseudoclientModes = "+io";
     27 	CanSVSNick = CanSVSJoin = CanSetVHost = CanSetVIdent = CanSNLine = CanSQLine = CanSQLineChannel
     28 		= CanSZLine = CanSVSHold = CanSVSO = CanCertFP = RequiresID = AmbiguousID = false;
     29 	MaxModes = 3;
     30 	MaxLine = 512;
     31 
     32 	if (IRCD == NULL)
     33 		IRCD = this;
     34 }
     35 
     36 IRCDProto::~IRCDProto()
     37 {
     38 	if (IRCD == this)
     39 		IRCD = NULL;
     40 }
     41 
     42 const Anope::string &IRCDProto::GetProtocolName()
     43 {
     44 	return this->proto_name;
     45 }
     46 
     47 static inline char nextID(int pos, Anope::string &buf)
     48 {
     49 	char &c = buf[pos];
     50 	if (c == 'Z')
     51 		c = '0';
     52 	else if (c != '9')
     53 		++c;
     54 	else if (pos)
     55 		c = 'A';
     56 	else
     57 		c = '0';
     58 	return c;
     59 }
     60 
     61 Anope::string IRCDProto::UID_Retrieve()
     62 {
     63 	if (!IRCD || !IRCD->RequiresID)
     64 		return "";
     65 
     66 	static Anope::string current_uid = "AAAAAA";
     67 
     68 	do
     69 	{
     70 		int current_len = current_uid.length() - 1;
     71 		while (current_len >= 0 && nextID(current_len--, current_uid) == 'A');
     72 	}
     73 	while (User::Find(Me->GetSID() + current_uid) != NULL);
     74 
     75 	return Me->GetSID() + current_uid;
     76 }
     77 
     78 Anope::string IRCDProto::SID_Retrieve()
     79 {
     80 	if (!IRCD || !IRCD->RequiresID)
     81 		return "";
     82 
     83 	static Anope::string current_sid = Config->GetBlock("serverinfo")->Get<const Anope::string>("id");
     84 	if (current_sid.empty())
     85 		current_sid = "00A";
     86 
     87 	do
     88 	{
     89 		int current_len = current_sid.length() - 1;
     90 		while (current_len >= 0 && nextID(current_len--, current_sid) == 'A');
     91 	}
     92 	while (Server::Find(current_sid) != NULL);
     93 
     94 	return current_sid;
     95 }
     96 
     97 void IRCDProto::SendKill(const MessageSource &source, const Anope::string &target, const Anope::string &reason)
     98 {
     99 	UplinkSocket::Message(source) << "KILL " << target << " :" << reason;
    100 }
    101 
    102 void IRCDProto::SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf)
    103 {
    104 	UplinkSocket::Message(source) << "KILL " << user->GetUID() << " :" << buf;
    105 }
    106 
    107 void IRCDProto::SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf)
    108 {
    109 	UplinkSocket::Message(source) << "MODE " << dest->name << " " << buf;
    110 }
    111 
    112 void IRCDProto::SendModeInternal(const MessageSource &source, User *dest, const Anope::string &buf)
    113 {
    114 	UplinkSocket::Message(source) << "MODE " << dest->GetUID() << " " << buf;
    115 }
    116 
    117 void IRCDProto::SendKickInternal(const MessageSource &source, const Channel *c, User *u, const Anope::string &r)
    118 {
    119 	if (!r.empty())
    120 		UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID() << " :" << r;
    121 	else
    122 		UplinkSocket::Message(source) << "KICK " << c->name << " " << u->GetUID();
    123 }
    124 
    125 void IRCDProto::SendNoticeInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &msg)
    126 {
    127 	UplinkSocket::Message(source) << "NOTICE " << dest << " :" << msg;
    128 }
    129 
    130 void IRCDProto::SendPrivmsgInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf)
    131 {
    132 	UplinkSocket::Message(source) << "PRIVMSG " << dest << " :" << buf;
    133 }
    134 
    135 void IRCDProto::SendQuitInternal(User *u, const Anope::string &buf)
    136 {
    137 	if (!buf.empty())
    138 		UplinkSocket::Message(u) << "QUIT :" << buf;
    139 	else
    140 		UplinkSocket::Message(u) << "QUIT";
    141 }
    142 
    143 void IRCDProto::SendPartInternal(User *u, const Channel *chan, const Anope::string &buf)
    144 {
    145 	if (!buf.empty())
    146 		UplinkSocket::Message(u) << "PART " << chan->name << " :" << buf;
    147 	else
    148 		UplinkSocket::Message(u) << "PART " << chan->name;
    149 }
    150 
    151 void IRCDProto::SendGlobopsInternal(const MessageSource &source, const Anope::string &buf)
    152 {
    153 	UplinkSocket::Message(source) << "GLOBOPS :" << buf;
    154 }
    155 
    156 void IRCDProto::SendCTCPInternal(const MessageSource &source, const Anope::string &dest, const Anope::string &buf)
    157 {
    158 	Anope::string s = Anope::NormalizeBuffer(buf);
    159 	this->SendNoticeInternal(source, dest, "\1" + s + "\1");
    160 }
    161 
    162 void IRCDProto::SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf)
    163 {
    164 	Anope::string n = stringify(numeric);
    165 	if (numeric < 10)
    166 		n = "0" + n;
    167 	if (numeric < 100)
    168 		n = "0" + n;
    169 	UplinkSocket::Message(Me) << n << " " << dest << " " << buf;
    170 }
    171 
    172 void IRCDProto::SendTopic(const MessageSource &source, Channel *c)
    173 {
    174 	UplinkSocket::Message(source) << "TOPIC " << c->name << " :" << c->topic;
    175 }
    176 
    177 void IRCDProto::SendSVSKill(const MessageSource &source, User *user, const char *fmt, ...)
    178 {
    179 	if (!user || !fmt)
    180 		return;
    181 
    182 	va_list args;
    183 	char buf[BUFSIZE] = "";
    184 	va_start(args, fmt);
    185 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    186 	va_end(args);
    187 	SendSVSKillInternal(source, user, buf);
    188 }
    189 
    190 void IRCDProto::SendMode(const MessageSource &source, const Channel *dest, const char *fmt, ...)
    191 {
    192 	va_list args;
    193 	char buf[BUFSIZE] = "";
    194 	va_start(args, fmt);
    195 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    196 	va_end(args);
    197 	SendModeInternal(source, dest, buf);
    198 }
    199 
    200 void IRCDProto::SendMode(const MessageSource &source, User *u, const char *fmt, ...)
    201 {
    202 	va_list args;
    203 	char buf[BUFSIZE] = "";
    204 	va_start(args, fmt);
    205 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    206 	va_end(args);
    207 	SendModeInternal(source, u, buf);
    208 }
    209 
    210 void IRCDProto::SendKick(const MessageSource &source, const Channel *chan, User *user, const char *fmt, ...)
    211 {
    212 	if (!chan || !user)
    213 		return;
    214 
    215 	va_list args;
    216 	char buf[BUFSIZE] = "";
    217 	va_start(args, fmt);
    218 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    219 	va_end(args);
    220 	SendKickInternal(source, chan, user, buf);
    221 }
    222 
    223 void IRCDProto::SendNotice(const MessageSource &source, const Anope::string &dest, const char *fmt, ...)
    224 {
    225 	va_list args;
    226 	char buf[BUFSIZE] = "";
    227 	va_start(args, fmt);
    228 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    229 	va_end(args);
    230 	SendNoticeInternal(source, dest, buf);
    231 }
    232 
    233 void IRCDProto::SendAction(const MessageSource &source, const Anope::string &dest, const char *fmt, ...)
    234 {
    235 	va_list args;
    236 	char buf[BUFSIZE] = "";
    237 	va_start(args, fmt);
    238 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    239 	va_end(args);
    240 	Anope::string actionbuf = Anope::string("\1ACTION ") + buf + '\1';
    241 	SendPrivmsgInternal(source, dest, actionbuf);
    242 }
    243 
    244 void IRCDProto::SendPrivmsg(const MessageSource &source, const Anope::string &dest, const char *fmt, ...)
    245 {
    246 	va_list args;
    247 	char buf[BUFSIZE] = "";
    248 	va_start(args, fmt);
    249 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    250 	va_end(args);
    251 	SendPrivmsgInternal(source, dest, buf);
    252 }
    253 
    254 void IRCDProto::SendQuit(User *u, const char *fmt, ...)
    255 {
    256 	va_list args;
    257 	char buf[BUFSIZE] = "";
    258 	va_start(args, fmt);
    259 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    260 	va_end(args);
    261 	SendQuitInternal(u, buf);
    262 }
    263 
    264 void IRCDProto::SendPing(const Anope::string &servname, const Anope::string &who)
    265 {
    266 	if (servname.empty())
    267 		UplinkSocket::Message(Me) << "PING " << who;
    268 	else
    269 		UplinkSocket::Message(Me) << "PING " << servname << " " << who;
    270 }
    271 
    272 /**
    273  * Send a PONG reply to a received PING.
    274  * servname should be left NULL to send a one param reply.
    275  * @param servname Daemon or client that is responding to the PING.
    276  * @param who Origin of the PING and destination of the PONG message.
    277  **/
    278 void IRCDProto::SendPong(const Anope::string &servname, const Anope::string &who)
    279 {
    280 	if (servname.empty())
    281 		UplinkSocket::Message(Me) << "PONG " << who;
    282 	else
    283 		UplinkSocket::Message(Me) << "PONG " << servname << " " << who;
    284 }
    285 
    286 void IRCDProto::SendInvite(const MessageSource &source, const Channel *c, User *u)
    287 {
    288 	UplinkSocket::Message(source) << "INVITE " << u->GetUID() << " " << c->name;
    289 }
    290 
    291 void IRCDProto::SendPart(User *user, const Channel *chan, const char *fmt, ...)
    292 {
    293 	if (fmt)
    294 	{
    295 		va_list args;
    296 		char buf[BUFSIZE] = "";
    297 		va_start(args, fmt);
    298 		vsnprintf(buf, BUFSIZE - 1, fmt, args);
    299 		va_end(args);
    300 		SendPartInternal(user, chan, buf);
    301 	}
    302 	else
    303 		SendPartInternal(user, chan, "");
    304 }
    305 
    306 void IRCDProto::SendGlobops(const MessageSource &source, const char *fmt, ...)
    307 {
    308 	va_list args;
    309 	char buf[BUFSIZE] = "";
    310 	va_start(args, fmt);
    311 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    312 	va_end(args);
    313 	SendGlobopsInternal(source, buf);
    314 }
    315 
    316 void IRCDProto::SendSquit(Server *s, const Anope::string &message)
    317 {
    318 	UplinkSocket::Message() << "SQUIT " << s->GetSID() << " :" << message;
    319 }
    320 
    321 void IRCDProto::SendNickChange(User *u, const Anope::string &newnick)
    322 {
    323 	UplinkSocket::Message(u) << "NICK " << newnick << " " << Anope::CurTime;
    324 }
    325 
    326 void IRCDProto::SendForceNickChange(User *u, const Anope::string &newnick, time_t when)
    327 {
    328 	UplinkSocket::Message() << "SVSNICK " << u->GetUID() << " " << newnick << " " << when;
    329 }
    330 
    331 void IRCDProto::SendCTCP(const MessageSource &source, const Anope::string &dest, const char *fmt, ...)
    332 {
    333 	va_list args;
    334 	char buf[BUFSIZE] = "";
    335 	va_start(args, fmt);
    336 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    337 	va_end(args);
    338 	SendCTCPInternal(source, dest, buf);
    339 }
    340 
    341 void IRCDProto::SendNumeric(int numeric, const Anope::string &dest, const char *fmt, ...)
    342 {
    343 	va_list args;
    344 	char buf[BUFSIZE] = "";
    345 	va_start(args, fmt);
    346 	vsnprintf(buf, BUFSIZE - 1, fmt, args);
    347 	va_end(args);
    348 	SendNumericInternal(numeric, dest, buf);
    349 }
    350 
    351 bool IRCDProto::IsNickValid(const Anope::string &nick)
    352 {
    353 	/**
    354 	 * RFC: definition of a valid nick
    355 	 * nickname =  ( letter / special ) ( letter / digit / special / "-" )
    356 	 * letter   =  A-Z / a-z
    357 	 * digit    =  0-9
    358 	 * special  =  [, ], \, `, _, ^, {, |, }
    359 	 **/
    360 
    361 	 if (nick.empty())
    362 		return false;
    363 
    364 	Anope::string special = "[]\\`_^{|}";
    365 
    366 	for (unsigned i = 0; i < nick.length(); ++i)
    367 		if (!(nick[i] >= 'A' && nick[i] <= 'Z') && !(nick[i] >= 'a' && nick[i] <= 'z')
    368 		  && special.find(nick[i]) == Anope::string::npos
    369 		  && (Config && Config->NickChars.find(nick[i]) == Anope::string::npos)
    370 		  && (!i || (!(nick[i] >= '0' && nick[i] <= '9') && nick[i] != '-')))
    371 			return false;
    372 
    373 	return true;
    374 }
    375 
    376 bool IRCDProto::IsChannelValid(const Anope::string &chan)
    377 {
    378 	if (chan.empty() || chan[0] != '#' || chan.length() > Config->GetBlock("networkinfo")->Get<unsigned>("chanlen"))
    379 		return false;
    380 
    381 	if (chan.find_first_of(" ,") != Anope::string::npos)
    382 		return false;
    383 
    384 	return true;
    385 }
    386 
    387 bool IRCDProto::IsIdentValid(const Anope::string &ident)
    388 {
    389 	if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen"))
    390 		return false;
    391 
    392 	for (unsigned i = 0; i < ident.length(); ++i)
    393 	{
    394 		const char &c = ident[i];
    395 
    396 		if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-')
    397 			continue;
    398 
    399 		return false;
    400 	}
    401 
    402 	return true;
    403 }
    404 
    405 bool IRCDProto::IsHostValid(const Anope::string &host)
    406 {
    407 	if (host.empty() || host.length() > Config->GetBlock("networkinfo")->Get<unsigned>("hostlen"))
    408 		return false;
    409 
    410 	const Anope::string &vhostdisablebe = Config->GetBlock("networkinfo")->Get<const Anope::string>("disallow_start_or_end"),
    411 		vhostchars = Config->GetBlock("networkinfo")->Get<const Anope::string>("vhost_chars");
    412 
    413 	if (vhostdisablebe.find_first_of(host[0]) != Anope::string::npos)
    414 		return false;
    415 	else if (vhostdisablebe.find_first_of(host[host.length() - 1]) != Anope::string::npos)
    416 		return false;
    417 
    418 	int dots = 0;
    419 	for (unsigned i = 0; i < host.length(); ++i)
    420 	{
    421 		if (host[i] == '.')
    422 			++dots;
    423 		if (vhostchars.find_first_of(host[i]) == Anope::string::npos)
    424 			return false;
    425 	}
    426 
    427 	return dots > 0 || Config->GetBlock("networkinfo")->Get<bool>("allow_undotted_vhosts");
    428 }
    429 
    430 void IRCDProto::SendOper(User *u)
    431 {
    432 	SendNumericInternal(381, u->GetUID(), ":You are now an IRC operator (set by services)");
    433 	u->SetMode(NULL, "OPER");
    434 }
    435 
    436 unsigned IRCDProto::GetMaxListFor(Channel *c)
    437 {
    438 	return c->HasMode("LBAN") ? 0 : Config->GetBlock("networkinfo")->Get<int>("modelistsize");
    439 }
    440 
    441 unsigned IRCDProto::GetMaxListFor(Channel *c, ChannelMode *cm)
    442 {
    443 	return GetMaxListFor(c);
    444 }
    445 
    446 Anope::string IRCDProto::NormalizeMask(const Anope::string &mask)
    447 {
    448 	if (IsExtbanValid(mask))
    449 		return mask;
    450 	return Entry("", mask).GetNUHMask();
    451 }
    452 
    453 MessageSource::MessageSource(const Anope::string &src) : source(src), u(NULL), s(NULL)
    454 {
    455 	/* no source for incoming message is our uplink */
    456 	if (src.empty())
    457 		this->s = Servers::GetUplink();
    458 	else if (IRCD->RequiresID || src.find('.') != Anope::string::npos)
    459 		this->s = Server::Find(src);
    460 	if (this->s == NULL)
    461 		this->u = User::Find(src);
    462 }
    463 
    464 MessageSource::MessageSource(User *_u) : source(_u ? _u->nick : ""), u(_u), s(NULL)
    465 {
    466 }
    467 
    468 MessageSource::MessageSource(Server *_s) : source(_s ? _s->GetName() : ""), u(NULL), s(_s)
    469 {
    470 }
    471 
    472 const Anope::string &MessageSource::GetName() const
    473 {
    474 	if (this->s)
    475 		return this->s->GetName();
    476 	else if (this->u)
    477 		return this->u->nick;
    478 	else
    479 		return this->source;
    480 }
    481 
    482 const Anope::string &MessageSource::GetSource() const
    483 {
    484 	return this->source;
    485 }
    486 
    487 User *MessageSource::GetUser() const
    488 {
    489 	return this->u;
    490 }
    491 
    492 BotInfo *MessageSource::GetBot() const
    493 {
    494 	return BotInfo::Find(this->GetName(), true);
    495 }
    496 
    497 Server *MessageSource::GetServer() const
    498 {
    499 	return this->s;
    500 }
    501 
    502 IRCDMessage::IRCDMessage(Module *o, const Anope::string &n, unsigned p) : Service(o, "IRCDMessage", o->name + "/" + n.lower()), name(n), param_count(p)
    503 {
    504 }
    505 
    506 unsigned IRCDMessage::GetParamCount() const
    507 {
    508 	return this->param_count;
    509 }
    510 
    511 void IRCDMessage::Run(MessageSource &source, const std::vector<Anope::string> &params, const Anope::map<Anope::string> &tags)
    512 {
    513 	// Most IRCds don't support message tags yet so use the tagless variant.
    514 	Run(source, params);
    515 }
    516