/* Bahamut functions * * (C) 2003-2010 Anope Team * Contact us at team@anope.org * * Please read COPYING and README for further details. * * Based on the original code of Epona by Lara. * Based on the original code of Services by Andy Church. * * */ /*************************************************************************/ #include "services.h" #include "pseudo.h" IRCDVar myIrcd[] = { {"Bahamut 1.8.x", /* ircd name */ "+", /* Modes used by pseudoclients */ 2, /* Chan Max Symbols */ "+o", /* Channel Umode used by Botserv bots */ 1, /* SVSNICK */ 0, /* Vhost */ 1, /* Supports SGlines */ 1, /* Supports SQlines */ 1, /* Supports SZlines */ 3, /* Number of server args */ 0, /* Join 2 Set */ 0, /* Join 2 Message */ 0, /* TS Topic Forward */ 0, /* TS Topci Backward */ 1, /* Chan SQlines */ 1, /* Quit on Kill */ 1, /* SVSMODE unban */ 0, /* Reverse */ 0, /* vidents */ 1, /* svshold */ 1, /* time stamp on mode */ 1, /* NICKIP */ 0, /* O:LINE */ 1, /* UMODE */ 0, /* VHOST ON NICK */ 0, /* Change RealName */ 1, /* No Knock requires +i */ 0, /* We support TOKENS */ 0, /* TIME STAMPS are BASE64 */ 0, /* Can remove User Channel Modes with SVSMODE */ 0, /* Sglines are not enforced until user reconnects */ 0, /* ts6 */ 0, /* p10 */ 0, /* CIDR channelbans */ "$", /* TLD Prefix for Global */ 6, /* Max number of modes we can send per line */ } , {NULL} }; void bahamut_cmd_burst() { send_cmd(NULL, "BURST"); } /* * SVINFO * parv[0] = sender prefix * parv[1] = TS_CURRENT for the server * parv[2] = TS_MIN for the server * parv[3] = server is standalone or connected to non-TS only * parv[4] = server's idea of UTC time */ void bahamut_cmd_svinfo() { send_cmd(NULL, "SVINFO 3 1 0 :%ld", static_cast(time(NULL))); } /* PASS */ void bahamut_cmd_pass(const char *pass) { send_cmd(NULL, "PASS %s :TS", pass); } /* CAPAB */ void bahamut_cmd_capab() { send_cmd(NULL, "CAPAB SSJOIN NOQUIT BURST UNCONNECT NICKIP TSMODE TS3"); } /* this avoids "undefined symbol" messages of those whom try to load mods that call on this function */ void bahamut_cmd_chghost(const char *nick, const char *vhost) { Alog(LOG_DEBUG) << "This IRCD does not support vhosting"; } class BahamutIRCdProto : public IRCDProto { void SendModeInternal(BotInfo *source, Channel *dest, const char *buf) { if (!buf) return; if (Capab.HasFlag(CAPAB_TSMODE)) send_cmd(source->nick, "MODE %s 0 %s", dest->name.c_str(), buf); else send_cmd(source->nick, "MODE %s %s", dest->name.c_str(), buf); } void SendModeInternal(BotInfo *bi, User *u, const char *buf) { if (!buf) return; send_cmd(bi ? bi->nick : Config.ServerName, "SVSMODE %s %ld %s", u->nick.c_str(), static_cast(u->timestamp), buf); } /* SVSHOLD - set */ void SendSVSHold(const char *nick) { send_cmd(Config.ServerName, "SVSHOLD %s %u :%s", nick, static_cast(Config.NSReleaseTimeout), "Being held for registered user"); } /* SVSHOLD - release */ void SendSVSHoldDel(const char *nick) { send_cmd(Config.ServerName, "SVSHOLD %s 0", nick); } /* SVSMODE -b */ void SendBanDel(Channel *c, const std::string &nick) { SendSVSModeChan(c, "-b", nick.empty() ? NULL : nick.c_str()); } /* SVSMODE channel modes */ void SendSVSModeChan(Channel *c, const char *mode, const char *nick) { if (nick) send_cmd(Config.ServerName, "SVSMODE %s %s %s", c->name.c_str(), mode, nick); else send_cmd(Config.ServerName, "SVSMODE %s %s", c->name.c_str(), mode); } /* SQLINE */ void SendSQLine(const std::string &mask, const std::string &reason) { if (mask.empty() || reason.empty()) return; send_cmd(NULL, "SQLINE %s :%s", mask.c_str(), reason.c_str()); } /* UNSGLINE */ void SendSGLineDel(SXLine *sx) { send_cmd(NULL, "UNSGLINE 0 :%s", sx->mask); } /* UNSZLINE */ void SendSZLineDel(SXLine *sx) { /* this will likely fail so its only here for legacy */ send_cmd(NULL, "UNSZLINE 0 %s", sx->mask); /* this is how we are supposed to deal with it */ send_cmd(NULL, "RAKILL %s *", sx->mask); } /* SZLINE */ void SendSZLine(SXLine *sx) { /* this will likely fail so its only here for legacy */ send_cmd(NULL, "SZLINE %s :%s", sx->mask, sx->reason); /* this is how we are supposed to deal with it */ send_cmd(NULL, "AKILL %s * %d %s %ld :%s", sx->mask, 172800, sx->by, static_cast(time(NULL)), sx->reason); } /* SVSNOOP */ void SendSVSNOOP(const char *server, int set) { send_cmd(NULL, "SVSNOOP %s %s", server, set ? "+" : "-"); } /* SGLINE */ void SendSGLine(SXLine *sx) { send_cmd(NULL, "SGLINE %d :%s:%s", static_cast(strlen(sx->mask)), sx->mask, sx->reason); } /* RAKILL */ void SendAkillDel(Akill *ak) { send_cmd(NULL, "RAKILL %s %s", ak->host, ak->user); } /* TOPIC */ void SendTopic(BotInfo *whosets, Channel *c, const char *whosetit, const char *topic) { send_cmd(whosets->nick, "TOPIC %s %s %lu :%s", c->name.c_str(), whosetit, static_cast(c->topic_time), topic); } /* UNSQLINE */ void SendSQLineDel(const std::string &user) { if (user.empty()) return; send_cmd(NULL, "UNSQLINE %s", user.c_str()); } /* JOIN - SJOIN */ void SendJoin(BotInfo *user, const char *channel, time_t chantime) { send_cmd(user->nick, "SJOIN %ld %s", static_cast(chantime), channel); } void SendAkill(Akill *ak) { // Calculate the time left before this would expire, capping it at 2 days time_t timeleft = ak->expires - time(NULL); if (timeleft > 172800) timeleft = 172800; send_cmd(NULL, "AKILL %s %s %d %s %ld :%s", ak->host, ak->user, static_cast(timeleft), ak->by, static_cast(time(NULL)), ak->reason); } /* Note: if the stamp is null 0, the below usage is correct of Bahamut */ void SendSVSKillInternal(BotInfo *source, User *user, const char *buf) { send_cmd(source ? source->nick : NULL, "SVSKILL %s :%s", user->nick.c_str(), buf); } /* SVSMODE */ /* parv[0] - sender * parv[1] - nick * parv[2] - TS (or mode, depending on svs version) * parv[3] - mode (or services id if old svs version) * parv[4] - optional arguement (services id) */ void SendSVSMode(User *u, int ac, const char **av) { this->SendModeInternal(NULL, u, merge_args(ac, av)); } void SendEOB() { send_cmd(NULL, "BURST 0"); } void SendNoticeChanopsInternal(BotInfo *source, Channel *dest, const char *buf) { if (!buf) return; send_cmd(NULL, "NOTICE @%s :%s", dest->name.c_str(), buf); } void SendKickInternal(BotInfo *source, Channel *chan, User *user, const char *buf) { if (buf) send_cmd(source->nick, "KICK %s %s :%s", chan->name.c_str(), user->nick.c_str(), buf); else send_cmd(source->nick, "KICK %s %s", chan->name.c_str(), user->nick.c_str()); } void SendClientIntroduction(const std::string &nick, const std::string &user, const std::string &host, const std::string &real, const char *modes, const std::string &uid) { EnforceQlinedNick(nick, Config.s_BotServ); send_cmd(NULL, "NICK %s 1 %ld %s %s %s %s 0 0 :%s", nick.c_str(), static_cast(time(NULL)), modes, user.c_str(), host.c_str(), Config.ServerName, real.c_str()); } /* SVSMODE +d */ /* nc_change was = 1, and there is no na->status */ void SendUnregisteredNick(User *u) { BotInfo *bi = findbot(Config.s_NickServ); u->RemoveMode(bi, UMODE_REGISTERED); ircdproto->SendMode(bi, u, "+d 1"); } /* SERVER */ void SendServer(Server *server) { send_cmd(NULL, "SERVER %s %d :%s", server->name, server->hops, server->desc); } void SendConnect() { bahamut_cmd_pass(uplink_server->password); bahamut_cmd_capab(); me_server = new_server(NULL, Config.ServerName, Config.ServerDesc, SERVER_ISME, ""); SendServer(me_server); bahamut_cmd_svinfo(); bahamut_cmd_burst(); } void SetAutoIdentificationToken(User *u) { char svidbuf[15]; if (!u->Account()) return; srand(time(NULL)); snprintf(svidbuf, sizeof(svidbuf), "%d", rand()); u->Account()->Shrink("authenticationtoken"); u->Account()->Extend("authenticationtoken", new ExtensibleItemPointerArray(sstrdup(svidbuf))); BotInfo *bi = findbot(Config.s_NickServ); u->SetMode(bi, UMODE_REGISTERED); ircdproto->SendMode(bi, u, "+d %s", svidbuf); } } ircd_proto; /* EVENT: SJOIN */ int anope_event_sjoin(const char *source, int ac, const char **av) { Channel *c = findchan(av[1]); time_t ts = atol(av[0]); bool was_created = false; bool keep_their_modes = false; if (!c) { c = new Channel(av[1], ts); was_created = true; } /* Our creation time is newer than what the server gave us */ else if (c->creation_time > ts) { c->creation_time = ts; /* Remove status from all of our users */ for (CUserList::iterator it = c->users.begin(); it != c->users.end(); ++it) { UserContainer *uc = *it; c->RemoveMode(NULL, CMODE_OWNER, uc->user->nick); c->RemoveMode(NULL, CMODE_PROTECT, uc->user->nick); c->RemoveMode(NULL, CMODE_OP, uc->user->nick); c->RemoveMode(NULL, CMODE_HALFOP, uc->user->nick); c->RemoveMode(NULL, CMODE_VOICE, uc->user->nick); } if (c->ci) { /* Rejoin the bot to fix the TS */ if (c->ci->bi) { ircdproto->SendPart(c->ci->bi, c, "TS reop"); bot_join(c->ci); } /* Reset mlock */ check_modes(c); } } /* Their TS is newer than ours, our modes > theirs, unset their modes if need be */ else keep_their_modes = false; /* Mark the channel as syncing */ if (was_created) c->SetFlag(CH_SYNCING); /* If we need to keep their modes, and this SJOIN string contains modes */ if (keep_their_modes && ac >= 4) { /* Set the modes internally */ ChanSetInternalModes(c, ac - 3, av + 2); } /* For a reason unknown to me, bahamut will send a SJOIN from the user joining a channel * if the channel already existed */ if (!was_created && ac == 2) { User *u = finduser(source); if (!u) { Alog(LOG_DEBUG) << "SJOIN for nonexistant user " << source << " on " << c->name; } else { EventReturn MOD_RESULT; FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); /* Add the user to the channel */ c->JoinUser(u); /* Now set whatever modes this user is allowed to have on the channel */ chan_set_correct_modes(u, c, 1); /* Check to see if modules want the user to join, if they do * check to see if they are allowed to join (CheckKick will kick/ban them) * Don't trigger OnJoinChannel event then as the user will be destroyed */ if (MOD_RESULT == EVENT_STOP && (!c->ci || !c->ci->CheckKick(u))) { FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); } } } else { spacesepstream sep(av[ac - 1]); std::string buf; while (sep.GetToken(buf)) { std::list Status; Status.clear(); char ch; /* Get prefixes from the nick */ while ((ch = ModeManager::GetStatusChar(buf[0]))) { buf.erase(buf.begin()); ChannelMode *cm = ModeManager::FindChannelModeByChar(ch); if (!cm) { Alog() << "Recieved unknown mode prefix " << buf[0] << " in SJOIN string"; continue; } Status.push_back(cm); } User *u = finduser(buf); if (!u) { Alog(LOG_DEBUG) << "SJOIN for nonexistant user " << buf << " on " << c->name; continue; } EventReturn MOD_RESULT; FOREACH_RESULT(I_OnPreJoinChannel, OnPreJoinChannel(u, c)); /* Add the user to the channel */ c->JoinUser(u); /* Update their status internally on the channel * This will enforce secureops etc on the user */ for (std::list::iterator it = Status.begin(); it != Status.end(); ++it) { c->SetModeInternal(*it, buf); } /* Now set whatever modes this user is allowed to have on the channel */ chan_set_correct_modes(u, c, 1); /* Check to see if modules want the user to join, if they do * check to see if they are allowed to join (CheckKick will kick/ban them) * Don't trigger OnJoinChannel event then as the user will be destroyed */ if (MOD_RESULT != EVENT_STOP && c->ci && c->ci->CheckKick(u)) continue; FOREACH_MOD(I_OnJoinChannel, OnJoinChannel(u, c)); } } /* Channel is done syncing */ if (was_created) { /* Unset the syncing flag */ c->UnsetFlag(CH_SYNCING); /* If there are users in the channel they are allowed to be, set topic mlock etc. */ if (!c->users.empty()) c->Sync(); /* If there are no users in the channel, there is a ChanServ timer set to part the service bot * and destroy the channel soon */ } return MOD_CONT; } /* ** NICK - new ** source = NULL ** parv[0] = nickname ** parv[1] = hopcount ** parv[2] = timestamp ** parv[3] = modes ** parv[4] = username ** parv[5] = hostname ** parv[6] = server ** parv[7] = servicestamp ** parv[8] = IP ** parv[9] = info ** NICK - change ** source = oldnick ** parv[0] = new nickname ** parv[1] = hopcount */ int anope_event_nick(const char *source, int ac, const char **av) { User *user; if (ac != 2) { user = do_nick(source, av[0], av[4], av[5], av[6], av[9], strtoul(av[2], NULL, 10), strtoul(av[8], NULL, 0), NULL, NULL); if (user) { /* Check to see if the user should be identified because their * services id matches the one in their nickcore */ user->CheckAuthenticationToken(av[7]); UserSetInternalModes(user, 1, &av[3]); } } else { do_nick(source, av[0], NULL, NULL, NULL, NULL, strtoul(av[1], NULL, 10), 0, NULL, NULL); } return MOD_CONT; } /* EVENT : CAPAB */ int anope_event_capab(const char *source, int ac, const char **av) { CapabParse(ac, av); return MOD_CONT; } /* EVENT : OS */ int anope_event_os(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_OperServ, av[0]); return MOD_CONT; } /* EVENT : NS */ int anope_event_ns(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_NickServ, av[0]); return MOD_CONT; } /* EVENT : MS */ int anope_event_ms(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_MemoServ, av[0]); return MOD_CONT; } /* EVENT : HS */ int anope_event_hs(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_HostServ, av[0]); return MOD_CONT; } /* EVENT : CS */ int anope_event_cs(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_privmsg(source, Config.s_ChanServ, av[0]); return MOD_CONT; } int anope_event_436(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; m_nickcoll(av[0]); return MOD_CONT; } /* EVENT : SERVER */ int anope_event_server(const char *source, int ac, const char **av) { if (!stricmp(av[1], "1")) { uplink = sstrdup(av[0]); } do_server(source, av[0], av[1], av[2], ""); return MOD_CONT; } /* EVENT : PRIVMSG */ int anope_event_privmsg(const char *source, int ac, const char **av) { if (ac != 2) return MOD_CONT; m_privmsg(source, av[0], av[1]); return MOD_CONT; } int anope_event_part(const char *source, int ac, const char **av) { if (ac < 1 || ac > 2) return MOD_CONT; do_part(source, ac, av); return MOD_CONT; } int anope_event_whois(const char *source, int ac, const char **av) { if (source && ac >= 1) { m_whois(source, av[0]); } return MOD_CONT; } int anope_event_topic(const char *source, int ac, const char **av) { if (ac != 4) return MOD_CONT; do_topic(source, ac, av); return MOD_CONT; } int anope_event_squit(const char *source, int ac, const char **av) { if (ac != 2) return MOD_CONT; do_squit(source, ac, av); return MOD_CONT; } int anope_event_quit(const char *source, int ac, const char **av) { if (ac != 1) return MOD_CONT; do_quit(source, ac, av); return MOD_CONT; } /* EVENT: MODE */ int anope_event_mode(const char *source, int ac, const char **av) { if (ac < 2) return MOD_CONT; if (*av[0] == '#' || *av[0] == '&') { do_cmode(source, ac, av); } else { do_umode(source, ac, av); } return MOD_CONT; } /* EVENT: KILL */ int anope_event_kill(const char *source, int ac, const char **av) { if (ac != 2) return MOD_CONT; m_kill(av[0], av[1]); return MOD_CONT; } /* EVENT: KICK */ int anope_event_kick(const char *source, int ac, const char **av) { if (ac != 3) return MOD_CONT; do_kick(source, ac, av); return MOD_CONT; } /* EVENT: JOIN */ int anope_event_join(const char *source, int ac, const char **av) { if (ac != 1) return MOD_CONT; do_join(source, ac, av); return MOD_CONT; } /* EVENT: MOTD */ int anope_event_motd(const char *source, int ac, const char **av) { if (!source) { return MOD_CONT; } m_motd(source); return MOD_CONT; } int anope_event_away(const char *source, int ac, const char **av) { if (!source) { return MOD_CONT; } m_away(source, (ac ? av[0] : NULL)); return MOD_CONT; } int anope_event_ping(const char *source, int ac, const char **av) { if (ac < 1) return MOD_CONT; ircdproto->SendPong(ac > 1 ? av[1] : Config.ServerName, av[0]); return MOD_CONT; } int anope_event_error(const char *source, int ac, const char **av) { if (ac >= 1) Alog(LOG_DEBUG) << av[0]; return MOD_CONT; } int anope_event_burst(const char *source, int ac, const char **av) { Server *s; s = findserver(servlist, source); if (!ac) { /* for future use - start burst */ } else { /* If we found a server with the given source, that one just * finished bursting. If there was no source, then our uplink * server finished bursting. -GD */ if (!s && serv_uplink) s = serv_uplink; finish_sync(s, 1); } return MOD_CONT; } bool ChannelModeFlood::IsValid(const std::string &value) { char *dp, *end; if (!value.empty() && value[0] != ':' && strtoul((value[0] == '*' ? value.c_str() + 1 : value.c_str()), &dp, 10) > 0 && *dp == ':' && *(++dp) && strtoul(dp, &end, 10) > 0 && !*end) return true; return false; } void moduleAddIRCDMsgs() { Message *m; /* now add the commands */ m = createMessage("436", anope_event_436); addCoreMessage(IRCD,m); m = createMessage("AWAY", anope_event_away); addCoreMessage(IRCD,m); m = createMessage("JOIN", anope_event_join); addCoreMessage(IRCD,m); m = createMessage("KICK", anope_event_kick); addCoreMessage(IRCD,m); m = createMessage("KILL", anope_event_kill); addCoreMessage(IRCD,m); m = createMessage("MODE", anope_event_mode); addCoreMessage(IRCD,m); m = createMessage("MOTD", anope_event_motd); addCoreMessage(IRCD,m); m = createMessage("NICK", anope_event_nick); addCoreMessage(IRCD,m); m = createMessage("PART", anope_event_part); addCoreMessage(IRCD,m); m = createMessage("PING", anope_event_ping); addCoreMessage(IRCD,m); m = createMessage("PRIVMSG", anope_event_privmsg); addCoreMessage(IRCD,m); m = createMessage("QUIT", anope_event_quit); addCoreMessage(IRCD,m); m = createMessage("SERVER", anope_event_server); addCoreMessage(IRCD,m); m = createMessage("SQUIT", anope_event_squit); addCoreMessage(IRCD,m); m = createMessage("TOPIC", anope_event_topic); addCoreMessage(IRCD,m); m = createMessage("WHOIS", anope_event_whois); addCoreMessage(IRCD,m); m = createMessage("SVSMODE", anope_event_mode); addCoreMessage(IRCD,m); m = createMessage("CAPAB", anope_event_capab); addCoreMessage(IRCD,m); m = createMessage("CS", anope_event_cs); addCoreMessage(IRCD,m); m = createMessage("HS", anope_event_hs); addCoreMessage(IRCD,m); m = createMessage("MS", anope_event_ms); addCoreMessage(IRCD,m); m = createMessage("NS", anope_event_ns); addCoreMessage(IRCD,m); m = createMessage("OS", anope_event_os); addCoreMessage(IRCD,m); m = createMessage("SJOIN", anope_event_sjoin); addCoreMessage(IRCD,m); m = createMessage("ERROR", anope_event_error); addCoreMessage(IRCD,m); m = createMessage("BURST", anope_event_burst); addCoreMessage(IRCD,m); } void moduleAddModes() { /* Add user modes */ ModeManager::AddUserMode(new UserMode(UMODE_SERV_ADMIN, 'A')); ModeManager::AddUserMode(new UserMode(UMODE_REGPRIV, 'R')); ModeManager::AddUserMode(new UserMode(UMODE_ADMIN, 'a')); ModeManager::AddUserMode(new UserMode(UMODE_INVIS, 'i')); ModeManager::AddUserMode(new UserMode(UMODE_OPER, 'o')); ModeManager::AddUserMode(new UserMode(UMODE_REGISTERED, 'r')); ModeManager::AddUserMode(new UserMode(UMODE_SNOMASK, 's')); ModeManager::AddUserMode(new UserMode(UMODE_WALLOPS, 'w')); ModeManager::AddUserMode(new UserMode(UMODE_DEAF, 'd')); /* b/e/I */ ModeManager::AddChannelMode(new ChannelModeBan('b')); /* v/h/o/a/q */ ModeManager::AddChannelMode(new ChannelModeStatus(CMODE_VOICE, 'v', '+')); ModeManager::AddChannelMode(new ChannelModeStatus(CMODE_OP, 'o', '@')); /* Add channel modes */ ModeManager::AddChannelMode(new ChannelMode(CMODE_BLOCKCOLOR, 'c')); ModeManager::AddChannelMode(new ChannelMode(CMODE_INVITE, 'i')); ModeManager::AddChannelMode(new ChannelModeFlood('f')); ModeManager::AddChannelMode(new ChannelModeKey('k')); ModeManager::AddChannelMode(new ChannelModeParam(CMODE_LIMIT, 'l')); ModeManager::AddChannelMode(new ChannelMode(CMODE_MODERATED, 'm')); ModeManager::AddChannelMode(new ChannelMode(CMODE_NOEXTERNAL, 'n')); ModeManager::AddChannelMode(new ChannelMode(CMODE_PRIVATE, 'p')); ModeManager::AddChannelMode(new ChannelModeRegistered('r')); ModeManager::AddChannelMode(new ChannelMode(CMODE_SECRET, 's')); ModeManager::AddChannelMode(new ChannelMode(CMODE_TOPIC, 't')); ModeManager::AddChannelMode(new ChannelMode(CMODE_REGMODERATED, 'M')); ModeManager::AddChannelMode(new ChannelModeOper('O')); ModeManager::AddChannelMode(new ChannelMode(CMODE_REGISTEREDONLY, 'R')); } class ProtoBahamut : public Module { public: ProtoBahamut(const std::string &modname, const std::string &creator) : Module(modname, creator) { this->SetAuthor("Anope"); this->SetVersion("$Id$"); this->SetType(PROTOCOL); pmodule_ircd_version("BahamutIRCd 1.4.*/1.8.*"); pmodule_ircd_var(myIrcd); pmodule_ircd_useTSMode(0); CapabType c[] = { CAPAB_NOQUIT, CAPAB_TSMODE, CAPAB_UNCONNECT, CAPAB_BURST, CAPAB_DKEY, CAPAB_DOZIP }; for (unsigned i = 0; i < 6; ++i) Capab.SetFlag(c[i]); moduleAddIRCDMsgs(); moduleAddModes(); pmodule_ircd_proto(&ircd_proto); ModuleManager::Attach(I_OnUserNickChange, this); } void OnUserNickChange(User *u, const std::string &) { u->RemoveModeInternal(ModeManager::FindUserModeByName(UMODE_REGISTERED)); } }; MODULE_INIT(ProtoBahamut)