anope

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

bahamut.cpp (17509B)

      1 /* Bahamut 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 
     14 class ChannelModeFlood : public ChannelModeParam
     15 {
     16  public:
     17 	ChannelModeFlood(char modeChar, bool minusNoArg) : ChannelModeParam("FLOOD", modeChar, minusNoArg) { }
     18 
     19 	bool IsValid(Anope::string &value) const anope_override
     20 	{
     21 		try
     22 		{
     23 			Anope::string rest;
     24 			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())
     25 				return true;
     26 		}
     27 		catch (const ConvertException &) { }
     28 
     29 		return false;
     30 	}
     31 };
     32 
     33 class BahamutIRCdProto : public IRCDProto
     34 {
     35  public:
     36 	BahamutIRCdProto(Module *creator) : IRCDProto(creator, "Bahamut 1.8.x")
     37 	{
     38 		DefaultPseudoclientModes = "+";
     39 		CanSVSNick = true;
     40 		CanSNLine = true;
     41 		CanSQLine = true;
     42 		CanSQLineChannel = true;
     43 		CanSZLine = true;
     44 		CanSVSHold = true;
     45 		MaxModes = 60;
     46 	}
     47 
     48 	void SendModeInternal(const MessageSource &source, const Channel *dest, const Anope::string &buf) anope_override
     49 	{
     50 		if (Servers::Capab.count("TSMODE") > 0)
     51 		{
     52 			UplinkSocket::Message(source) << "MODE " << dest->name << " " << dest->creation_time << " " << buf;
     53 		}
     54 		else
     55 			IRCDProto::SendModeInternal(source, dest, buf);
     56 	}
     57 
     58 	void SendModeInternal(const MessageSource &source, User *u, const Anope::string &buf) anope_override
     59 	{
     60 		UplinkSocket::Message(source) << "SVSMODE " << u->nick << " " << u->timestamp << " " << buf;
     61 	}
     62 
     63 	void SendGlobalNotice(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
     64 	{
     65 		UplinkSocket::Message(bi) << "NOTICE $" << dest->GetName() << " :" << msg;
     66 	}
     67 
     68 	void SendGlobalPrivmsg(BotInfo *bi, const Server *dest, const Anope::string &msg) anope_override
     69 	{
     70 		UplinkSocket::Message(bi) << "PRIVMSG $" << dest->GetName() << " :" << msg;
     71 	}
     72 
     73 	/* SVSHOLD - set */
     74 	void SendSVSHold(const Anope::string &nick, time_t time) anope_override
     75 	{
     76 		UplinkSocket::Message(Me) << "SVSHOLD " << nick << " " << time << " :Being held for registered user";
     77 	}
     78 
     79 	/* SVSHOLD - release */
     80 	void SendSVSHoldDel(const Anope::string &nick) anope_override
     81 	{
     82 		UplinkSocket::Message(Me) << "SVSHOLD " << nick << " 0";
     83 	}
     84 
     85 	/* SQLINE */
     86 	void SendSQLine(User *, const XLine *x) anope_override
     87 	{
     88 		UplinkSocket::Message() << "SQLINE " << x->mask << " :" << x->GetReason();
     89 	}
     90 
     91 	/* UNSLINE */
     92 	void SendSGLineDel(const XLine *x) anope_override
     93 	{
     94 		UplinkSocket::Message() << "UNSGLINE 0 :" << x->mask;
     95 	}
     96 
     97 	/* UNSZLINE */
     98 	void SendSZLineDel(const XLine *x) anope_override
     99 	{
    100 		/* this will likely fail so its only here for legacy */
    101 		UplinkSocket::Message() << "UNSZLINE 0 " << x->GetHost();
    102 		/* this is how we are supposed to deal with it */
    103 		UplinkSocket::Message() << "RAKILL " << x->GetHost() << " *";
    104 	}
    105 
    106 	/* SZLINE */
    107 	void SendSZLine(User *, const XLine *x) anope_override
    108 	{
    109 		// Calculate the time left before this would expire, capping it at 2 days
    110 		time_t timeleft = x->expires - Anope::CurTime;
    111 		if (timeleft > 172800 || !x->expires)
    112 			timeleft = 172800;
    113 		/* this will likely fail so its only here for legacy */
    114 		UplinkSocket::Message() << "SZLINE " << x->GetHost() << " :" << x->GetReason();
    115 		/* this is how we are supposed to deal with it */
    116 		UplinkSocket::Message() << "AKILL " << x->GetHost() << " * " << timeleft << " " << x->by << " " << Anope::CurTime << " :" << x->GetReason();
    117 	}
    118 
    119 	/* SVSNOOP */
    120 	void SendSVSNOOP(const Server *server, bool set) anope_override
    121 	{
    122 		UplinkSocket::Message() << "SVSNOOP " << server->GetName() << " " << (set ? "+" : "-");
    123 	}
    124 
    125 	/* SGLINE */
    126 	void SendSGLine(User *, const XLine *x) anope_override
    127 	{
    128 		UplinkSocket::Message() << "SGLINE " << x->mask.length() << " :" << x->mask << ":" << x->GetReason();
    129 	}
    130 
    131 	/* RAKILL */
    132 	void SendAkillDel(const XLine *x) anope_override
    133 	{
    134 		if (x->IsRegex() || x->HasNickOrReal())
    135 			return;
    136 
    137 		/* ZLine if we can instead */
    138 		if (x->GetUser() == "*")
    139 		{
    140 			cidr a(x->GetHost());
    141 			if (a.valid())
    142 			{
    143 				IRCD->SendSZLineDel(x);
    144 				return;
    145 			}
    146 		}
    147 
    148 		UplinkSocket::Message() << "RAKILL " << x->GetHost() << " " << x->GetUser();
    149 	}
    150 
    151 	/* TOPIC */
    152 	void SendTopic(const MessageSource &source, Channel *c) anope_override
    153 	{
    154 		UplinkSocket::Message(source) << "TOPIC " << c->name << " " << c->topic_setter << " " << c->topic_ts << " :" << c->topic;
    155 	}
    156 
    157 	/* UNSQLINE */
    158 	void SendSQLineDel(const XLine *x) anope_override
    159 	{
    160 		UplinkSocket::Message() << "UNSQLINE " << x->mask;
    161 	}
    162 
    163 	/* JOIN - SJOIN */
    164 	void SendJoin(User *user, Channel *c, const ChannelStatus *status) anope_override
    165 	{
    166 		UplinkSocket::Message(user) << "SJOIN " << c->creation_time << " " << c->name;
    167 		if (status)
    168 		{
    169 			/* First save the channel status incase uc->Status == status */
    170 			ChannelStatus cs = *status;
    171 			/* If the user is internally on the channel with flags, kill them so that
    172 			 * the stacker will allow this.
    173 			 */
    174 			ChanUserContainer *uc = c->FindUser(user);
    175 			if (uc != NULL)
    176 				uc->status.Clear();
    177 
    178 			BotInfo *setter = BotInfo::Find(user->GetUID());
    179 			for (size_t i = 0; i < cs.Modes().length(); ++i)
    180 				c->SetMode(setter, ModeManager::FindChannelModeByChar(cs.Modes()[i]), user->GetUID(), false);
    181 
    182 			if (uc != NULL)
    183 				uc->status = cs;
    184 		}
    185 	}
    186 
    187 	void SendAkill(User *u, XLine *x) anope_override
    188 	{
    189 		if (x->IsRegex() || x->HasNickOrReal())
    190 		{
    191 			if (!u)
    192 			{
    193 				/* No user (this akill was just added), and contains nick and/or realname. Find users that match and ban them */
    194 				for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
    195 					if (x->manager->Check(it->second, x))
    196 						this->SendAkill(it->second, x);
    197 				return;
    198 			}
    199 
    200 			const XLine *old = x;
    201 
    202 			if (old->manager->HasEntry("*@" + u->host))
    203 				return;
    204 
    205 			/* We can't akill x as it has a nick and/or realname included, so create a new akill for *@host */
    206 			x = new XLine("*@" + u->host, old->by, old->expires, old->reason, old->id);
    207 			old->manager->AddXLine(x);
    208 
    209 			Log(Config->GetClient("OperServ"), "akill") << "AKILL: Added an akill for " << x->mask << " because " << u->GetMask() << "#" << u->realname << " matches " << old->mask;
    210 		}
    211 
    212 		/* ZLine if we can instead */
    213 		if (x->GetUser() == "*")
    214 		{
    215 			cidr a(x->GetHost());
    216 			if (a.valid())
    217 			{
    218 				IRCD->SendSZLine(u, x);
    219 				return;
    220 			}
    221 		}
    222 
    223 		// Calculate the time left before this would expire, capping it at 2 days
    224 		time_t timeleft = x->expires - Anope::CurTime;
    225 		if (timeleft > 172800)
    226 			timeleft = 172800;
    227 		UplinkSocket::Message() << "AKILL " << x->GetHost() << " " << x->GetUser() << " " << timeleft << " " << x->by << " " << Anope::CurTime << " :" << x->GetReason();
    228 	}
    229 
    230 	/*
    231 	  Note: if the stamp is null 0, the below usage is correct of Bahamut
    232 	*/
    233 	void SendSVSKillInternal(const MessageSource &source, User *user, const Anope::string &buf) anope_override
    234 	{
    235 		UplinkSocket::Message(source) << "SVSKILL " << user->nick << " :" << buf;
    236 	}
    237 
    238 	void SendBOB() anope_override
    239 	{
    240 		UplinkSocket::Message() << "BURST";
    241 	}
    242 
    243 	void SendEOB() anope_override
    244 	{
    245 		UplinkSocket::Message() << "BURST 0";
    246 	}
    247 
    248 	void SendClientIntroduction(User *u) anope_override
    249 	{
    250 		Anope::string modes = "+" + u->GetModes();
    251 		UplinkSocket::Message() << "NICK " << u->nick << " 1 " << u->timestamp << " " << modes << " " << u->GetIdent() << " " << u->host << " " << u->server->GetName() << " 0 0 :" << u->realname;
    252 	}
    253 
    254 	/* SERVER */
    255 	void SendServer(const Server *server) anope_override
    256 	{
    257 		UplinkSocket::Message() << "SERVER " << server->GetName() << " " << server->GetHops() << " :" << server->GetDescription();
    258 	}
    259 
    260 	void SendConnect() anope_override
    261 	{
    262 		UplinkSocket::Message() << "PASS " << Config->Uplinks[Anope::CurrentUplink].password << " :TS";
    263 		UplinkSocket::Message() << "CAPAB SSJOIN NOQUIT BURST UNCONNECT NICKIP TSMODE TS3";
    264 		SendServer(Me);
    265 		/*
    266 		 * SVINFO
    267 		 *	   parv[0] = sender prefix
    268 		 *	   parv[1] = TS_CURRENT for the server
    269 		 *	   parv[2] = TS_MIN for the server
    270 		 *	   parv[3] = server is standalone or connected to non-TS only
    271 		 *	   parv[4] = server's idea of UTC time
    272 		 */
    273 		UplinkSocket::Message() << "SVINFO 3 1 0 :" << Anope::CurTime;
    274 		this->SendBOB();
    275 	}
    276 
    277 	void SendChannel(Channel *c) anope_override
    278 	{
    279 		Anope::string modes = c->GetModes(true, true);
    280 		if (modes.empty())
    281 			modes = "+";
    282 		UplinkSocket::Message() << "SJOIN " << c->creation_time << " " << c->name << " " << modes << " :";
    283 	}
    284 
    285 	void SendLogin(User *u, NickAlias *) anope_override
    286 	{
    287 		IRCD->SendMode(Config->GetClient("NickServ"), u, "+d %d", u->signon);
    288 	}
    289 
    290 	void SendLogout(User *u) anope_override
    291 	{
    292 		IRCD->SendMode(Config->GetClient("NickServ"), u, "+d 1");
    293 	}
    294 };
    295 
    296 struct IRCDMessageBurst : IRCDMessage
    297 {
    298 	IRCDMessageBurst(Module *creator) : IRCDMessage(creator, "BURST", 0) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    299 
    300 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    301 	{
    302 		/* If we found a server with the given source, that one just
    303 		 * finished bursting. If there was no source, then our uplink
    304 		 * server finished bursting. -GD
    305 		 */
    306 		Server *s = source.GetServer();
    307 		if (!s)
    308 			s = Me->GetLinks().front();
    309 		if (s)
    310 			s->Sync(true);
    311 	}
    312 };
    313 
    314 struct IRCDMessageMode : IRCDMessage
    315 {
    316 	IRCDMessageMode(Module *creator, const Anope::string &sname) : IRCDMessage(creator, sname, 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    317 
    318 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    319 	{
    320 		if (params.size() > 2 && IRCD->IsChannelValid(params[0]))
    321 		{
    322 			Channel *c = Channel::Find(params[0]);
    323 			time_t ts = 0;
    324 
    325 			try
    326 			{
    327 				ts = convertTo<time_t>(params[1]);
    328 			}
    329 			catch (const ConvertException &) { }
    330 
    331 			Anope::string modes = params[2];
    332 			for (unsigned int i = 3; i < params.size(); ++i)
    333 				modes += " " + params[i];
    334 
    335 			if (c)
    336 				c->SetModesInternal(source, modes, ts);
    337 		}
    338 		else
    339 		{
    340 			User *u = User::Find(params[0]);
    341 			if (u)
    342 				u->SetModesInternal(source, "%s", params[1].c_str());
    343 		}
    344 	}
    345 };
    346 
    347 /*
    348  ** NICK - new
    349  **	  source  = NULL
    350  **	  parv[0] = nickname
    351  **	  parv[1] = hopcount
    352  **	  parv[2] = timestamp
    353  **	  parv[3] = modes
    354  **	  parv[4] = username
    355  **	  parv[5] = hostname
    356  **	  parv[6] = server
    357  **	  parv[7] = servicestamp
    358  **	  parv[8] = IP
    359  **	  parv[9] = info
    360  ** NICK - change
    361  **	  source  = oldnick
    362  **	  parv[0] = new nickname
    363  **	  parv[1] = hopcount
    364  */
    365 struct IRCDMessageNick : IRCDMessage
    366 {
    367 	IRCDMessageNick(Module *creator) : IRCDMessage(creator, "NICK", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    368 
    369 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    370 	{
    371 		if (params.size() == 10)
    372 		{
    373 			Server *s = Server::Find(params[6]);
    374 			if (s == NULL)
    375 			{
    376 				Log(LOG_DEBUG) << "User " << params[0] << " introduced from nonexistent server " << params[6] << "?";
    377 				return;
    378 			}
    379 
    380 			NickAlias *na = NULL;
    381 			time_t signon = params[2].is_pos_number_only() ? convertTo<time_t>(params[2]) : 0,
    382 				stamp = params[7].is_pos_number_only() ? convertTo<time_t>(params[7]) : 0;
    383 			if (signon && signon == stamp)
    384 				na = NickAlias::Find(params[0]);
    385 
    386 			User::OnIntroduce(params[0], params[4], params[5], "", params[8], s, params[9], signon, params[3], "", na ? *na->nc : NULL);
    387 		}
    388 		else
    389 		{
    390 			User *u = source.GetUser();
    391 
    392 			if (u)
    393 				u->ChangeNick(params[0]);
    394 		}
    395 	}
    396 };
    397 
    398 struct IRCDMessageServer : IRCDMessage
    399 {
    400 	IRCDMessageServer(Module *creator) : IRCDMessage(creator, "SERVER", 3) { SetFlag(IRCDMESSAGE_REQUIRE_SERVER); }
    401 
    402 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    403 	{
    404 		unsigned int hops = Anope::string(params[1]).is_pos_number_only() ? convertTo<unsigned>(params[1]) : 0;
    405 		new Server(source.GetServer() == NULL ? Me : source.GetServer(), params[0], hops, params[2]);
    406 	}
    407 };
    408 
    409 struct IRCDMessageSJoin : IRCDMessage
    410 {
    411 	IRCDMessageSJoin(Module *creator) : IRCDMessage(creator, "SJOIN", 2) { SetFlag(IRCDMESSAGE_SOFT_LIMIT); }
    412 
    413 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    414 	{
    415 		Anope::string modes;
    416 		if (params.size() >= 4)
    417 			for (unsigned i = 2; i < params.size(); ++i)
    418 				modes += " " + params[i];
    419 		if (!modes.empty())
    420 			modes.erase(modes.begin());
    421 
    422 		std::list<Message::Join::SJoinUser> users;
    423 
    424 		/* For some reason, bahamut will send a SJOIN from the user joining a channel
    425 		 * if the channel already existed
    426 		 */
    427 		if (source.GetUser())
    428 		{
    429 			Message::Join::SJoinUser sju;
    430 			sju.second = source.GetUser();
    431 			users.push_back(sju);
    432 		}
    433 		else
    434 		{
    435 			spacesepstream sep(params[params.size() - 1]);
    436 			Anope::string buf;
    437 
    438 			while (sep.GetToken(buf))
    439 			{
    440 				Message::Join::SJoinUser sju;
    441 
    442 				/* Get prefixes from the nick */
    443 				for (char ch; (ch = ModeManager::GetStatusChar(buf[0]));)
    444 				{
    445 					buf.erase(buf.begin());
    446 					sju.first.AddMode(ch);
    447 				}
    448 
    449 				sju.second = User::Find(buf);
    450 				if (!sju.second)
    451 				{
    452 					Log(LOG_DEBUG) << "SJOIN for nonexistent user " << buf << " on " << params[1];
    453 					continue;
    454 				}
    455 
    456 				users.push_back(sju);
    457 			}
    458 		}
    459 
    460 		time_t ts = Anope::string(params[0]).is_pos_number_only() ? convertTo<time_t>(params[0]) : Anope::CurTime;
    461 		Message::Join::SJoin(source, params[1], ts, modes, users);
    462 	}
    463 };
    464 
    465 struct IRCDMessageTopic : IRCDMessage
    466 {
    467 	IRCDMessageTopic(Module *creator) : IRCDMessage(creator, "TOPIC", 4) { }
    468 
    469 	void Run(MessageSource &source, const std::vector<Anope::string> &params) anope_override
    470 	{
    471 		Channel *c = Channel::Find(params[0]);
    472 		if (c)
    473 			c->ChangeTopicInternal(source.GetUser(), params[1], params[3], Anope::string(params[2]).is_pos_number_only() ? convertTo<time_t>(params[2]) : Anope::CurTime);
    474 	}
    475 };
    476 
    477 class ProtoBahamut : public Module
    478 {
    479 	BahamutIRCdProto ircd_proto;
    480 
    481 	/* Core message handlers */
    482 	Message::Away message_away;
    483 	Message::Capab message_capab;
    484 	Message::Error message_error;
    485 	Message::Invite message_invite;
    486 	Message::Join message_join;
    487 	Message::Kick message_kick;
    488 	Message::Kill message_kill;
    489 	Message::MOTD message_motd;
    490 	Message::Notice message_notice;
    491 	Message::Part message_part;
    492 	Message::Ping message_ping;
    493 	Message::Privmsg message_privmsg;
    494 	Message::Quit message_quit;
    495 	Message::SQuit message_squit;
    496 	Message::Stats message_stats;
    497 	Message::Time message_time;
    498 	Message::Version message_version;
    499 	Message::Whois message_whois;
    500 
    501 	/* Our message handlers */
    502 	IRCDMessageBurst message_burst;
    503 	IRCDMessageMode message_mode, message_svsmode;
    504 	IRCDMessageNick message_nick;
    505 	IRCDMessageServer message_server;
    506 	IRCDMessageSJoin message_sjoin;
    507 	IRCDMessageTopic message_topic;
    508 
    509 	void AddModes()
    510 	{
    511 		/* Add user modes */
    512 		ModeManager::AddUserMode(new UserModeOperOnly("SERV_ADMIN", 'A'));
    513 		ModeManager::AddUserMode(new UserMode("REGPRIV", 'R'));
    514 		ModeManager::AddUserMode(new UserModeOperOnly("ADMIN", 'a'));
    515 		ModeManager::AddUserMode(new UserMode("INVIS", 'i'));
    516 		ModeManager::AddUserMode(new UserModeOperOnly("OPER", 'o'));
    517 		ModeManager::AddUserMode(new UserModeNoone("REGISTERED", 'r'));
    518 		ModeManager::AddUserMode(new UserModeOperOnly("SNOMASK", 's'));
    519 		ModeManager::AddUserMode(new UserModeOperOnly("WALLOPS", 'w'));
    520 		ModeManager::AddUserMode(new UserMode("DEAF", 'd'));
    521 
    522 		/* b/e/I */
    523 		ModeManager::AddChannelMode(new ChannelModeList("BAN", 'b'));
    524 
    525 		/* v/h/o/a/q */
    526 		ModeManager::AddChannelMode(new ChannelModeStatus("VOICE", 'v', '+', 0));
    527 		ModeManager::AddChannelMode(new ChannelModeStatus("HALFOP", 'h', '%', 1));
    528 		ModeManager::AddChannelMode(new ChannelModeStatus("OP", 'o', '@', 1));
    529 
    530 		/* Add channel modes */
    531 		ModeManager::AddChannelMode(new ChannelMode("BLOCKCOLOR", 'c'));
    532 		ModeManager::AddChannelMode(new ChannelMode("INVITE", 'i'));
    533 		ModeManager::AddChannelMode(new ChannelModeFlood('f', false));
    534 		ModeManager::AddChannelMode(new ChannelModeKey('k'));
    535 		ModeManager::AddChannelMode(new ChannelModeParam("LIMIT", 'l', true));
    536 		ModeManager::AddChannelMode(new ChannelMode("MODERATED", 'm'));
    537 		ModeManager::AddChannelMode(new ChannelMode("NOEXTERNAL", 'n'));
    538 		ModeManager::AddChannelMode(new ChannelMode("PRIVATE", 'p'));
    539 		ModeManager::AddChannelMode(new ChannelModeNoone("REGISTERED", 'r'));
    540 		ModeManager::AddChannelMode(new ChannelMode("SECRET", 's'));
    541 		ModeManager::AddChannelMode(new ChannelMode("TOPIC", 't'));
    542 		ModeManager::AddChannelMode(new ChannelMode("REGMODERATED", 'M'));
    543 		ModeManager::AddChannelMode(new ChannelModeOperOnly("OPERONLY", 'O'));
    544 		ModeManager::AddChannelMode(new ChannelMode("REGISTEREDONLY", 'R'));
    545 	}
    546 
    547  public:
    548 	ProtoBahamut(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PROTOCOL | VENDOR),
    549 		ircd_proto(this),
    550 		message_away(this), message_capab(this), message_error(this), message_invite(this),
    551 		message_join(this), message_kick(this), message_kill(this), message_motd(this), message_notice(this),
    552 		message_part(this), message_ping(this), message_privmsg(this), message_quit(this),
    553 		message_squit(this), message_stats(this), message_time(this), message_version(this), message_whois(this),
    554 
    555 		message_burst(this), message_mode(this, "MODE"), message_svsmode(this, "SVSMODE"),
    556 		message_nick(this), message_server(this), message_sjoin(this), message_topic(this)
    557 	{
    558 
    559 		this->AddModes();
    560 
    561 	}
    562 
    563 	void OnUserNickChange(User *u, const Anope::string &) anope_override
    564 	{
    565 		u->RemoveModeInternal(Me, ModeManager::FindUserModeByName("REGISTERED"));
    566 		IRCD->SendLogout(u);
    567 	}
    568 };
    569 
    570 MODULE_INIT(ProtoBahamut)