anope

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

inspircd12.cpp (43509B)

      1 /* inspircd 1.2 functions
      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 "module.h"
     13 #include "modules/sasl.h"
     14 
     15 struct SASLUser
     16 {
     17 	Anope::string uid;
     18 	Anope::string acc;
     19 	time_t created;
     20 };
     21 
     22 static std::list<SASLUser> saslusers;
     23 
     24 static Anope::string rsquit_server, rsquit_id;
     25 
     26 class ChannelModeFlood : public ChannelModeParam
     27 {
     28  public:
     29 	ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam("FLOOD", modeChar, minusNoArg) { }
     30 
     31 	bool IsValid(Anope::string &value) const anope_override
     32 	{
     33 		try
     34 		{
     35 			Anope::string rest;
     36 			if (!value.empty() && value[0] != ':' && convertTo<int>(value[0] == '*' ? value.substr(1) : value, rest, false) > 0 && rest[0] == ':' && rest.length() > 1 && convertTo<int>(rest.substr(1), rest, false) > 0 && rest.empty())
     37 				return true;
     38 		}
     39 		catch (const ConvertException &) { }
     40 
     41 		return false;
     42 	}
     43 };
     44 
     45 class InspIRCd12Proto : public IRCDProto
     46 {
     47  private:
     48 	void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override
     49 	{
     50 		IRCDProto::SendSVSKillInternal(source, user, buf);
     51 		user->KillInternal(source, buf);
     52 	}
     53 
     54 	void SendChgIdentInternal(const Anope::string &nick, const Anope::string &vIdent)
     55 	{
     56 		if (!Servers::Capab.count("CHGIDENT"))
     57 			Log() << "CHGIDENT not loaded!";
     58 		else
     59 			UplinkSocket::Message(Me) << "CHGIDENT " << nick << " " << vIdent;
     60 	}
     61 
     62 	void SendChgHostInternal(const Anope::string &nick, const Anope::string &vhost)
     63 	{
     64 		if (!Servers::Capab.count("CHGHOST"))
     65 			Log() << "CHGHOST not loaded!";
     66 		else
     67 			UplinkSocket::Message(Me) << "CHGHOST " << nick << " " << vhost;
     68 	}
     69 
     70 	void SendAddLine(const Anope::string &xtype, const Anope::string &mask, time_t duration, const Anope::string &addedby, const Anope::string &reason)
     71 	{
     72 		UplinkSocket::Message(Me) << "ADDLINE " << xtype << " " << mask << " " << addedby << " " << Anope::CurTime << " " << duration << " :" << reason;
     73 	}
     74 
     75 	void SendDelLine(const Anope::string &xtype, const Anope::string &mask)
     76 	{
     77 		UplinkSocket::Message(Me) << "DELLINE " << xtype << " " << mask;
     78 	}
     79 
     80  public:
     81 	InspIRCd12Proto(Module *creator) : IRCDProto(creator, "InspIRCd 1.2")
     82 	{
     83 		DefaultPseudoclientModes = "+I";
     84 		CanSVSNick = true;
     85 		CanSVSJoin = true;
     86 		CanSetVHost = true;
     87 		CanSetVIdent = true;
     88 		CanSQLine = true;
     89 		CanSZLine = true;
     90 		CanSVSHold = true;
     91 		CanCertFP = true;
     92 		RequiresID = true;
     93 		MaxModes = 20;
     94 	}
     95 
     96 	void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
     97 	{
     98 		UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg;
     99 	}
    100 
    101 	void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
    102 	{
    103 		UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg;
    104 	}
    105 
    106 	void SendAkillDel(const XLine *x) anope_override
    107 	{
    108 		/* InspIRCd may support regex bans
    109 		 * Mask is expected in format: 'n!u@h\sr' and spaces as '\s'
    110 		 * We remove the '//' and replace '#' and any ' ' with '\s'
    111 		 */
    112 		if (x->IsRegex() && Servers::Capab.count("RLINE"))
    113 		{
    114 			Anope::string mask = x->mask;
    115 			if (mask.length() >= 2 && mask[0] == '/' && mask[mask.length() - 1] == '/')
    116 				mask = mask.substr(1, mask.length() - 2);
    117 			size_t h = mask.find('#');
    118 			if (h != Anope::string::npos)
    119 			{
    120 				mask = mask.replace(h, 1, "\\s");
    121 				mask = mask.replace_all_cs(" ", "\\s");
    122 			}
    123 			SendDelLine("R", mask);
    124 			return;
    125 		}
    126 		else if (x->IsRegex() || x->HasNickOrReal())
    127 			return;
    128 
    129 		/* ZLine if we can instead */
    130 		if (x->GetUser() == "*")
    131 		{
    132 			cidr addr(x->GetHost());
    133 			if (addr.valid())
    134 			{
    135 				IRCD->SendSZLineDel(x);
    136 				return;
    137 			}
    138 		}
    139 
    140 		SendDelLine("G", x->GetUser() + "@" + x->GetHost());
    141 	}
    142 
    143 	void SendTopic(const MessageSource &source, Channel *c) anope_override
    144 	{
    145 		if (Servers::Capab.count("SVSTOPIC"))
    146 		{
    147 			UplinkSocket::Message(c->ci->WhoSends()) << "SVSTOPIC " << c->name << " " << c->topic_ts << " " << c->topic_setter << " :" << c->topic;
    148 		}
    149 		else
    150 		{
    151 			/* If the last time a topic was set is after the TS we want for this topic we must bump this topic's timestamp to now */
    152 			time_t ts = c->topic_ts;
    153 			if (c->topic_time > ts)
    154 				ts = Anope::CurTime;
    155 			/* But don't modify c->topic_ts, it should remain set to the real TS we want as ci->last_topic_time pulls from it */
    156 			UplinkSocket::Message(source) << "FTOPIC " << c->name << " " << ts << " " << c->topic_setter << " :" << c->topic;
    157 		}
    158 	}
    159 
    160 	void SendVhostDel(User *u) anope_override
    161 	{
    162 		UserMode *um = ModeManager::FindUserModeByName("CLOAK");
    163 
    164 		if (um && !u->HasMode(um->name))
    165 			// Just set +x if we can
    166 			u->SetMode(NULL, um);
    167 		else
    168 			// Try to restore cloaked host
    169 			this->SendChgHostInternal(u->nick, u->chost);
    170 	}
    171 
    172 	void SendAkill(User *u, XLine *x) anope_override
    173 	{
    174 		// Calculate the time left before this would expire, capping it at 2 days
    175 		time_t timeleft = x->expires - Anope::CurTime;
    176 		if (timeleft > 172800 || !x->expires)
    177 			timeleft = 172800;
    178 
    179 		/* InspIRCd may support regex bans, if they do we can send this and forget about it
    180 		 * Mask is expected in format: 'n!u@h\sr' and spaces as '\s'
    181 		 * We remove the '//' and replace '#' and any ' ' with '\s'
    182 		 */
    183 		if (x->IsRegex() && Servers::Capab.count("RLINE"))
    184 		{
    185 			Anope::string mask = x->mask;
    186 			if (mask.length() >= 2 && mask[0] == '/' && mask[mask.length() - 1] == '/')
    187 				mask = mask.substr(1, mask.length() - 2);
    188 			size_t h = mask.find('#');
    189 			if (h != Anope::string::npos)
    190 			{
    191 				mask = mask.replace(h, 1, "\\s");
    192 				mask = mask.replace_all_cs(" ", "\\s");
    193 			}
    194 			SendAddLine("R", mask, timeleft, x->by, x->GetReason());
    195 			return;
    196 		}
    197 		else if (x->IsRegex() || x->HasNickOrReal())
    198 		{
    199 			if (!u)
    200 			{
    201 				/* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */
    202 				for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
    203 					if (x->manager->Check(it->second, x))
    204 						this->SendAkill(it->second, x);
    205 				return;
    206 			}
    207 
    208 			const XLine *old = x;
    209 
    210 			if (old->manager->HasEntry("*@" + u->host))
    211 				return;
    212 
    213 			/* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */
    214 			x = new XLine("*@" + u->host, old->by, old->expires, old->reason, old->id);
    215 			old->manager->AddXLine(x);
    216 
    217 			Log(Config->GetClient("OperServ"), "akill") << "AKILL: Added an akill for " << x->mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->mask;
    218 		}
    219 
    220 		/* ZLine if we can instead */
    221 		if (x->GetUser() == "*")
    222 		{
    223 			cidr addr(x->GetHost());
    224 			if (addr.valid())
    225 			{
    226 				IRCD->SendSZLine(u, x);
    227 				return;
    228 			}
    229 		}
    230 
    231 		SendAddLine("G", x->GetUser() + "@" + x->GetHost(), timeleft, x->by, x->GetReason());
    232 	}
    233 
    234 	void SendNumericInternal(int numeric, const Anope::string &dest, const Anope::string &buf) anope_override
    235 	{
    236 		User *u = User::Find(dest);
    237 		UplinkSocket::Message() << "PUSH " << dest << " ::" << Me->GetName() << " " << numeric << " " << (u ? u->nick : dest) << " " << buf;
    238 	}
    239 
    240 	void SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf) anope_override
    241 	{
    242 		UplinkSocket::Message(source) << "FMODE " << dest->name << " " << dest->creation_time << " " << buf;
    243 	}
    244 
    245 	void SendClientIntroduction(User *u) anope_override
    246 	{
    247 		Anope::string modes = "+" + u->GetModes();
    248 		UplinkSocket::Message(Me) << "UID " << u->GetUID() << " " << u->timestamp << " " << u->nick << " " << u->host << " " << u->host << " " << u->GetIdent() << " 0.0.0.0 " << u->timestamp << " " << modes << " :" << u->realname;
    249 		if (modes.find('o') != Anope::string::npos)
    250 			UplinkSocket::Message(u) << "OPERTYPE :service";
    251 	}
    252 
    253 	/* SERVER services-dev.chatspike.net password 0 :Description here */
    254 	void SendServer(const Server *server) anope_override
    255 	{
    256 		/* if rsquit is set then we are waiting on a squit */
    257 		if (rsquit_id.empty() && rsquit_server.empty())
    258 			UplinkSocket::Message() << "SERVER " << server->GetName() << " " << Config->Uplinks[Anope::CurrentUplink].password << " " << server->GetHops() << " " << server->GetSID() << " :" << server->GetDescription();
    259 	}
    260 
    261 	void SendSquit(Server *s, const Anope::string &message) anope_override
    262 	{
    263 		if (s != Me)
    264 		{
    265 			rsquit_id = s->GetSID();
    266 			rsquit_server = s->GetName();
    267 			UplinkSocket::Message() << "RSQUIT " << s->GetName() << " :" << message;
    268 		}
    269 		else
    270 			UplinkSocket::Message() << "SQUIT " << s->GetName() << " :" << message;
    271 	}
    272 
    273 	/* JOIN */
    274 	void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override
    275 	{
    276 		UplinkSocket::Message(Me) << "FJOIN " << c->name << " " << c->creation_time << " +" << c->GetModes(true, true) << " :," << user->GetUID();
    277 		/* Note that we can send this with the FJOIN but choose not to
    278 		 * because the mode stacker will handle this and probably will
    279 		 * merge these modes with +nrt and other mlocked modes
    280 		 */
    281 		if (status)
    282 		{
    283 			/* First save the channel status incase uc->Status == status */
    284 			ChannelStatus cs = *status;
    285 			/* If the user is internally on the channel with flags, kill them so that
    286 			 * the stacker will allow this.
    287 			 */
    288 			ChanUserContainer *uc = c->FindUser(user);
    289 			if (uc != NULL)
    290 				uc->status.Clear();
    291 
    292 			BotInfo *setter = BotInfo::Find(user->GetUID());
    293 			for (size_t i = 0; i < cs.Modes().length(); ++i)
    294 				c->SetMode(setter, ModeManager::FindChannelModeByChar(cs.Modes()[i]), user->GetUID(), false);
    295 
    296 			if (uc != NULL)
    297 				uc->status = cs;
    298 		}
    299 	}
    300 
    301 	/* UNSQLINE */
    302 	void SendSQLineDel(const XLine *x) anope_override
    303 	{
    304 		SendDelLine("Q", x->mask);
    305 	}
    306 
    307 	/* SQLINE */
    308 	void SendSQLine(User *, const XLine *x) anope_override
    309 	{
    310 		// Calculate the time left before this would expire, capping it at 2 days
    311 		time_t timeleft = x->expires - Anope::CurTime;
    312 		if (timeleft > 172800 || !x->expires)
    313 			timeleft = 172800;
    314 		SendAddLine("Q", x->mask, timeleft, x->by, x->GetReason());
    315 	}
    316 
    317 	void SendVhost(User *u, const Anope::string &vIdent, const Anope::string &vhost) anope_override
    318 	{
    319 		if (!vIdent.empty())
    320 			this->SendChgIdentInternal(u->nick, vIdent);
    321 		if (!vhost.empty())
    322 			this->SendChgHostInternal(u->nick, vhost);
    323 	}
    324 
    325 	void SendConnect() anope_override
    326 	{
    327 		SendServer(Me);
    328 	}
    329 
    330 	/* SVSHOLD - set */
    331 	void SendSVSHold(const Anope::string &nick, time_t t) anope_override
    332 	{
    333 		UplinkSocket::Message(Config->GetClient("NickServ")) << "SVSHOLD " << nick << " " << t << " :Being held for registered user";
    334 	}
    335 
    336 	/* SVSHOLD - release */
    337 	void SendSVSHoldDel(const Anope::string &nick) anope_override
    338 	{
    339 		UplinkSocket::Message(Config->GetClient("NickServ")) << "SVSHOLD " << nick;
    340 	}
    341 
    342 	/* UNSZLINE */
    343 	void SendSZLineDel(const XLine *x) anope_override
    344 	{
    345 		SendDelLine("Z", x->GetHost());
    346 	}
    347 
    348 	/* SZLINE */
    349 	void SendSZLine(User *, const XLine *x) anope_override
    350 	{
    351 		// Calculate the time left before this would expire, capping it at 2 days
    352 		time_t timeleft = x->expires - Anope::CurTime;
    353 		if (timeleft > 172800 || !x->expires)
    354 			timeleft = 172800;
    355 		SendAddLine("Z", x->GetHost(), timeleft, x->by, x->GetReason());
    356 	}
    357 
    358 	void SendSVSJoin(const MessageSource &source, User *u, const Anope::string &chan, const Anope::string &) anope_override
    359 	{
    360 		UplinkSocket::Message(source) << "SVSJOIN " << u->GetUID() << " " << chan;
    361 	}
    362 
    363 	void SendSVSPart(const MessageSource &source, User *u, const Anope::string &chan, const Anope::string &param) anope_override
    364 	{
    365 		if (!param.empty())
    366 			UplinkSocket::Message(source) << "SVSPART " << u->GetUID() << " " << chan << " :" << param;
    367 		else
    368 			UplinkSocket::Message(source) << "SVSPART " << u->GetUID() << " " << chan;
    369 	}
    370 
    371 	void SendSWhois(const MessageSource &, const Anope::string &who, const Anope::string &mask) anope_override
    372 	{
    373 		User *u = User::Find(who);
    374 
    375 		UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " swhois :" << mask;
    376 	}
    377 
    378 	void SendBOB() anope_override
    379 	{
    380 		UplinkSocket::Message(Me) << "BURST " << Anope::CurTime;
    381 		Module *enc = ModuleManager::FindFirstOf(ENCRYPTION);
    382 		UplinkSocket::Message(Me) << "VERSION :Anope-" << Anope::Version() << " " << Me->GetName() << " :" << IRCD->GetProtocolName() << " - (" << (enc ? enc->name : "none") << ") -- " << Anope::VersionBuildString();
    383 	}
    384 
    385 	void SendEOB() anope_override
    386 	{
    387 		UplinkSocket::Message(Me) << "ENDBURST";
    388 	}
    389 
    390 	void SendGlobopsInternal(const MessageSource &source, const Anope::string &buf) anope_override
    391 	{
    392 		if (Servers::Capab.count("GLOBOPS"))
    393 			UplinkSocket::Message(source) << "SNONOTICE g :" << buf;
    394 		else
    395 			UplinkSocket::Message(source) << "SNONOTICE A :" << buf;
    396 	}
    397 
    398 	void SendLogin(User *u, NickAlias *na) anope_override
    399 	{
    400 		/* InspIRCd uses an account to bypass chmode +R, not umode +r, so we can't send this here */
    401 		if (na->nc->HasExt("UNCONFIRMED"))
    402 			return;
    403 
    404 		UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountname :" << na->nc->display;
    405 	}
    406 
    407 	void SendLogout(User *u) anope_override
    408 	{
    409 		UplinkSocket::Message(Me) << "METADATA " << u->GetUID() << " accountname :";
    410 	}
    411 
    412 	void SendChannel(Channel *c) anope_override
    413 	{
    414 		UplinkSocket::Message(Me) << "FJOIN " << c->name << " " << c->creation_time << " +" << c->GetModes(true, true) << " :";
    415 	}
    416 
    417 	void SendOper(User *u) anope_override
    418 	{
    419 	}
    420 
    421 	void SendSASLMessage(const SASL::Message &message) anope_override
    422 	{
    423 		UplinkSocket::Message(Me) << "ENCAP " << message.target.substr(0, 3) << " SASL " << message.source << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : (" " + message.ext));
    424 	}
    425 
    426 	void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override
    427 	{
    428 		UplinkSocket::Message(Me) << "METADATA " << uid << " accountname :" << acc;
    429 
    430 		if (!vident.empty())
    431 			UplinkSocket::Message(Me) << "ENCAP " << uid.substr(0, 3) << " CHGIDENT " << uid << " " << vident;
    432 		if (!vhost.empty())
    433 			UplinkSocket::Message(Me) << "ENCAP " << uid.substr(0, 3) << " CHGHOST " << uid << " " << vhost;
    434 
    435 		SASLUser su;
    436 		su.uid = uid;
    437 		su.acc = acc;
    438 		su.created = Anope::CurTime;
    439 
    440 		for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();)
    441 		{
    442 			SASLUser &u = *it;
    443 
    444 			if (u.created + 30 < Anope::CurTime || u.uid == uid)
    445 				it = saslusers.erase(it);
    446 			else
    447 				++it;
    448 		}
    449 
    450 		saslusers.push_back(su);
    451 	}
    452 
    453 	bool IsExtbanValid(const Anope::string &mask) anope_override
    454 	{
    455 		return mask.length() >= 3 && mask[1] == ':';
    456 	}
    457 
    458 	bool IsIdentValid(const Anope::string &ident) anope_override
    459 	{
    460 		if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen"))
    461 			return false;
    462 
    463 		for (unsigned i = 0; i < ident.length(); ++i)
    464 		{
    465 			const char &c = ident[i];
    466 
    467 			if (c >= 'A' && c <= '}')
    468 				continue;
    469 
    470 			if ((c >= '0' && c <= '9') || c == '-' || c == '.')
    471 				continue;
    472 
    473 			return false;
    474 		}
    475 
    476 		return true;
    477 	}
    478 };
    479 
    480 class InspIRCdExtBan : public ChannelModeList
    481 {
    482  public:
    483 	InspIRCdExtBan(const Anope::string &mname, char modeChar) : ChannelModeList(mname, modeChar) { }
    484 
    485 	bool Matches(User *u, const Entry *e) anope_override
    486 	{
    487 		const Anope::string &mask = e->GetMask();
    488 
    489 		if (mask.find("m:") == 0 || mask.find("N:") == 0)
    490 		{
    491 			Anope::string real_mask = mask.substr(2);
    492 
    493 			Entry en(this->name, real_mask);
    494 			if (en.Matches(u))
    495 				return true;
    496 		}
    497 		else if (mask.find("j:") == 0)
    498 		{
    499 			Anope::string real_mask = mask.substr(2);
    500 
    501 			Channel *c = Channel::Find(real_mask);
    502 			if (c != NULL && c->FindUser(u) != NULL)
    503 				return true;
    504 		}
    505 		else if (mask.find("M:") == 0 || mask.find("R:") == 0)
    506 		{
    507 			Anope::string real_mask = mask.substr(2);
    508 
    509 			if (u->IsIdentified() && real_mask.equals_ci(u->Account()->display))
    510 				return true;
    511 		}
    512 		else if (mask.find("r:") == 0)
    513 		{
    514 			Anope::string real_mask = mask.substr(2);
    515 
    516 			if (Anope::Match(u->realname, real_mask))
    517 				return true;
    518 		}
    519 		else if (mask.find("s:") == 0)
    520 		{
    521 			Anope::string real_mask = mask.substr(2);
    522 
    523 			if (Anope::Match(u->server->GetName(), real_mask))
    524 				return true;
    525 		}
    526 
    527 		return false;
    528 	}
    529 };
    530 
    531 struct IRCDMessageCapab : Message::Capab
    532 {
    533 	IRCDMessageCapab(Module *creator) : Message::Capab(creator, "CAPAB") { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    534 
    535 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    536 	{
    537 		if (params[0].equals_cs("START"))
    538 		{
    539 			/* reset CAPAB */
    540 			Servers::Capab.clear();
    541 			Servers::Capab.insert("NOQUIT");
    542 			IRCD->CanSVSHold = false;
    543 		}
    544 		else if (params[0].equals_cs("MODULES") && params.size() > 1)
    545 		{
    546 			if (params[1].find("m_globops.so") != Anope::string::npos)
    547 				Servers::Capab.insert("GLOBOPS");
    548 			if (params[1].find("m_services_account.so") != Anope::string::npos)
    549 				Servers::Capab.insert("SERVICES");
    550 			if (params[1].find("m_svshold.so") != Anope::string::npos)
    551 				IRCD->CanSVSHold = true;
    552 			if (params[1].find("m_chghost.so") != Anope::string::npos)
    553 				Servers::Capab.insert("CHGHOST");
    554 			if (params[1].find("m_chgident.so") != Anope::string::npos)
    555 				Servers::Capab.insert("CHGIDENT");
    556 			if (params[1].find("m_hidechans.so") != Anope::string::npos)
    557 				Servers::Capab.insert("HIDECHANS");
    558 			if (params[1].find("m_servprotect.so") != Anope::string::npos)
    559 				IRCD->DefaultPseudoclientModes = "+Ik";
    560 			if (params[1].find("m_rline.so") != Anope::string::npos)
    561 				Servers::Capab.insert("RLINE");
    562 		}
    563 		else if (params[0].equals_cs("CAPABILITIES") && params.size() > 1)
    564 		{
    565 			spacesepstream ssep(params[1]);
    566 			Anope::string capab;
    567 			while (ssep.GetToken(capab))
    568 			{
    569 				if (capab.find("CHANMODES") != Anope::string::npos)
    570 				{
    571 					Anope::string modes(capab.begin() + 10, capab.end());
    572 					commasepstream sep(modes);
    573 					Anope::string modebuf;
    574 
    575 					sep.GetToken(modebuf);
    576 					for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    577 					{
    578 						switch (modebuf[t])
    579 						{
    580 							case 'b':
    581 								ModeManager::AddChannelMode(new InspIRCdExtBan("BAN", 'b'));
    582 								continue;
    583 							case 'e':
    584 								ModeManager::AddChannelMode(new InspIRCdExtBan("EXCEPT", 'e'));
    585 								continue;
    586 							case 'I':
    587 								ModeManager::AddChannelMode(new InspIRCdExtBan("INVITEOVERRIDE", 'I'));
    588 								continue;
    589 							/* InspIRCd sends q and a here if they have no prefixes */
    590 							case 'q':
    591 								ModeManager::AddChannelMode(new ChannelModeStatus("OWNER", 'q', '@', 4));
    592 								continue;
    593 							case 'a':
    594 								ModeManager::AddChannelMode(new ChannelModeStatus("PROTECT" , 'a', '@', 3));
    595 								continue;
    596 							default:
    597 								ModeManager::AddChannelMode(new ChannelModeList("", modebuf[t]));
    598 						}
    599 					}
    600 
    601 					sep.GetToken(modebuf);
    602 					for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    603 					{
    604 						switch (modebuf[t])
    605 						{
    606 							case 'k':
    607 								ModeManager::AddChannelMode(new ChannelModeKey('k'));
    608 								continue;
    609 							default:
    610 								ModeManager::AddChannelMode(new ChannelModeParam("", modebuf[t]));
    611 						}
    612 					}
    613 
    614 					sep.GetToken(modebuf);
    615 					for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    616 					{
    617 						switch (modebuf[t])
    618 						{
    619 							case 'F':
    620 								ModeManager::AddChannelMode(new ChannelModeParam("NICKFLOOD", 'F', true));
    621 								continue;
    622 							case 'J':
    623 								ModeManager::AddChannelMode(new ChannelModeParam("NOREJOIN", 'J', true));
    624 								continue;
    625 							case 'L':
    626 								ModeManager::AddChannelMode(new ChannelModeParam("REDIRECT", 'L', true));
    627 								continue;
    628 							case 'f':
    629 								ModeManager::AddChannelMode(new ChannelModeFlood('f', true));
    630 								continue;
    631 							case 'j':
    632 								ModeManager::AddChannelMode(new ChannelModeParam("JOINFLOOD", 'j', true));
    633 								continue;
    634 							case 'l':
    635 								ModeManager::AddChannelMode(new ChannelModeParam("LIMIT", 'l', true));
    636 								continue;
    637 							default:
    638 								ModeManager::AddChannelMode(new ChannelModeParam("", modebuf[t], true));
    639 						}
    640 					}
    641 
    642 					sep.GetToken(modebuf);
    643 					for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    644 					{
    645 						switch (modebuf[t])
    646 						{
    647 							case 'A':
    648 								ModeManager::AddChannelMode(new ChannelMode("ALLINVITE", 'A'));
    649 								continue;
    650 							case 'B':
    651 								ModeManager::AddChannelMode(new ChannelMode("BLOCKCAPS", 'B'));
    652 								continue;
    653 							case 'C':
    654 								ModeManager::AddChannelMode(new ChannelMode("NOCTCP", 'C'));
    655 								continue;
    656 							case 'D':
    657 								ModeManager::AddChannelMode(new ChannelMode("DELAYEDJOIN", 'D'));
    658 								continue;
    659 							case 'G':
    660 								ModeManager::AddChannelMode(new ChannelMode("CENSOR", 'G'));
    661 								continue;
    662 							case 'K':
    663 								ModeManager::AddChannelMode(new ChannelMode("NOKNOCK", 'K'));
    664 								continue;
    665 							case 'M':
    666 								ModeManager::AddChannelMode(new ChannelMode("REGMODERATED", 'M'));
    667 								continue;
    668 							case 'N':
    669 								ModeManager::AddChannelMode(new ChannelMode("NONICK", 'N'));
    670 								continue;
    671 							case 'O':
    672 								ModeManager::AddChannelMode(new ChannelModeOperOnly("OPERONLY", 'O'));
    673 								continue;
    674 							case 'P':
    675 								ModeManager::AddChannelMode(new ChannelMode("PERM", 'P'));
    676 								continue;
    677 							case 'Q':
    678 								ModeManager::AddChannelMode(new ChannelMode("NOKICK", 'Q'));
    679 								continue;
    680 							case 'R':
    681 								ModeManager::AddChannelMode(new ChannelMode("REGISTEREDONLY", 'R'));
    682 								continue;
    683 							case 'S':
    684 								ModeManager::AddChannelMode(new ChannelMode("STRIPCOLOR", 'S'));
    685 								continue;
    686 							case 'T':
    687 								ModeManager::AddChannelMode(new ChannelMode("NONOTICE", 'T'));
    688 								continue;
    689 							case 'c':
    690 								ModeManager::AddChannelMode(new ChannelMode("BLOCKCOLOR", 'c'));
    691 								continue;
    692 							case 'i':
    693 								ModeManager::AddChannelMode(new ChannelMode("INVITE", 'i'));
    694 								continue;
    695 							case 'm':
    696 								ModeManager::AddChannelMode(new ChannelMode("MODERATED", 'm'));
    697 								continue;
    698 							case 'n':
    699 								ModeManager::AddChannelMode(new ChannelMode("NOEXTERNAL", 'n'));
    700 								continue;
    701 							case 'p':
    702 								ModeManager::AddChannelMode(new ChannelMode("PRIVATE", 'p'));
    703 								continue;
    704 							case 'r':
    705 								ModeManager::AddChannelMode(new ChannelModeNoone("REGISTERED", 'r'));
    706 								continue;
    707 							case 's':
    708 								ModeManager::AddChannelMode(new ChannelMode("SECRET", 's'));
    709 								continue;
    710 							case 't':
    711 								ModeManager::AddChannelMode(new ChannelMode("TOPIC", 't'));
    712 								continue;
    713 							case 'u':
    714 								ModeManager::AddChannelMode(new ChannelMode("AUDITORIUM", 'u'));
    715 								continue;
    716 							case 'z':
    717 								ModeManager::AddChannelMode(new ChannelMode("SSL", 'z'));
    718 								continue;
    719 							default:
    720 								ModeManager::AddChannelMode(new ChannelMode("", modebuf[t]));
    721 						}
    722 					}
    723 				}
    724 				else if (capab.find("USERMODES") != Anope::string::npos)
    725 				{
    726 					Anope::string modes(capab.begin() + 10, capab.end());
    727 					commasepstream sep(modes);
    728 					Anope::string modebuf;
    729 
    730 					while (sep.GetToken(modebuf))
    731 					{
    732 						for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    733 						{
    734 							switch (modebuf[t])
    735 							{
    736 								case 'h':
    737 									ModeManager::AddUserMode(new UserModeOperOnly("HELPOP", 'h'));
    738 									continue;
    739 								case 'B':
    740 									ModeManager::AddUserMode(new UserMode("BOT", 'B'));
    741 									continue;
    742 								case 'G':
    743 									ModeManager::AddUserMode(new UserMode("CENSOR", 'G'));
    744 									continue;
    745 								case 'H':
    746 									ModeManager::AddUserMode(new UserModeOperOnly("HIDEOPER", 'H'));
    747 									continue;
    748 								case 'I':
    749 									ModeManager::AddUserMode(new UserMode("PRIV", 'I'));
    750 									continue;
    751 								case 'Q':
    752 									ModeManager::AddUserMode(new UserModeOperOnly("HIDDEN", 'Q'));
    753 									continue;
    754 								case 'R':
    755 									ModeManager::AddUserMode(new UserMode("REGPRIV", 'R'));
    756 									continue;
    757 								case 'S':
    758 									ModeManager::AddUserMode(new UserMode("STRIPCOLOR", 'S'));
    759 									continue;
    760 								case 'W':
    761 									ModeManager::AddUserMode(new UserMode("WHOIS", 'W'));
    762 									continue;
    763 								case 'c':
    764 									ModeManager::AddUserMode(new UserMode("COMMONCHANS", 'c'));
    765 									continue;
    766 								case 'g':
    767 									ModeManager::AddUserMode(new UserMode("CALLERID", 'g'));
    768 									continue;
    769 								case 'i':
    770 									ModeManager::AddUserMode(new UserMode("INVIS", 'i'));
    771 									continue;
    772 								case 'k':
    773 									ModeManager::AddUserMode(new UserModeNoone("PROTECTED", 'k'));
    774 									continue;
    775 								case 'o':
    776 									ModeManager::AddUserMode(new UserModeOperOnly("OPER", 'o'));
    777 									continue;
    778 								case 'r':
    779 									ModeManager::AddUserMode(new UserModeNoone("REGISTERED", 'r'));
    780 									continue;
    781 								case 'w':
    782 									ModeManager::AddUserMode(new UserMode("WALLOPS", 'w'));
    783 									continue;
    784 								case 'x':
    785 									ModeManager::AddUserMode(new UserMode("CLOAK", 'x'));
    786 									continue;
    787 								case 'd':
    788 									ModeManager::AddUserMode(new UserMode("DEAF", 'd'));
    789 									continue;
    790 								default:
    791 									ModeManager::AddUserMode(new UserMode("", modebuf[t]));
    792 							}
    793 						}
    794 					}
    795 				}
    796 				else if (capab.find("PREFIX=(") != Anope::string::npos)
    797 				{
    798 					Anope::string modes(capab.begin() + 8, capab.begin() + capab.find(')'));
    799 					Anope::string chars(capab.begin() + capab.find(')') + 1, capab.end());
    800 					unsigned short level = modes.length() - 1;
    801 
    802 					for (size_t t = 0, end = modes.length(); t < end; ++t)
    803 					{
    804 						switch (modes[t])
    805 						{
    806 							case 'q':
    807 								ModeManager::AddChannelMode(new ChannelModeStatus("OWNER", 'q', chars[t], level--));
    808 								continue;
    809 							case 'a':
    810 								ModeManager::AddChannelMode(new ChannelModeStatus("PROTECT", 'a', chars[t], level--));
    811 								continue;
    812 							case 'o':
    813 								ModeManager::AddChannelMode(new ChannelModeStatus("OP", 'o', chars[t], level--));
    814 								continue;
    815 							case 'h':
    816 								ModeManager::AddChannelMode(new ChannelModeStatus("HALFOP", 'h', chars[t], level--));
    817 								continue;
    818 							case 'v':
    819 								ModeManager::AddChannelMode(new ChannelModeStatus("VOICE", 'v', chars[t], level--));
    820 								continue;
    821 							default:
    822 								ModeManager::AddChannelMode(new ChannelModeStatus("", modes[t], chars[t], level--));
    823 						}
    824 					}
    825 
    826 					ModeManager::RebuildStatusModes();
    827 				}
    828 				else if (capab.find("MAXMODES=") != Anope::string::npos)
    829 				{
    830 					Anope::string maxmodes(capab.begin() + 9, capab.end());
    831 					IRCD->MaxModes = maxmodes.is_pos_number_only() ? convertTo<unsigned>(maxmodes) : 3;
    832 				}
    833 			}
    834 		}
    835 		else if (params[0].equals_cs("END"))
    836 		{
    837 			if (!Servers::Capab.count("GLOBOPS"))
    838 			{
    839 				UplinkSocket::Message() << "ERROR :m_globops is not loaded. This is required by Anope";
    840 				Anope::QuitReason = "Remote server does not have the m_globops module loaded, and this is required.";
    841 				Anope::Quitting = true;
    842 				return;
    843 			}
    844 			if (!Servers::Capab.count("SERVICES"))
    845 			{
    846 				UplinkSocket::Message() << "ERROR :m_services_account.so is not loaded. This is required by Anope";
    847 				Anope::QuitReason = "ERROR: Remote server does not have the m_services_account module loaded, and this is required.";
    848 				Anope::Quitting = true;
    849 				return;
    850 			}
    851 			if (!Servers::Capab.count("HIDECHANS"))
    852 			{
    853 				UplinkSocket::Message() << "ERROR :m_hidechans.so is not loaded. This is required by Anope";
    854 				Anope::QuitReason = "ERROR: Remote server does not have the m_hidechans module loaded, and this is required.";
    855 				Anope::Quitting = true;
    856 				return;
    857 			}
    858 			if (!IRCD->CanSVSHold)
    859 				Log() << "SVSHOLD missing, Usage disabled until module is loaded.";
    860 			if (!Servers::Capab.count("CHGHOST"))
    861 				Log() << "CHGHOST missing, Usage disabled until module is loaded.";
    862 			if (!Servers::Capab.count("CHGIDENT"))
    863 				Log() << "CHGIDENT missing, Usage disabled until module is loaded.";
    864 		}
    865 
    866 		Message::Capab::Run(source, params);
    867 	}
    868 };
    869 
    870 struct IRCDMessageChgIdent : IRCDMessage
    871 {
    872 	IRCDMessageChgIdent(Module *creator) : IRCDMessage(creator, "CHGIDENT", 2) { }
    873 
    874 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    875 	{
    876 		User *u = User::Find(params[0]);
    877 		if (u)
    878 			u->SetIdent(params[1]);
    879 	}
    880 };
    881 
    882 struct IRCDMessageChgName : IRCDMessage
    883 {
    884 	IRCDMessageChgName(Module *creator, const Anope::string &n) : IRCDMessage(creator, n, 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
    885 
    886 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    887 	{
    888 		source.GetUser()->SetRealname(params[0]);
    889 	}
    890 };
    891 
    892 struct IRCDMessageEncap : IRCDMessage
    893 {
    894 	IRCDMessageEncap(Module *creator) : IRCDMessage(creator, "ENCAP", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    895 
    896 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    897 	{
    898 		if (!Anope::Match(Me->GetSID(), params[0]) && !Anope::Match(Me->GetName(), params[0]))
    899 			return;
    900 
    901 		if (SASL::sasl && params[1] == "SASL" && params.size() >= 6)
    902 		{
    903 			SASL::Message m;
    904 			m.source = params[2];
    905 			m.target = params[3];
    906 			m.type = params[4];
    907 			m.data = params[5];
    908 			m.ext = params.size() > 6 ? params[6] : "";
    909 
    910 			SASL::sasl->ProcessMessage(m);
    911 		}
    912 	}
    913 };
    914 
    915 struct IRCDMessageEndburst : IRCDMessage
    916 {
    917 	IRCDMessageEndburst(Module *creator) : IRCDMessage(creator, "ENDBURST", 0) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    918 
    919 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    920 	{
    921 		Server *s = source.GetServer();
    922 
    923 		Log(LOG_DEBUG) << "Processed ENDBURST for " << s->GetName();
    924 
    925 		s->Sync(true);
    926 	}
    927 };
    928 
    929 struct IRCDMessageFHost : IRCDMessage
    930 {
    931 	IRCDMessageFHost(Module *creator, const Anope::string &n) : IRCDMessage(creator, n, 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
    932 
    933 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    934 	{
    935 		source.GetUser()->SetDisplayedHost(params[0]);
    936 	}
    937 };
    938 
    939 struct IRCDMessageFJoin : IRCDMessage
    940 {
    941 	IRCDMessageFJoin(Module *creator) : IRCDMessage(creator, "FJOIN", 2) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    942 
    943 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    944 	{
    945 		Anope::string modes;
    946 		if (params.size() >= 3)
    947 		{
    948 			for (unsigned i = 2; i < params.size() - 1; ++i)
    949 				modes += " " + params[i];
    950 			if (!modes.empty())
    951 				modes.erase(modes.begin());
    952 		}
    953 
    954 		std::list<Message::Join::SJoinUser> users;
    955 
    956 		spacesepstream sep(params[params.size() - 1]);
    957 		Anope::string buf;
    958 		while (sep.GetToken(buf))
    959 		{
    960 			Message::Join::SJoinUser sju;
    961 
    962 			/* Loop through prefixes and find modes for them */
    963 			for (char c; (c = buf[0]) != ',' && c;)
    964 			{
    965 				buf.erase(buf.begin());
    966 				sju.first.AddMode(c);
    967 			}
    968 			/* Erase the , */
    969 			if (!buf.empty())
    970 				buf.erase(buf.begin());
    971 
    972 			sju.second = User::Find(buf);
    973 			if (!sju.second)
    974 			{
    975 				Log(LOG_DEBUG) << "FJOIN for nonexistent user " << buf << " on " << params[0];
    976 				continue;
    977 			}
    978 
    979 			users.push_back(sju);
    980 		}
    981 
    982 		time_t ts = Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime;
    983 		Message::Join::SJoin(source, params[0], ts, modes, users);
    984 	}
    985 };
    986 
    987 struct IRCDMessageFMode : IRCDMessage
    988 {
    989 	IRCDMessageFMode(Module *creator) : IRCDMessage(creator, "FMODE", 3) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    990 
    991 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    992 	{
    993 		/* :source FMODE #test 12345678 +nto foo */
    994 
    995 		Anope::string modes = params[2];
    996 		for (unsigned n = 3; n < params.size(); ++n)
    997 			modes += " " + params[n];
    998 
    999 		Channel *c = Channel::Find(params[0]);
   1000 		time_t ts;
   1001 
   1002 		try
   1003 		{
   1004 			ts = convertTo<time_t>(params[1]);
   1005 		}
   1006 		catch (const ConvertException &)
   1007 		{
   1008 			ts = 0;
   1009 		}
   1010 
   1011 		if (c)
   1012 			c->SetModesInternal(source, modes, ts);
   1013 	}
   1014 };
   1015 
   1016 struct IRCDMessageFTopic : IRCDMessage
   1017 {
   1018 	IRCDMessageFTopic(Module *creator) : IRCDMessage(creator, "FTOPIC", 4) { }
   1019 
   1020 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1021 	{
   1022 		/* :source FTOPIC channel topicts setby :topic */
   1023 
   1024 		Channel *c = Channel::Find(params[0]);
   1025 		if (c)
   1026 			c->ChangeTopicInternal(NULL, params[2], params[3], Anope::string(params[1]).is_pos_number_only() ? convertTo<time_t>(params[1]) : Anope::CurTime);
   1027 	}
   1028 };
   1029 
   1030 struct IRCDMessageIdle : IRCDMessage
   1031 {
   1032 	IRCDMessageIdle(Module *creator) : IRCDMessage(creator, "IDLE", 1) { }
   1033 
   1034 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1035 	{
   1036 		BotInfo *bi = BotInfo::Find(params[0]);
   1037 		if (bi)
   1038 			UplinkSocket::Message(bi) << "IDLE " << source.GetSource() << " " << Anope::StartTime << " " << (Anope::CurTime - bi->lastmsg);
   1039 		else
   1040 		{
   1041 			User *u = User::Find(params[0]);
   1042 			if (u && u->server == Me)
   1043 				UplinkSocket::Message(u) <<  "IDLE " << source.GetSource() << " " << Anope::StartTime << " 0";
   1044 		}
   1045 	}
   1046 };
   1047 
   1048 /*
   1049  *   source     = numeric of the sending server
   1050  *   params[0]  = uuid
   1051  *   params[1]  = metadata name
   1052  *   params[2]  = data
   1053  */
   1054 struct IRCDMessageMetadata : IRCDMessage
   1055 {
   1056 	IRCDMessageMetadata(Module *creator) : IRCDMessage(creator, "METADATA", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
   1057 
   1058 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1059 	{
   1060 		if (isdigit(params[0][0]))
   1061 		{
   1062 			if (params[1].equals_cs("accountname"))
   1063 			{
   1064 				User *u = User::Find(params[0]);
   1065 				NickCore *nc = NickCore::Find(params[2]);
   1066 				if (u && nc)
   1067 					u->Login(nc);
   1068 			}
   1069 
   1070 			/*
   1071 			 *   possible incoming ssl_cert messages:
   1072 			 *   Received: :409 METADATA 409AAAAAA ssl_cert :vTrSe c38070ce96e41cc144ed6590a68d45a6 <...> <...>
   1073 			 *   Received: :409 METADATA 409AAAAAC ssl_cert :vTrSE Could not get peer certificate: error:00000000:lib(0):func(0):reason(0)
   1074 			 */
   1075 			else if (params[1].equals_cs("ssl_cert"))
   1076 			{
   1077 				User *u = User::Find(params[0]);
   1078 				if (!u)
   1079 					return;
   1080 				u->Extend<bool>("ssl");
   1081 				Anope::string data = params[2].c_str();
   1082 				size_t pos1 = data.find(' ') + 1;
   1083 				size_t pos2 = data.find(' ', pos1);
   1084 				if ((pos2 - pos1) >= 32) // inspircd supports md5 and sha1 fingerprint hashes -> size 32 or 40 bytes.
   1085 				{
   1086 					u->fingerprint = data.substr(pos1, pos2 - pos1);
   1087 				}
   1088 				FOREACH_MOD(OnFingerprint, (u));
   1089 			}
   1090 		}
   1091 		else if (params[0][0] == '#')
   1092 		{
   1093 		}
   1094 		else if (params[0] == "*")
   1095 		{
   1096 			// Wed Oct  3 15:40:27 2012: S[14] O :20D METADATA * modules :-m_svstopic.so
   1097 
   1098 			if (params[1].equals_cs("modules") && !params[2].empty())
   1099 			{
   1100 				// only interested when it comes from our uplink
   1101 				Server* server = source.GetServer();
   1102 				if (!server || server->GetUplink() != Me)
   1103 					return;
   1104 
   1105 				bool plus = (params[2][0] == '+');
   1106 				if (!plus && params[2][0] != '-')
   1107 					return;
   1108 
   1109 				bool required = false;
   1110 				Anope::string capab, module = params[2].substr(1);
   1111 
   1112 				if (module.equals_cs("m_services_account.so"))
   1113 					required = true;
   1114 				else if (module.equals_cs("m_hidechans.so"))
   1115 					required = true;
   1116 				else if (module.equals_cs("m_chghost.so"))
   1117 					capab = "CHGHOST";
   1118 				else if (module.equals_cs("m_chgident.so"))
   1119 					capab = "CHGIDENT";
   1120 				else if (module.equals_cs("m_svshold.so"))
   1121 					capab = "SVSHOLD";
   1122 				else if (module.equals_cs("m_rline.so"))
   1123 					capab = "RLINE";
   1124 				else if (module.equals_cs("m_topiclock.so"))
   1125 					capab = "TOPICLOCK";
   1126 				else
   1127 					return;
   1128 
   1129 				if (required)
   1130 				{
   1131 					if (!plus)
   1132 						Log() << "Warning: InspIRCd unloaded module " << module << ", Anope won't function correctly without it";
   1133 				}
   1134 				else
   1135 				{
   1136 					if (plus)
   1137 						Servers::Capab.insert(capab);
   1138 					else
   1139 						Servers::Capab.erase(capab);
   1140 
   1141 					Log() << "InspIRCd " << (plus ? "loaded" : "unloaded") << " module " << module << ", adjusted functionality";
   1142 				}
   1143 
   1144 			}
   1145 		}
   1146 	}
   1147 };
   1148 
   1149 struct IRCDMessageMode : IRCDMessage
   1150 {
   1151 	IRCDMessageMode(Module *creator) : IRCDMessage(creator, "MODE", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
   1152 
   1153 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1154 	{
   1155 		if (IRCD->IsChannelValid(params[0]))
   1156 		{
   1157 			Channel *c = Channel::Find(params[0]);
   1158 
   1159 			Anope::string modes = params[1];
   1160 			for (unsigned n = 2; n < params.size(); ++n)
   1161 				modes += " " + params[n];
   1162 
   1163 			if (c)
   1164 				c->SetModesInternal(source, modes);
   1165 		}
   1166 		else
   1167 		{
   1168 			/* InspIRCd lets opers change another
   1169 			   users modes, we have to kludge this
   1170 			   as it slightly breaks RFC1459
   1171 			 */
   1172 			User *u = User::Find(params[0]);
   1173 			if (u)
   1174 				u->SetModesInternal(source, "%s", params[1].c_str());
   1175 		}
   1176 	}
   1177 };
   1178 
   1179 struct IRCDMessageNick : IRCDMessage
   1180 {
   1181 	IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 2) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
   1182 
   1183 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1184 	{
   1185 		source.GetUser()->ChangeNick(params[0]);
   1186 	}
   1187 };
   1188 
   1189 struct IRCDMessageOperType : IRCDMessage
   1190 {
   1191 	IRCDMessageOperType(Module *creator) : IRCDMessage(creator, "OPERTYPE", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_USER); }
   1192 
   1193 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1194 	{
   1195 		/* opertype is equivalent to mode +o because servers
   1196 		   don't do this directly */
   1197 		User *u = source.GetUser();
   1198 		if (!u->HasMode("OPER"))
   1199 			u->SetModesInternal(source, "+o");
   1200 	}
   1201 };
   1202 
   1203 struct IRCDMessageRSQuit : IRCDMessage
   1204 {
   1205 	IRCDMessageRSQuit(Module *creator) : IRCDMessage(creator, "RSQUIT", 1) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
   1206 
   1207 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1208 	{
   1209 		Server *s = Server::Find(params[0]);
   1210 		const Anope::string &reason = params.size() > 1 ? params[1] : "";
   1211 		if (!s)
   1212 			return;
   1213 
   1214 		UplinkSocket::Message(Me) << "SQUIT " << s->GetSID() << " :" << reason;
   1215 		s->Delete(s->GetName() + " " + s->GetUplink()->GetName());
   1216 	}
   1217 };
   1218 
   1219 struct IRCDMessageSetIdent : IRCDMessage
   1220 {
   1221 	IRCDMessageSetIdent(Module *creator) : IRCDMessage(creator, "SETIDENT", 0) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
   1222 
   1223 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1224 	{
   1225 		source.GetUser()->SetIdent(params[0]);
   1226 	}
   1227 };
   1228 
   1229 struct IRCDMessageServer : IRCDMessage
   1230 {
   1231 	IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 5) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
   1232 
   1233 	/*
   1234 	 * [Nov 04 00:08:46.308435 2009] debug: Received: SERVER irc.inspircd.com pass 0 964 :Testnet Central!
   1235 	 * 0: name
   1236 	 * 1: pass
   1237 	 * 2: hops
   1238 	 * 3: numeric
   1239 	 * 4: desc
   1240 	 */
   1241 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1242 	{
   1243 		unsigned int hops = Anope::string(params[2]).is_pos_number_only() ? convertTo<unsigned>(params[2]) : 0;
   1244 		new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, params[4], params[3]);
   1245 	}
   1246 };
   1247 
   1248 struct IRCDMessageSQuit : Message::SQuit
   1249 {
   1250 	IRCDMessageSQuit(Module *creator) : Message::SQuit(creator) { }
   1251 
   1252 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1253 	{
   1254 		if (params[0] == rsquit_id || params[0] == rsquit_server)
   1255 		{
   1256 			/* squit for a recently squit server, introduce the juped server now */
   1257 			Server *s = Server::Find(rsquit_server);
   1258 
   1259 			rsquit_id.clear();
   1260 			rsquit_server.clear();
   1261 
   1262 			if (s && s->IsJuped())
   1263 				IRCD->SendServer(s);
   1264 		}
   1265 		else
   1266 			Message::SQuit::Run(source, params);
   1267 	}
   1268 };
   1269 
   1270 struct IRCDMessageTime : IRCDMessage
   1271 {
   1272 	IRCDMessageTime(Module *creator) : IRCDMessage(creator, "TIME", 2) { }
   1273 
   1274 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1275 	{
   1276 		UplinkSocket::Message(Me) << "TIME " << source.GetSource() << " " << params[1] << " " << Anope::CurTime;
   1277 	}
   1278 };
   1279 
   1280 struct IRCDMessageUID : IRCDMessage
   1281 {
   1282 	IRCDMessageUID(Module *creator) : IRCDMessage(creator, "UID", 8) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
   1283 
   1284 	/*
   1285 	 * [Nov 03 22:09:58.176252 2009] debug: Received: :964 UID 964AAAAAC 1225746297 w00t2 localhost testnet.user w00t 127.0.0.1 1225746302 +iosw +ACGJKLNOQcdfgjklnoqtx :Robin Burchell <w00t@inspircd.org>
   1286 	 * 0: uid
   1287 	 * 1: ts
   1288 	 * 2: nick
   1289 	 * 3: host
   1290 	 * 4: dhost
   1291 	 * 5: ident
   1292 	 * 6: ip
   1293 	 * 7: signon
   1294 	 * 8+: modes and params -- IMPORTANT, some modes (e.g. +s) may have parameters. So don't assume a fixed position of realname!
   1295 	 * last: realname
   1296 	 */
   1297 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1298 	{
   1299 		time_t ts = convertTo<time_t>(params[1]);
   1300 
   1301 		Anope::string modes = params[8];
   1302 		for (unsigned i = 9; i < params.size() - 1; ++i)
   1303 			modes += " " + params[i];
   1304 
   1305 		NickAlias *na = NULL;
   1306 		if (SASL::sasl)
   1307 			for (std::list<SASLUser>::iterator it = saslusers.begin(); it != saslusers.end();)
   1308 			{
   1309 				SASLUser &u = *it;
   1310 
   1311 				if (u.created + 30 < Anope::CurTime)
   1312 					it = saslusers.erase(it);
   1313 				else if (u.uid == params[0])
   1314 				{
   1315 					na = NickAlias::Find(u.acc);
   1316 					it = saslusers.erase(it);
   1317 				}
   1318 				else
   1319 					++it;
   1320 			}
   1321 
   1322 		User *u = User::OnIntroduce(params[2], params[5], params[3], params[4], params[6], source.GetServer(), params[params.size() - 1], ts, modes, params[0], na ? *na->nc : NULL);
   1323 		if (u)
   1324 			u->signon = convertTo<time_t>(params[7]);
   1325 	}
   1326 };
   1327 
   1328 class ProtoInspIRCd12 : public Module
   1329 {
   1330 	InspIRCd12Proto ircd_proto;
   1331 	ExtensibleItem<bool> ssl;
   1332 
   1333 	/* Core message handlers */
   1334 	Message::Away message_away;
   1335 	Message::Error message_error;
   1336 	Message::Invite message_invite;
   1337 	Message::Join message_join;
   1338 	Message::Kick message_kick;
   1339 	Message::Kill message_kill;
   1340 	Message::MOTD message_motd;
   1341 	Message::Notice message_notice;
   1342 	Message::Part message_part;
   1343 	Message::Ping message_ping;
   1344 	Message::Privmsg message_privmsg;
   1345 	Message::Quit message_quit;
   1346 	Message::Stats message_stats;
   1347 	Message::Topic message_topic;
   1348 
   1349 	/* Our message handlers */
   1350 	IRCDMessageChgIdent message_chgident;
   1351 	IRCDMessageChgName message_setname, message_chgname;
   1352 	IRCDMessageCapab message_capab;
   1353 	IRCDMessageEncap message_encap;
   1354 	IRCDMessageEndburst message_endburst;
   1355 	IRCDMessageFHost message_fhost, message_sethost;
   1356 	IRCDMessageFJoin message_fjoin;
   1357 	IRCDMessageFMode message_fmode;
   1358 	IRCDMessageFTopic message_ftopic;
   1359 	IRCDMessageIdle message_idle;
   1360 	IRCDMessageMetadata message_metadata;
   1361 	IRCDMessageMode message_mode;
   1362 	IRCDMessageNick message_nick;
   1363 	IRCDMessageOperType message_opertype;
   1364 	IRCDMessageRSQuit message_rsquit;
   1365 	IRCDMessageSetIdent message_setident;
   1366 	IRCDMessageServer message_server;
   1367 	IRCDMessageSQuit message_squit;
   1368 	IRCDMessageTime message_time;
   1369 	IRCDMessageUID message_uid;
   1370 
   1371  public:
   1372 	ProtoInspIRCd12(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR),
   1373 		ircd_proto(this), ssl(this, "ssl"),
   1374 		message_away(this), message_error(this), message_invite(this), message_join(this), message_kick(this), message_kill(this),
   1375 		message_motd(this), message_notice(this), message_part(this), message_ping(this), message_privmsg(this), message_quit(this),
   1376 		message_stats(this), message_topic(this),
   1377 
   1378 		message_chgident(this), message_setname(this, "SETNAME"), message_chgname(this, "FNAME"), message_capab(this), message_encap(this),
   1379 		message_endburst(this),
   1380 		message_fhost(this, "FHOST"), message_sethost(this, "SETHOST"), message_fjoin(this), message_fmode(this), message_ftopic(this),
   1381 		message_idle(this), message_metadata(this), message_mode(this), message_nick(this), message_opertype(this), message_rsquit(this),
   1382 		message_setident(this), message_server(this), message_squit(this), message_time(this), message_uid(this)
   1383 	{
   1384 		Servers::Capab.insert("NOQUIT");
   1385 	}
   1386 
   1387 	void OnUserNickChange(User *u, const Anope::string &) anope_override
   1388 	{
   1389 		/* InspIRCd 1.2 doesn't set -r on nick change, remove -r here. Note that if we have to set +r later
   1390 		 * this will cancel out this -r, resulting in no mode changes.
   1391 		 *
   1392 		 * Do not set -r if we don't have a NickServ loaded - DP
   1393 		 */
   1394 		BotInfo *NickServ = Config->GetClient("NickServ");
   1395 		if (NickServ)
   1396 			u->RemoveMode(NickServ, "REGISTERED");
   1397 	}
   1398 };
   1399 
   1400 MODULE_INIT(ProtoInspIRCd12)