anope

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

unreal.cpp (41304B)

      1 /* Unreal IRCD 3.2.x 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/cs_mode.h"
     14 #include "modules/sasl.h"
     15 
     16 class UnrealIRCdProto : public IRCDProto
     17 {
     18  public:
     19 	UnrealIRCdProto(Module *creator) : IRCDProto(creator, "UnrealIRCd 3.2.x")
     20 	{
     21 		DefaultPseudoclientModes = "+Soiq";
     22 		CanSVSNick = true;
     23 		CanSVSJoin = true;
     24 		CanSetVHost = true;
     25 		CanSetVIdent = true;
     26 		CanSNLine = true;
     27 		CanSQLine = true;
     28 		CanSZLine = true;
     29 		CanSVSHold = true;
     30 		CanSVSO = true;
     31 		MaxModes = 12;
     32 	}
     33 
     34  private:
     35 	/* SVSNOOP */
     36 	void SendSVSNOOP(const Server *server, bool set) anope_override
     37 	{
     38 		UplinkSocket::Message() << "SVSNOOP " << server->GetName() << " " << (set ? "+" : "-");
     39 	}
     40 
     41 	void SendAkillDel(const XLine *x) anope_override
     42 	{
     43 		if (x->IsRegex() || x->HasNickOrReal())
     44 			return;
     45 
     46 		/* ZLine if we can instead */
     47 		if (x->GetUser() == "*")
     48 		{
     49 			cidr a(x->GetHost());
     50 			if (a.valid())
     51 			{
     52 				IRCD->SendSZLineDel(x);
     53 				return;
     54 			}
     55 		}
     56 
     57 		UplinkSocket::Message() << "TKL - G " << x->GetUser() << " " << x->GetHost() << " " << x->by;
     58 	}
     59 
     60 	void SendTopic(const MessageSource &source, Channel *c) anope_override
     61 	{
     62 		UplinkSocket::Message(source) << "TOPIC " << c->name << " " << c->topic_setter << " " << c->topic_ts << " :" << c->topic;
     63 	}
     64 
     65 	void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
     66 	{
     67 		UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg;
     68 	}
     69 
     70 	void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
     71 	{
     72 		UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg;
     73 	}
     74 
     75 	void SendVhostDel(User *u) anope_override
     76 	{
     77 		BotInfo *HostServ = Config->GetClient("HostServ");
     78 		u->RemoveMode(HostServ, "CLOAK");
     79 		u->RemoveMode(HostServ, "VHOST");
     80 		ModeManager::ProcessModes();
     81 		u->SetMode(HostServ, "CLOAK");
     82 	}
     83 
     84 	void SendAkill(User *u, XLine *x) anope_override
     85 	{
     86 		if (x->IsRegex() || x->HasNickOrReal())
     87 		{
     88 			if (!u)
     89 			{
     90 				/* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */
     91 				for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
     92 					if (x->manager->Check(it->second, x))
     93 						this->SendAkill(it->second, x);
     94 				return;
     95 			}
     96 
     97 			const XLine *old = x;
     98 
     99 			if (old->manager->HasEntry("*@" + u->host))
    100 				return;
    101 
    102 			/* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */
    103 			XLine *xline = new XLine("*@" + u->host, old->by, old->expires, old->reason, old->id);
    104 			old->manager->AddXLine(xline);
    105 			x = xline;
    106 
    107 			Log(Config->GetClient("OperServ"), "akill") << "AKILL: Added an akill for " << x->mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->mask;
    108 		}
    109 
    110 		/* ZLine if we can instead */
    111 		if (x->GetUser() == "*")
    112 		{
    113 			cidr a(x->GetHost());
    114 			if (a.valid())
    115 			{
    116 				IRCD->SendSZLine(u, x);
    117 				return;
    118 			}
    119 		}
    120 
    121 		// Calculate the time left before this would expire, capping it at 2 days
    122 		time_t timeleft = x->expires - Anope::CurTime;
    123 		if (timeleft > 172800 || !x->expires)
    124 			timeleft = 172800;
    125 		UplinkSocket::Message() << "TKL + G " << x->GetUser() << " " << x->GetHost() << " " << x->by << " " << Anope::CurTime + timeleft << " " << x->created << " :" << x->GetReason();
    126 	}
    127 
    128 	void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override
    129 	{
    130 		UplinkSocket::Message(source) << "SVSKILL " << user->nick << " :" << buf;
    131 		user->KillInternal(source, buf);
    132 	}
    133 
    134 	void SendModeInternal(const MessageSource &source, User *u, const Anope::string &buf) anope_override
    135 	{
    136 		UplinkSocket::Message(source) << "SVS2MODE " << u->nick <<" " << buf;
    137 	}
    138 
    139 	void SendClientIntroduction(User *u) anope_override
    140 	{
    141 		Anope::string modes = "+" + u->GetModes();
    142 		UplinkSocket::Message() << "NICK " << u->nick << " 1 " << u->timestamp << " " << u->GetIdent() << " " << u->host << " " << u->server->GetName() << " 0 " << modes << " " << u->host << " * :" << u->realname;
    143 	}
    144 
    145 	/* SERVER name hop descript */
    146 	/* Unreal 3.2 actually sends some info about itself in the descript area */
    147 	void SendServer(const Server *server) anope_override
    148 	{
    149 		if (!server->GetSID().empty() && server == Me)
    150 			UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetHops() << " :U0-*-" << server->GetSID() << " " << server->GetDescription();
    151 		else
    152 			UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetHops() << " :" << server->GetDescription();
    153 	}
    154 
    155 	/* JOIN */
    156 	void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override
    157 	{
    158 		UplinkSocket::Message(Me) << "SJOIN " << c->creation_time << " " << c->name << " :" << user->nick;
    159 		if (status)
    160 		{
    161 			/* First save the channel status incase uc->Status == status */
    162 			ChannelStatus cs = *status;
    163 			/* If the user is internally on the channel with flags, kill them so that
    164 			 * the stacker will allow this.
    165 			 */
    166 			ChanUserContainer *uc = c->FindUser(user);
    167 			if (uc != NULL)
    168 				uc->status.Clear();
    169 
    170 			BotInfo *setter = BotInfo::Find(user->GetUID());
    171 			for (size_t i = 0; i < cs.Modes().length(); ++i)
    172 				c->SetMode(setter, ModeManager::FindChannelModeByChar(cs.Modes()[i]), user->GetUID(), false);
    173 
    174 			if (uc != NULL)
    175 				uc->status = cs;
    176 		}
    177 	}
    178 
    179 	/* unsqline
    180 	*/
    181 	void SendSQLineDel(const XLine *x) anope_override
    182 	{
    183 		UplinkSocket::Message() << "UNSQLINE " << x->mask;
    184 	}
    185 
    186 	/* SQLINE */
    187 	/*
    188 	** - Unreal will translate this to TKL for us
    189 	**
    190 	*/
    191 	void SendSQLine(User *, const XLine *x) anope_override
    192 	{
    193 		UplinkSocket::Message() << "SQLINE " << x->mask << " :" << x->GetReason();
    194 	}
    195 
    196 	/*
    197 	** svso
    198 	**	  parv[0] = sender prefix
    199 	**	  parv[1] = nick
    200 	**	  parv[2] = options
    201 	*/
    202 	void SendSVSO(BotInfo *source, const Anope::string &nick, const Anope::string &flag) anope_override
    203 	{
    204 		UplinkSocket::Message(source) << "SVSO " << nick << " " << flag;
    205 	}
    206 
    207 	/* Functions that use serval cmd functions */
    208 
    209 	void SendVhost(User *u, const Anope::string &vIdent, const Anope::string &vhost) anope_override
    210 	{
    211 		if (!vIdent.empty())
    212 			UplinkSocket::Message(Me) << "CHGIDENT " << u->nick << " " << vIdent;
    213 		if (!vhost.empty())
    214 			UplinkSocket::Message(Me) << "CHGHOST " << u->nick << " " << vhost;
    215 	}
    216 
    217 	void SendConnect() anope_override
    218 	{
    219 		/*
    220 		   NICKv2 = Nick Version 2
    221 		   VHP    = Sends hidden host
    222 		   UMODE2 = sends UMODE2 on user modes
    223 		   NICKIP = Sends IP on NICK
    224 		   TOKEN  = Use tokens to talk
    225 		   SJ3    = Supports SJOIN
    226 		   NOQUIT = No Quit
    227 		   TKLEXT = Extended TKL we don't use it but best to have it
    228 		   SJB64  = Base64 encoded time stamps
    229 		   ESVID  = Allows storing account names as services stamp
    230 		   MLOCK  = Supports the MLOCK server command
    231 		   VL     = Version Info
    232 		   NS     = Config->Numeric Server
    233 		*/
    234 		Anope::string protoctl = "NICKv2 VHP UMODE2 NICKIP SJOIN SJOIN2 SJ3 NOQUIT TKLEXT ESVID MLOCK VL";
    235 		if (!Me->GetSID().empty())
    236 			protoctl += " VL";
    237 		UplinkSocket::Message() << "PROTOCTL " << protoctl;
    238 		UplinkSocket::Message() << "PASS :" << Config->Uplinks[Anope::CurrentUplink].password;
    239 		SendServer(Me);
    240 	}
    241 
    242 	/* SVSHOLD - set */
    243 	void SendSVSHold(const Anope::string &nick, time_t t) anope_override
    244 	{
    245 		UplinkSocket::Message() << "TKL + Q H " << nick << " " << Me->GetName() << " " << Anope::CurTime + t << " " << Anope::CurTime << " :Being held for registered user";
    246 	}
    247 
    248 	/* SVSHOLD - release */
    249 	void SendSVSHoldDel(const Anope::string &nick) anope_override
    250 	{
    251 		UplinkSocket::Message() << "TKL - Q * " << nick << " " << Me->GetName();
    252 	}
    253 
    254 	/* UNSGLINE */
    255 	/*
    256 	 * SVSNLINE - :realname mask
    257 	*/
    258 	void SendSGLineDel(const XLine *x) anope_override
    259 	{
    260 		UplinkSocket::Message() << "SVSNLINE - :" << x->mask;
    261 	}
    262 
    263 	/* UNSZLINE */
    264 	void SendSZLineDel(const XLine *x) anope_override
    265 	{
    266 		UplinkSocket::Message() << "TKL - Z * " << x->GetHost() << " " << x->by;
    267 	}
    268 
    269 	/* SZLINE */
    270 	void SendSZLine(User *, const XLine *x) anope_override
    271 	{
    272 		// Calculate the time left before this would expire, capping it at 2 days
    273 		time_t timeleft = x->expires - Anope::CurTime;
    274 		if (timeleft > 172800 || !x->expires)
    275 			timeleft = 172800;
    276 		UplinkSocket::Message() << "TKL + Z * " << x->GetHost() << " " << x->by << " " << Anope::CurTime + timeleft << " " << x->created << " :" << x->GetReason();
    277 	}
    278 
    279 	/* SGLINE */
    280 	/*
    281 	 * SVSNLINE + reason_where_is_space :realname mask with spaces
    282 	*/
    283 	void SendSGLine(User *, const XLine *x) anope_override
    284 	{
    285 		Anope::string edited_reason = x->GetReason();
    286 		edited_reason = edited_reason.replace_all_cs(" ", "_");
    287 		UplinkSocket::Message() << "SVSNLINE + " << edited_reason << " :" << x->mask;
    288 	}
    289 
    290 	/* svsjoin
    291 		parv[0] - sender
    292 		parv[1] - nick to make join
    293 		parv[2] - channel to join
    294 		parv[3] - (optional) channel key(s)
    295 	*/
    296 	/* In older Unreal SVSJOIN and SVSNLINE tokens were mixed so SVSJOIN and SVSNLINE are broken
    297 	   when coming from a none TOKEN'd server
    298 	*/
    299 	void SendSVSJoin(const MessageSource &source, User *user, const Anope::string &chan, const Anope::string &param) anope_override
    300 	{
    301 		if (!param.empty())
    302 			UplinkSocket::Message(source) << "SVSJOIN " << user->GetUID() << " " << chan << " :" << param;
    303 		else
    304 			UplinkSocket::Message(source) << "SVSJOIN " << user->GetUID() << " " << chan;
    305 	}
    306 
    307 	void SendSVSPart(const MessageSource &source, User *user, const Anope::string &chan, const Anope::string &param) anope_override
    308 	{
    309 		if (!param.empty())
    310 			UplinkSocket::Message(source) << "SVSPART " << user->GetUID() << " " << chan << " :" << param;
    311 		else
    312 			UplinkSocket::Message(source) << "SVSPART " << user->GetUID() << " " << chan;
    313 	}
    314 
    315 	void SendSWhois(const MessageSource &source, const Anope::string &who, const Anope::string &mask) anope_override
    316 	{
    317 		UplinkSocket::Message(source) << "SWHOIS " << who << " :" << mask;
    318 	}
    319 
    320 	void SendEOB() anope_override
    321 	{
    322 		UplinkSocket::Message(Me) << "EOS";
    323 	}
    324 
    325 	bool IsNickValid(const Anope::string &nick) anope_override
    326 	{
    327 		if (nick.equals_ci("ircd") || nick.equals_ci("irc"))
    328 			return false;
    329 
    330 		return IRCDProto::IsNickValid(nick);
    331 	}
    332 
    333 	bool IsChannelValid(const Anope::string &chan) anope_override
    334 	{
    335 		if (chan.find(':') != Anope::string::npos)
    336 			return false;
    337 
    338 		return IRCDProto::IsChannelValid(chan);
    339 	}
    340 
    341 	bool IsExtbanValid(const Anope::string &mask) anope_override
    342 	{
    343 		return mask.length() >= 4 && mask[0] == '~' && mask[2] == ':';
    344 	}
    345 
    346 	void SendLogin(User *u, NickAlias *na) anope_override
    347 	{
    348 		/* 3.2.10.4+ treats users logged in with accounts as fully registered, even if -r, so we can not set this here. Just use the timestamp. */
    349 		if (Servers::Capab.count("ESVID") > 0 && !na->nc->HasExt("UNCONFIRMED"))
    350 			IRCD->SendMode(Config->GetClient("NickServ"), u, "+d %s", na->nc->display.c_str());
    351 		else
    352 			IRCD->SendMode(Config->GetClient("NickServ"), u, "+d %d", u->signon);
    353 	}
    354 
    355 	void SendLogout(User *u) anope_override
    356 	{
    357 		IRCD->SendMode(Config->GetClient("NickServ"), u, "+d 0");
    358 	}
    359 
    360 	void SendChannel(Channel *c) anope_override
    361 	{
    362 		/* Unreal does not support updating a channels TS without actually joining a user,
    363 		 * so we will join and part us now
    364 		 */
    365 		BotInfo *bi = c->ci->WhoSends();
    366 		if (!bi)
    367 			;
    368 		else if (c->FindUser(bi) == NULL)
    369 		{
    370 			bi->Join(c);
    371 			bi->Part(c);
    372 		}
    373 		else
    374 		{
    375 			bi->Part(c);
    376 			bi->Join(c);
    377 		}
    378 	}
    379 
    380 	void SendSASLMessage(const SASL::Message &message) anope_override
    381 	{
    382 		size_t p = message.target.find('!');
    383 		if (p == Anope::string::npos)
    384 			return;
    385 
    386 		UplinkSocket::Message(BotInfo::Find(message.source)) << "SASL " << message.target.substr(0, p) << " " << message.target << " " << message.type << " " << message.data << (message.ext.empty() ? "" : " " + message.ext);
    387 	}
    388 
    389 	void SendSVSLogin(const Anope::string &uid, const Anope::string &acc, const Anope::string &vident, const Anope::string &vhost) anope_override
    390 	{
    391 		size_t p = uid.find('!');
    392 		if (p == Anope::string::npos)
    393 			return;
    394 		UplinkSocket::Message(Me) << "SVSLOGIN " << uid.substr(0, p) << " " << uid << " " << acc;
    395 	}
    396 
    397 	bool IsIdentValid(const Anope::string &ident) anope_override
    398 	{
    399 		if (ident.empty() || ident.length() > Config->GetBlock("networkinfo")->Get<unsigned>("userlen"))
    400 			return false;
    401 
    402 		for (unsigned i = 0; i < ident.length(); ++i)
    403 		{
    404 			const char &c = ident[i];
    405 
    406 			if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '.' || c == '-')
    407 				continue;
    408 
    409 			if (c == '-' || c == '.' || c == '_')
    410 				continue;
    411 
    412 			return false;
    413 		}
    414 
    415 		return true;
    416 	}
    417 };
    418 
    419 class UnrealExtBan : public ChannelModeVirtual<ChannelModeList>
    420 {
    421 	char ext;
    422 
    423  public:
    424 	UnrealExtBan(const Anope::string &mname, const Anope::string &basename, char extban) : ChannelModeVirtual<ChannelModeList>(mname, basename)
    425 		, ext(extban)
    426 	{
    427 	}
    428 
    429 	ChannelMode *Wrap(Anope::string &param) anope_override
    430 	{
    431 		param = "~" + Anope::string(ext) + ":" + param;
    432 		return ChannelModeVirtual<ChannelModeList>::Wrap(param);
    433 	}
    434 
    435 	ChannelMode *Unwrap(ChannelMode *cm, Anope::string &param) anope_override
    436 	{
    437 		if (cm->type != MODE_LIST || param.length() < 4 || param[0] != '~' || param[1] != ext || param[2] != ':')
    438 			return cm;
    439 
    440 		param = param.substr(3);
    441 		return this;
    442 	}
    443 };
    444 
    445 namespace UnrealExtban
    446 {
    447 	class ChannelMatcher : public UnrealExtBan
    448 	{
    449 	 public:
    450 		ChannelMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
    451 		{
    452 		}
    453 
    454 		bool Matches(User *u, const Entry *e) anope_override
    455 		{
    456 			const Anope::string &mask = e->GetMask();
    457 			Anope::string channel = mask.substr(3);
    458 
    459 			ChannelMode *cm = NULL;
    460 			if (channel[0] != '#')
    461 			{
    462 				char modeChar = ModeManager::GetStatusChar(channel[0]);
    463 				channel.erase(channel.begin());
    464 				cm = ModeManager::FindChannelModeByChar(modeChar);
    465 				if (cm != NULL && cm->type != MODE_STATUS)
    466 					cm = NULL;
    467 			}
    468 
    469 			Channel *c = Channel::Find(channel);
    470 			if (c != NULL)
    471 			{
    472 				ChanUserContainer *uc = c->FindUser(u);
    473 				if (uc != NULL)
    474 					if (cm == NULL || uc->status.HasMode(cm->mchar))
    475 						return true;
    476 			}
    477 
    478 			return false;
    479 		}
    480 	};
    481 
    482 	class EntryMatcher : public UnrealExtBan
    483 	{
    484 	 public:
    485 		EntryMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
    486 		{
    487 		}
    488 
    489 		bool Matches(User *u, const Entry *e) anope_override
    490 		{
    491 			const Anope::string &mask = e->GetMask();
    492 			Anope::string real_mask = mask.substr(3);
    493 
    494 			return Entry(this->name, real_mask).Matches(u);
    495 		}
    496 	};
    497 
    498 	class RealnameMatcher : public UnrealExtBan
    499 	{
    500 	 public:
    501 		RealnameMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
    502 		{
    503 		}
    504 
    505 		bool Matches(User *u, const Entry *e) anope_override
    506 		{
    507 			const Anope::string &mask = e->GetMask();
    508 			Anope::string real_mask = mask.substr(3);
    509 
    510 			return Anope::Match(u->realname, real_mask);
    511 		}
    512 	};
    513 
    514 	class RegisteredMatcher : public UnrealExtBan
    515 	{
    516 	 public:
    517 		RegisteredMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
    518 		{
    519 		}
    520 
    521 		bool Matches(User *u, const Entry *e) anope_override
    522 		{
    523 			const Anope::string &mask = e->GetMask();
    524 			return u->HasMode("REGISTERED") && mask.equals_ci(u->nick);
    525 		}
    526 	};
    527 
    528 	class AccountMatcher : public UnrealExtBan
    529 	{
    530 	 public:
    531 		AccountMatcher(const Anope::string &mname, const Anope::string &mbase, char c) : UnrealExtBan(mname, mbase, c)
    532 		{
    533 		}
    534 
    535 		bool Matches(User *u, const Entry *e) anope_override
    536 		{
    537 			const Anope::string &mask = e->GetMask();
    538 			Anope::string real_mask = mask.substr(3);
    539 
    540 			return u->Account() && Anope::Match(u->Account()->display, real_mask);
    541 		}
    542 	};
    543 }
    544 
    545 class ChannelModeFlood : public ChannelModeParam
    546 {
    547  public:
    548 	ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam("FLOOD", modeChar, minusNoArg) { }
    549 
    550 	/* Borrowed part of this check from UnrealIRCd */
    551 	bool IsValid(Anope::string &value) const anope_override
    552 	{
    553 		if (value.empty())
    554 			return false;
    555 		try
    556 		{
    557 			Anope::string rest;
    558 			if (value[0] != ':' && convertTo<unsigned>(value[0] == '*' ? value.substr(1) : value, rest, false) > 0 && rest[0] == ':' && rest.length() > 1 && convertTo<unsigned>(rest.substr(1), rest, false) > 0 && rest.empty())
    559 				return true;
    560 		}
    561 		catch (const ConvertException &) { }
    562 
    563 		/* '['<number><1 letter>[optional: '#'+1 letter],[next..]']'':'<number> */
    564 		size_t end_bracket = value.find(']', 1);
    565 		if (end_bracket == Anope::string::npos)
    566 			return false;
    567 		Anope::string xbuf = value.substr(0, end_bracket);
    568 		if (value[end_bracket + 1] != ':')
    569 			return false;
    570 		commasepstream args(xbuf.substr(1));
    571 		Anope::string arg;
    572 		while (args.GetToken(arg))
    573 		{
    574 			/* <number><1 letter>[optional: '#'+1 letter] */
    575 			size_t p = 0;
    576 			while (p < arg.length() && isdigit(arg[p]))
    577 				++p;
    578 			if (p == arg.length() || !(arg[p] == 'c' || arg[p] == 'j' || arg[p] == 'k' || arg[p] == 'm' || arg[p] == 'n' || arg[p] == 't'))
    579 				continue; /* continue instead of break for forward compatibility. */
    580 			try
    581 			{
    582 				int v = arg.substr(0, p).is_number_only() ? convertTo<int>(arg.substr(0, p)) : 0;
    583 				if (v < 1 || v > 999)
    584 					return false;
    585 			}
    586 			catch (const ConvertException &)
    587 			{
    588 				return false;
    589 			}
    590 		}
    591 
    592 		return true;
    593 	}
    594 };
    595 
    596 class ChannelModeUnrealSSL : public ChannelMode
    597 {
    598  public:
    599 	ChannelModeUnrealSSL(const Anope::string &n, char c) : ChannelMode(n, c)
    600 	{
    601 	}
    602 
    603 	bool CanSet(User *u) const anope_override
    604 	{
    605 		return false;
    606 	}
    607 };
    608 
    609 struct IRCDMessageCapab : Message::Capab
    610 {
    611 	IRCDMessageCapab(Module *creator) : Message::Capab(creator, "PROTOCTL") { }
    612 
    613 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    614 	{
    615 		for (unsigned i = 0; i < params.size(); ++i)
    616 		{
    617 			Anope::string capab = params[i];
    618 
    619 			if (capab.find("CHANMODES") != Anope::string::npos)
    620 			{
    621 				Anope::string modes(capab.begin() + 10, capab.end());
    622 				commasepstream sep(modes);
    623 				Anope::string modebuf;
    624 
    625 				sep.GetToken(modebuf);
    626 				for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    627 				{
    628 					switch (modebuf[t])
    629 					{
    630 						case 'b':
    631 							ModeManager::AddChannelMode(new ChannelModeList("BAN", 'b'));
    632 
    633 							ModeManager::AddChannelMode(new UnrealExtban::ChannelMatcher("CHANNELBAN", "BAN", 'c'));
    634 							ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("JOINBAN", "BAN", 'j'));
    635 							ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("NONICKBAN", "BAN", 'n'));
    636 							ModeManager::AddChannelMode(new UnrealExtban::EntryMatcher("QUIET", "BAN", 'q'));
    637 							ModeManager::AddChannelMode(new UnrealExtban::RealnameMatcher("REALNAMEBAN", "BAN", 'r'));
    638 							ModeManager::AddChannelMode(new UnrealExtban::RegisteredMatcher("REGISTEREDBAN", "BAN", 'R'));
    639 							ModeManager::AddChannelMode(new UnrealExtban::AccountMatcher("ACCOUNTBAN", "BAN", 'a'));
    640 							continue;
    641 						case 'e':
    642 							ModeManager::AddChannelMode(new ChannelModeList("EXCEPT", 'e'));
    643 							continue;
    644 						case 'I':
    645 							ModeManager::AddChannelMode(new ChannelModeList("INVITEOVERRIDE", 'I'));
    646 							continue;
    647 						default:
    648 							ModeManager::AddChannelMode(new ChannelModeList("", modebuf[t]));
    649 					}
    650 				}
    651 
    652 				sep.GetToken(modebuf);
    653 				for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    654 				{
    655 					switch (modebuf[t])
    656 					{
    657 						case 'k':
    658 							ModeManager::AddChannelMode(new ChannelModeKey('k'));
    659 							continue;
    660 						case 'f':
    661 							ModeManager::AddChannelMode(new ChannelModeFlood('f', false));
    662 							continue;
    663 						case 'L':
    664 							ModeManager::AddChannelMode(new ChannelModeParam("REDIRECT", 'L'));
    665 							continue;
    666 						default:
    667 							ModeManager::AddChannelMode(new ChannelModeParam("", modebuf[t]));
    668 					}
    669 				}
    670 
    671 				sep.GetToken(modebuf);
    672 				for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    673 				{
    674 					switch (modebuf[t])
    675 					{
    676 						case 'l':
    677 							ModeManager::AddChannelMode(new ChannelModeParam("LIMIT", 'l', true));
    678 							continue;
    679 						case 'j':
    680 							ModeManager::AddChannelMode(new ChannelModeParam("JOINFLOOD", 'j', true));
    681 							continue;
    682 						default:
    683 							ModeManager::AddChannelMode(new ChannelModeParam("", modebuf[t], true));
    684 					}
    685 				}
    686 
    687 				sep.GetToken(modebuf);
    688 				for (size_t t = 0, end = modebuf.length(); t < end; ++t)
    689 				{
    690 					switch (modebuf[t])
    691 					{
    692 						case 'p':
    693 							ModeManager::AddChannelMode(new ChannelMode("PRIVATE", 'p'));
    694 							continue;
    695 						case 's':
    696 							ModeManager::AddChannelMode(new ChannelMode("SECRET", 's'));
    697 							continue;
    698 						case 'm':
    699 							ModeManager::AddChannelMode(new ChannelMode("MODERATED", 'm'));
    700 							continue;
    701 						case 'n':
    702 							ModeManager::AddChannelMode(new ChannelMode("NOEXTERNAL", 'n'));
    703 							continue;
    704 						case 't':
    705 							ModeManager::AddChannelMode(new ChannelMode("TOPIC", 't'));
    706 							continue;
    707 						case 'i':
    708 							ModeManager::AddChannelMode(new ChannelMode("INVITE", 'i'));
    709 							continue;
    710 						case 'r':
    711 							ModeManager::AddChannelMode(new ChannelModeNoone("REGISTERED", 'r'));
    712 							continue;
    713 						case 'R':
    714 							ModeManager::AddChannelMode(new ChannelMode("REGISTEREDONLY", 'R'));
    715 							continue;
    716 						case 'c':
    717 							ModeManager::AddChannelMode(new ChannelMode("BLOCKCOLOR", 'c'));
    718 							continue;
    719 						case 'O':
    720 							ModeManager::AddChannelMode(new ChannelModeOperOnly("OPERONLY", 'O'));
    721 							continue;
    722 						case 'A':
    723 							ModeManager::AddChannelMode(new ChannelModeOperOnly("ADMINONLY", 'A'));
    724 							continue;
    725 						case 'Q':
    726 							ModeManager::AddChannelMode(new ChannelMode("NOKICK", 'Q'));
    727 							continue;
    728 						case 'K':
    729 							ModeManager::AddChannelMode(new ChannelMode("NOKNOCK", 'K'));
    730 							continue;
    731 						case 'V':
    732 							ModeManager::AddChannelMode(new ChannelMode("NOINVITE", 'V'));
    733 							continue;
    734 						case 'C':
    735 							ModeManager::AddChannelMode(new ChannelMode("NOCTCP", 'C'));
    736 							continue;
    737 						case 'u':
    738 							ModeManager::AddChannelMode(new ChannelMode("AUDITORIUM", 'u'));
    739 							continue;
    740 						case 'z':
    741 							ModeManager::AddChannelMode(new ChannelMode("SSL", 'z'));
    742 							continue;
    743 						case 'N':
    744 							ModeManager::AddChannelMode(new ChannelMode("NONICK", 'N'));
    745 							continue;
    746 						case 'S':
    747 							ModeManager::AddChannelMode(new ChannelMode("STRIPCOLOR", 'S'));
    748 							continue;
    749 						case 'M':
    750 							ModeManager::AddChannelMode(new ChannelMode("REGMODERATED", 'M'));
    751 							continue;
    752 						case 'T':
    753 							ModeManager::AddChannelMode(new ChannelMode("NONOTICE", 'T'));
    754 							continue;
    755 						case 'G':
    756 							ModeManager::AddChannelMode(new ChannelMode("CENSOR", 'G'));
    757 							continue;
    758 						case 'Z':
    759 							ModeManager::AddChannelMode(new ChannelModeUnrealSSL("", 'Z'));
    760 							continue;
    761 						default:
    762 							ModeManager::AddChannelMode(new ChannelMode("", modebuf[t]));
    763 					}
    764 				}
    765 			}
    766 		}
    767 
    768 		Message::Capab::Run(source, params);
    769 	}
    770 };
    771 
    772 struct IRCDMessageChgHost : IRCDMessage
    773 {
    774 	IRCDMessageChgHost(Module *creator) : IRCDMessage(creator, "CHGHOST", 2) { }
    775 
    776 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    777 	{
    778 		User *u = User::Find(params[0]);
    779 		if (u)
    780 			u->SetDisplayedHost(params[1]);
    781 	}
    782 };
    783 
    784 struct IRCDMessageChgIdent : IRCDMessage
    785 {
    786 	IRCDMessageChgIdent(Module *creator) : IRCDMessage(creator, "CHGIDENT", 2) { }
    787 
    788 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    789 	{
    790 		User *u = User::Find(params[0]);
    791 		if (u)
    792 			u->SetVIdent(params[1]);
    793 	}
    794 };
    795 
    796 struct IRCDMessageChgName : IRCDMessage
    797 {
    798 	IRCDMessageChgName(Module *creator) : IRCDMessage(creator, "CHGNAME", 2) { }
    799 
    800 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    801 	{
    802 		User *u = User::Find(params[0]);
    803 		if (u)
    804 			u->SetRealname(params[1]);
    805 	}
    806 };
    807 
    808 struct IRCDMessageMode : IRCDMessage
    809 {
    810 	IRCDMessageMode(Module *creator, const Anope::string &mname) : IRCDMessage(creator, mname, 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    811 
    812 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    813 	{
    814 		bool server_source = source.GetServer() != NULL;
    815 		Anope::string modes = params[1];
    816 		for (unsigned i = 2; i < params.size() - (server_source ? 1 : 0); ++i)
    817 			modes += " " + params[i];
    818 
    819 		if (IRCD->IsChannelValid(params[0]))
    820 		{
    821 			Channel *c = Channel::Find(params[0]);
    822 			time_t ts = 0;
    823 
    824 			try
    825 			{
    826 				if (server_source)
    827 					ts = convertTo<time_t>(params[params.size() - 1]);
    828 			}
    829 			catch (const ConvertException &) { }
    830 
    831 			if (c)
    832 				c->SetModesInternal(source, modes, ts);
    833 		}
    834 		else
    835 		{
    836 			User *u = User::Find(params[0]);
    837 			if (u)
    838 				u->SetModesInternal(source, "%s", params[1].c_str());
    839 		}
    840 	}
    841 };
    842 
    843 /* netinfo
    844  *  argv[0] = max global count
    845  *  argv[1] = time of end sync
    846  *  argv[2] = unreal protocol using (numeric)
    847  *  argv[3] = cloak-crc (> u2302)
    848  *  argv[4] = free(**)
    849  *  argv[5] = free(**)
    850  *  argv[6] = free(**)
    851  *  argv[7] = ircnet
    852  */
    853 struct IRCDMessageNetInfo : IRCDMessage
    854 {
    855 	IRCDMessageNetInfo(Module *creator) : IRCDMessage(creator, "NETINFO", 8) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    856 
    857 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    858 	{
    859 		UplinkSocket::Message() << "NETINFO " << MaxUserCount << " " << Anope::CurTime << " " << convertTo<int>(params[2]) << " " << params[3] << " 0 0 0 :" << params[7];
    860 	}
    861 };
    862 
    863 struct IRCDMessageNick : IRCDMessage
    864 {
    865 	IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    866 
    867 	/*
    868 	** NICK - new
    869 	**	  source  = NULL
    870 	**	  parv[0] = nickname
    871 	**	  parv[1] = hopcount
    872 	**	  parv[2] = timestamp
    873 	**	  parv[3] = username
    874 	**	  parv[4] = hostname
    875 	**	  parv[5] = servername
    876 	**	  parv[6] = servicestamp
    877 	**	  parv[7] = umodes
    878 	**	  parv[8] = virthost, * if none
    879 	**	  parv[9] = ip
    880 	**	  parv[10] = info
    881 	**
    882 	** NICK - change
    883 	**	  source  = oldnick
    884 	**	  parv[0] = new nickname
    885 	**	  parv[1] = hopcount
    886 	*/
    887 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    888 	{
    889 		if (params.size() == 11)
    890 		{
    891 			Anope::string ip;
    892 			if (params[9] != "*")
    893 			{
    894 				Anope::string decoded_ip;
    895 				Anope::B64Decode(params[9], decoded_ip);
    896 
    897 				sockaddrs ip_addr;
    898 				ip_addr.ntop(params[9].length() == 8 ? AF_INET : AF_INET6, decoded_ip.c_str());
    899 				ip = ip_addr.addr();
    900 			}
    901 
    902 			Anope::string vhost = params[8];
    903 			if (vhost.equals_cs("*"))
    904 				vhost.clear();
    905 
    906 			time_t user_ts = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime;
    907 
    908 			Server *s = Server::Find(params[5]);
    909 			if (s == NULL)
    910 			{
    911 				Log(LOG_DEBUG) << "User " << params[0] << " introduced from nonexistent server " << params[5] << "?";
    912 				return;
    913 			}
    914 
    915 			NickAlias *na = NULL;
    916 
    917 			if (params[6] == "0")
    918 				;
    919 			else if (params[6].is_pos_number_only())
    920 			{
    921 				if (convertTo<time_t>(params[6]) == user_ts)
    922 					na = NickAlias::Find(params[0]);
    923 			}
    924 			else
    925 			{
    926 				na = NickAlias::Find(params[6]);
    927 			}
    928 
    929 			User::OnIntroduce(params[0], params[3], params[4], vhost, ip, s, params[10], user_ts, params[7], "", na ? *na->nc : NULL);
    930 		}
    931 		else
    932 		{
    933 			User *u = source.GetUser();
    934 			if (u)
    935 				u->ChangeNick(params[0]);
    936 		}
    937 	}
    938 };
    939 
    940 /** This is here because:
    941  *
    942  * If we had three servers, A, B & C linked like so: A<->B<->C
    943  * If Anope is linked to A and B splits from A and then reconnects
    944  * B introduces itself, introduces C, sends EOS for C, introduces Bs clients
    945  * introduces Cs clients, sends EOS for B. This causes all of Cs clients to be introduced
    946  * with their server "not syncing". We now send a PING immediately when receiving a new server
    947  * and then finish sync once we get a pong back from that server.
    948  */
    949 struct IRCDMessagePong : IRCDMessage
    950 {
    951 	IRCDMessagePong(Module *creator) : IRCDMessage(creator, "PONG", 0) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    952 
    953 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    954 	{
    955 		if (!source.GetServer()->IsSynced())
    956 			source.GetServer()->Sync(false);
    957 	}
    958 };
    959 
    960 struct IRCDMessageSASL : IRCDMessage
    961 {
    962 	IRCDMessageSASL(Module *creator) : IRCDMessage(creator, "SASL", 4) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    963 
    964 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    965 	{
    966 		size_t p = params[1].find('!');
    967 		if (!SASL::sasl || p == Anope::string::npos)
    968 			return;
    969 
    970 		SASL::Message m;
    971 		m.source = params[1];
    972 		m.target = params[0];
    973 		m.type = params[2];
    974 		m.data = params[3];
    975 		m.ext = params.size() > 4 ? params[4] : "";
    976 
    977 		SASL::sasl->ProcessMessage(m);
    978 	}
    979 };
    980 
    981 struct IRCDMessageSDesc : IRCDMessage
    982 {
    983 	IRCDMessageSDesc(Module *creator) : IRCDMessage(creator, "SDESC", 1) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    984 
    985 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    986 	{
    987 		source.GetServer()->SetDescription(params[0]);
    988 	}
    989 };
    990 
    991 struct IRCDMessageSetHost : IRCDMessage
    992 {
    993 	IRCDMessageSetHost(Module *creator) : IRCDMessage(creator, "SETHOST", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
    994 
    995 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    996 	{
    997 		User *u = source.GetUser();
    998 
    999 		/* When a user sets +x we receive the new host and then the mode change */
   1000 		if (u->HasMode("CLOAK"))
   1001 			u->SetDisplayedHost(params[0]);
   1002 		else
   1003 			u->SetCloakedHost(params[0]);
   1004 	}
   1005 };
   1006 
   1007 struct IRCDMessageSetIdent : IRCDMessage
   1008 {
   1009 	IRCDMessageSetIdent(Module *creator) : IRCDMessage(creator, "SETIDENT", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
   1010 
   1011 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1012 	{
   1013 		User *u = source.GetUser();
   1014 		u->SetVIdent(params[0]);
   1015 	}
   1016 };
   1017 
   1018 struct IRCDMessageSetName : IRCDMessage
   1019 {
   1020 	IRCDMessageSetName(Module *creator) : IRCDMessage(creator, "SETNAME", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
   1021 
   1022 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1023 	{
   1024 		User *u = source.GetUser();
   1025 		u->SetRealname(params[0]);
   1026 	}
   1027 };
   1028 
   1029 struct IRCDMessageServer : IRCDMessage
   1030 {
   1031 	IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
   1032 
   1033 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1034 	{
   1035 		unsigned int hops = Anope::string(params[1]).is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0;
   1036 
   1037 		if (params[1].equals_cs("1"))
   1038 		{
   1039 			Anope::string desc;
   1040 			spacesepstream(params[2]).GetTokenRemainder(desc, 1);
   1041 
   1042 			new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, desc);
   1043 		}
   1044 		else
   1045 			new Server(source.GetServer(), params[0], hops, params[2]);
   1046 
   1047 		IRCD->SendPing(Me->GetName(), params[0]);
   1048 	}
   1049 };
   1050 
   1051 struct IRCDMessageSJoin : IRCDMessage
   1052 {
   1053 	IRCDMessageSJoin(Module *creator) : IRCDMessage(creator, "SJOIN", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
   1054 
   1055 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1056 	{
   1057 		Anope::string modes;
   1058 		if (params.size() >= 4)
   1059 			for (unsigned i = 2; i < params.size() - 1; ++i)
   1060 				modes += " " + params[i];
   1061 		if (!modes.empty())
   1062 			modes.erase(modes.begin());
   1063 
   1064 		std::list<Anope::string> bans, excepts, invites;
   1065 		std::list<Message::Join::SJoinUser> users;
   1066 
   1067 		spacesepstream sep(params[params.size() - 1]);
   1068 		Anope::string buf;
   1069 		while (sep.GetToken(buf))
   1070 		{
   1071 			/* Ban */
   1072 			if (buf[0] == '&')
   1073 			{
   1074 				buf.erase(buf.begin());
   1075 				bans.push_back(buf);
   1076 			}
   1077 			/* Except */
   1078 			else if (buf[0] == '"')
   1079 			{
   1080 				buf.erase(buf.begin());
   1081 				excepts.push_back(buf);
   1082 			}
   1083 			/* Invex */
   1084 			else if (buf[0] == '\'')
   1085 			{
   1086 				buf.erase(buf.begin());
   1087 				invites.push_back(buf);
   1088 			}
   1089 			else
   1090 			{
   1091 				Message::Join::SJoinUser sju;
   1092 
   1093 				/* Get prefixes from the nick */
   1094 				for (char ch; (ch = ModeManager::GetStatusChar(buf[0]));)
   1095 				{
   1096 					sju.first.AddMode(ch);
   1097 					buf.erase(buf.begin());
   1098 				}
   1099 
   1100 				sju.second = User::Find(buf);
   1101 				if (!sju.second)
   1102 				{
   1103 					Log(LOG_DEBUG) << "SJOIN for nonexistent user " << buf << " on " << params[1];
   1104 					continue;
   1105 				}
   1106 
   1107 				users.push_back(sju);
   1108 			}
   1109 		}
   1110 
   1111 		time_t ts = Anope::string(params[0]).is_pos_number_only() ? convertTo<time_t>(params[0]) : Anope::CurTime;
   1112 		Message::Join::SJoin(source, params[1], ts, modes, users);
   1113 
   1114 		if (!bans.empty() || !excepts.empty() || !invites.empty())
   1115 		{
   1116 			Channel *c = Channel::Find(params[1]);
   1117 
   1118 			if (!c || c->creation_time != ts)
   1119 				return;
   1120 
   1121 			ChannelMode *ban = ModeManager::FindChannelModeByName("BAN"),
   1122 				*except = ModeManager::FindChannelModeByName("EXCEPT"),
   1123 				*invex = ModeManager::FindChannelModeByName("INVITEOVERRIDE");
   1124 
   1125 			if (ban)
   1126 				for (std::list<Anope::string>::iterator it = bans.begin(), it_end = bans.end(); it != it_end; ++it)
   1127 					c->SetModeInternal(source, ban, *it);
   1128 			if (except)
   1129 				for (std::list<Anope::string>::iterator it = excepts.begin(), it_end = excepts.end(); it != it_end; ++it)
   1130 					c->SetModeInternal(source, except, *it);
   1131 			if (invex)
   1132 				for (std::list<Anope::string>::iterator it = invites.begin(), it_end = invites.end(); it != it_end; ++it)
   1133 					c->SetModeInternal(source, invex, *it);
   1134 		}
   1135 	}
   1136 };
   1137 
   1138 struct IRCDMessageTopic : IRCDMessage
   1139 {
   1140 	IRCDMessageTopic(Module *creator) : IRCDMessage(creator, "TOPIC", 4) { }
   1141 
   1142 	/*
   1143 	**	source = sender prefix
   1144 	**	parv[0] = channel name
   1145 	**	parv[1] = topic nickname
   1146 	**	parv[2] = topic time
   1147 	**	parv[3] = topic text
   1148 	*/
   1149 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1150 	{
   1151 		Channel *c = Channel::Find(params[0]);
   1152 		if (c)
   1153 			c->ChangeTopicInternal(source.GetUser(), params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime);
   1154 	}
   1155 };
   1156 
   1157 
   1158 struct IRCDMessageUmode2 : IRCDMessage
   1159 {
   1160 	IRCDMessageUmode2(Module *creator) : IRCDMessage(creator, "UMODE2", 1) { SetFlag(IRCDMESSAGE_REQUIRE_USER); }
   1161 
   1162 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
   1163 	{
   1164 		source.GetUser()->SetModesInternal(source, "%s", params[0].c_str());
   1165 	}
   1166 };
   1167 
   1168 class ProtoUnreal : public Module
   1169 {
   1170 	UnrealIRCdProto ircd_proto;
   1171 
   1172 	/* Core message handlers */
   1173 	Message::Away message_away;
   1174 	Message::Error message_error;
   1175 	Message::Invite message_invite;
   1176 	Message::Join message_join;
   1177 	Message::Kick message_kick;
   1178 	Message::Kill message_kill, message_svskill;
   1179 	Message::MOTD message_motd;
   1180 	Message::Notice message_notice;
   1181 	Message::Part message_part;
   1182 	Message::Ping message_ping;
   1183 	Message::Privmsg message_privmsg;
   1184 	Message::Quit message_quit;
   1185 	Message::SQuit message_squit;
   1186 	Message::Stats message_stats;
   1187 	Message::Time message_time;
   1188 	Message::Version message_version;
   1189 	Message::Whois message_whois;
   1190 
   1191 	/* Our message handlers */
   1192 	IRCDMessageCapab message_capab;
   1193 	IRCDMessageChgHost message_chghost;
   1194 	IRCDMessageChgIdent message_chgident;
   1195 	IRCDMessageChgName message_chgname;
   1196 	IRCDMessageMode message_mode, message_svsmode, message_svs2mode;
   1197 	IRCDMessageNetInfo message_netinfo;
   1198 	IRCDMessageNick message_nick;
   1199 	IRCDMessagePong message_pong;
   1200 	IRCDMessageSASL message_sasl;
   1201 	IRCDMessageSDesc message_sdesc;
   1202 	IRCDMessageSetHost message_sethost;
   1203 	IRCDMessageSetIdent message_setident;
   1204 	IRCDMessageSetName message_setname;
   1205 	IRCDMessageServer message_server;
   1206 	IRCDMessageSJoin message_sjoin;
   1207 	IRCDMessageTopic message_topic;
   1208 	IRCDMessageUmode2 message_umode2;
   1209 
   1210 	bool use_server_side_mlock;
   1211 
   1212 	void AddModes()
   1213 	{
   1214 		ModeManager::AddChannelMode(new ChannelModeStatus("VOICE", 'v', '+', 0));
   1215 		ModeManager::AddChannelMode(new ChannelModeStatus("HALFOP", 'h', '%', 1));
   1216 		ModeManager::AddChannelMode(new ChannelModeStatus("OP", 'o', '@', 2));
   1217 		/* Unreal sends +q as * and +a as ~ */
   1218 		ModeManager::AddChannelMode(new ChannelModeStatus("PROTECT", 'a', '~', 3));
   1219 		ModeManager::AddChannelMode(new ChannelModeStatus("OWNER", 'q', '*', 4));
   1220 
   1221 		/* Add user modes */
   1222 		ModeManager::AddUserMode(new UserModeOperOnly("SERV_ADMIN", 'A'));
   1223 		ModeManager::AddUserMode(new UserMode("BOT", 'B'));
   1224 		ModeManager::AddUserMode(new UserModeOperOnly("CO_ADMIN", 'C'));
   1225 		ModeManager::AddUserMode(new UserMode("CENSOR", 'G'));
   1226 		ModeManager::AddUserMode(new UserModeOperOnly("HIDEOPER", 'H'));
   1227 		ModeManager::AddUserMode(new UserModeOperOnly("HIDEIDLE", 'I'));
   1228 		ModeManager::AddUserMode(new UserModeOperOnly("NETADMIN", 'N'));
   1229 		ModeManager::AddUserMode(new UserMode("REGPRIV", 'R'));
   1230 		ModeManager::AddUserMode(new UserModeOperOnly("PROTECTED", 'S'));
   1231 		ModeManager::AddUserMode(new UserMode("NOCTCP", 'T'));
   1232 		ModeManager::AddUserMode(new UserMode("WEBTV", 'V'));
   1233 		ModeManager::AddUserMode(new UserModeOperOnly("WHOIS", 'W'));
   1234 		ModeManager::AddUserMode(new UserModeOperOnly("ADMIN", 'a'));
   1235 		ModeManager::AddUserMode(new UserMode("DEAF", 'd'));
   1236 		ModeManager::AddUserMode(new UserModeOperOnly("GLOBOPS", 'g'));
   1237 		ModeManager::AddUserMode(new UserModeOperOnly("HELPOP", 'h'));
   1238 		ModeManager::AddUserMode(new UserMode("INVIS", 'i'));
   1239 		ModeManager::AddUserMode(new UserModeOperOnly("OPER", 'o'));
   1240 		ModeManager::AddUserMode(new UserMode("PRIV", 'p'));
   1241 		ModeManager::AddUserMode(new UserModeOperOnly("GOD", 'q'));
   1242 		ModeManager::AddUserMode(new UserModeNoone("REGISTERED", 'r'));
   1243 		ModeManager::AddUserMode(new UserModeOperOnly("SNOMASK", 's'));
   1244 		ModeManager::AddUserMode(new UserModeNoone("VHOST", 't'));
   1245 		ModeManager::AddUserMode(new UserMode("WALLOPS", 'w'));
   1246 		ModeManager::AddUserMode(new UserMode("CLOAK", 'x'));
   1247 		ModeManager::AddUserMode(new UserModeNoone("SSL", 'z'));
   1248 	}
   1249 
   1250  public:
   1251 	ProtoUnreal(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR),
   1252 		ircd_proto(this),
   1253 		message_away(this), message_error(this), message_invite(this), message_join(this), message_kick(this),
   1254 		message_kill(this), message_svskill(this, "SVSKILL"), message_motd(this), message_notice(this), message_part(this), message_ping(this),
   1255 		message_privmsg(this), message_quit(this), message_squit(this), message_stats(this), message_time(this),
   1256 		message_version(this), message_whois(this),
   1257 
   1258 		message_capab(this), message_chghost(this), message_chgident(this), message_chgname(this), message_mode(this, "MODE"),
   1259 		message_svsmode(this, "SVSMODE"), message_svs2mode(this, "SVS2MODE"), message_netinfo(this), message_nick(this), message_pong(this),
   1260 		message_sasl(this), message_sdesc(this), message_sethost(this), message_setident(this), message_setname(this), message_server(this),
   1261 		message_sjoin(this), message_topic(this), message_umode2(this)
   1262 	{
   1263 
   1264 		this->AddModes();
   1265 	}
   1266 
   1267 	void Prioritize() anope_override
   1268 	{
   1269 		ModuleManager::SetPriority(this, PRIORITY_FIRST);
   1270 	}
   1271 
   1272 	void OnReload(Configuration::Conf *conf) anope_override
   1273 	{
   1274 		use_server_side_mlock = conf->GetModule(this)->Get<bool>("use_server_side_mlock");
   1275 	}
   1276 
   1277 	void OnUserNickChange(User *u, const Anope::string &) anope_override
   1278 	{
   1279 		u->RemoveModeInternal(Me, ModeManager::FindUserModeByName("REGISTERED"));
   1280 		if (Servers::Capab.count("ESVID") == 0)
   1281 			IRCD->SendLogout(u);
   1282 	}
   1283 
   1284 	void OnChannelSync(Channel *c) anope_override
   1285 	{
   1286 		if (!c->ci)
   1287 			return;
   1288 
   1289 		ModeLocks *modelocks = c->ci->GetExt<ModeLocks>("modelocks");
   1290 		if (use_server_side_mlock && Servers::Capab.count("MLOCK") > 0 && modelocks)
   1291 		{
   1292 			Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "");
   1293 			UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(c->creation_time) << " " << c->ci->name << " " << modes;
   1294 		}
   1295 	}
   1296 
   1297 	void OnChanRegistered(ChannelInfo *ci) anope_override
   1298 	{
   1299 		ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks");
   1300 		if (!ci->c || !use_server_side_mlock || !modelocks || !Servers::Capab.count("MLOCK"))
   1301 			return;
   1302 		Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "");
   1303 		UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes;
   1304 	}
   1305 
   1306 	void OnDelChan(ChannelInfo *ci) anope_override
   1307 	{
   1308 		if (!ci->c || !use_server_side_mlock || !Servers::Capab.count("MLOCK"))
   1309 			return;
   1310 		UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " :";
   1311 	}
   1312 
   1313 	EventReturn OnMLock(ChannelInfo *ci, ModeLock *lock) anope_override
   1314 	{
   1315 		ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks");
   1316 		ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name);
   1317 		if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0)
   1318 		{
   1319 			Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "") + cm->mchar;
   1320 			UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes;
   1321 		}
   1322 
   1323 		return EVENT_CONTINUE;
   1324 	}
   1325 
   1326 	EventReturn OnUnMLock(ChannelInfo *ci, ModeLock *lock) anope_override
   1327 	{
   1328 		ModeLocks *modelocks = ci->GetExt<ModeLocks>("modelocks");
   1329 		ChannelMode *cm = ModeManager::FindChannelModeByName(lock->name);
   1330 		if (use_server_side_mlock && cm && modelocks && ci->c && (cm->type == MODE_REGULAR || cm->type == MODE_PARAM) && Servers::Capab.count("MLOCK") > 0)
   1331 		{
   1332 			Anope::string modes = modelocks->GetMLockAsString(false).replace_all_cs("+", "").replace_all_cs("-", "").replace_all_cs(cm->mchar, "");
   1333 			UplinkSocket::Message(Me) << "MLOCK " << static_cast<long>(ci->c->creation_time) << " " << ci->name << " " << modes;
   1334 		}
   1335 
   1336 		return EVENT_CONTINUE;
   1337 	}
   1338 };
   1339 
   1340 MODULE_INIT(ProtoUnreal)