CmdResult CommandSQuit::HandleServer(TreeServer* server, std::vector<std::string>& params) { TreeServer* quitting = Utils->FindServer(params[0]); if (!quitting) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Squit from unknown server"); return CMD_FAILURE; } CmdResult ret = CMD_SUCCESS; if (quitting == server) { ret = CMD_FAILURE; server = server->GetParent(); } else if (quitting->GetParent() != server) throw ProtocolException("Attempted to SQUIT a non-directly connected server or the parent"); server->SQuitChild(quitting, params[1]); // XXX: Return CMD_FAILURE when servers SQUIT themselves (i.e. :00S SQUIT 00S :Shutting down) // to stop this message from being forwarded. // The squit logic generates a SQUIT message with our sid as the source and sends it to the // remaining servers. return ret; }
/** Because the core won't let users or even SERVERS set +o, * we use the OPERTYPE command to do this. */ CmdResult CommandOpertype::HandleRemote(RemoteUser* u, std::vector<std::string>& params) { const std::string& opertype = params[0]; if (!u->IsOper()) ServerInstance->Users->all_opers.push_back(u); ModeHandler* opermh = ServerInstance->Modes->FindMode('o', MODETYPE_USER); u->SetMode(opermh, true); OperIndex::iterator iter = ServerInstance->Config->OperTypes.find(opertype); if (iter != ServerInstance->Config->OperTypes.end()) u->oper = iter->second; else { u->oper = new OperInfo; u->oper->name = opertype; } if (Utils->quiet_bursts) { /* * If quiet bursts are enabled, and server is bursting or silent uline (i.e. services), * then do nothing. -- w00t */ TreeServer* remoteserver = TreeServer::Get(u); if (remoteserver->bursting || remoteserver->IsSilentULine()) return CMD_SUCCESS; } ServerInstance->SNO->WriteToSnoMask('O',"From %s: User %s (%s@%s) is now an IRC operator of type %s",u->server->GetName().c_str(), u->nick.c_str(),u->ident.c_str(), u->host.c_str(), opertype.c_str()); return CMD_SUCCESS; }
int ModuleSpanningTree::HandleStats(const char** parameters, int pcnt, userrec* user) { if (pcnt > 1) { if (match(ServerInstance->Config->ServerName, parameters[1])) return 0; /* Remote STATS, the server is within the 2nd parameter */ std::deque<std::string> params; params.push_back(parameters[0]); params.push_back(parameters[1]); /* Send it out remotely, generate no reply yet */ TreeServer* s = Utils->FindServerMask(parameters[1]); if (s) { params[1] = s->GetName(); Utils->DoOneToOne(user->nick, "STATS", params, s->GetName()); } else { user->WriteServ( "402 %s %s :No such server", user->nick, parameters[1]); } return 1; } return 0; }
/* returns a list of DIRECT servernames for a specific channel */ void SpanningTreeUtilities::GetListOfServersForChannel(Channel* c, TreeSocketSet& list, char status, const CUList& exempt_list) { unsigned int minrank = 0; if (status) { PrefixMode* mh = ServerInstance->Modes->FindPrefix(status); if (mh) minrank = mh->GetPrefixRank(); } const UserMembList *ulist = c->GetUsers(); for (UserMembCIter i = ulist->begin(); i != ulist->end(); i++) { if (IS_LOCAL(i->first)) continue; if (minrank && i->second->getRank() < minrank) continue; if (exempt_list.find(i->first) == exempt_list.end()) { TreeServer* best = TreeServer::Get(i->first); list.insert(best->GetSocket()); } } return; }
bool TreeSocket::DelLine(const std::string &prefix, parameterlist ¶ms) { if (params.size() < 2) return true; std::string setter = "<unknown>"; User* user = ServerInstance->FindNick(prefix); if (user) setter = user->nick; else { TreeServer* t = Utils->FindServer(prefix); if (t) setter = t->GetName(); } /* NOTE: No check needed on 'user', this function safely handles NULL */ if (ServerInstance->XLines->DelLine(params[1].c_str(), params[0], user)) { ServerInstance->SNO->WriteToSnoMask('X',"%s removed %s%s on %s", setter.c_str(), params[0].c_str(), params[0].length() == 1 ? "-line" : "", params[1].c_str()); Utils->DoOneToAllButSender(prefix,"DELLINE", params, prefix); } return true; }
int ModuleSpanningTree::HandleSquit(const char** parameters, int pcnt, userrec* user) { TreeServer* s = Utils->FindServerMask(parameters[0]); if (s) { if (s == Utils->TreeRoot) { user->WriteServ("NOTICE %s :*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (%s matches local server name)",user->nick,parameters[0]); return 1; } TreeSocket* sock = s->GetSocket(); if (sock) { ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0],user->nick); sock->Squit(s,std::string("Server quit by ") + user->GetFullRealHost()); ServerInstance->SE->DelFd(sock); sock->Close(); } else { if (IS_LOCAL(user)) user->WriteServ("NOTICE %s :*** WARNING: Using SQUIT to split remote servers is deprecated. Please use RSQUIT instead.",user->nick); } } else { user->WriteServ("NOTICE %s :*** SQUIT: The server \002%s\002 does not exist on the network.",user->nick,parameters[0]); } return 1; }
void ModuleSpanningTree::ShowLinks(TreeServer* Current, User* user, int hops) { std::string Parent = Utils->TreeRoot->GetName(); if (Current->GetParent()) { Parent = Current->GetParent()->GetName(); } const TreeServer::ChildServers& children = Current->GetChildren(); for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { TreeServer* server = *i; if ((server->Hidden) || ((Utils->HideULines) && (server->IsULine()))) { if (user->IsOper()) { ShowLinks(server, user, hops+1); } } else { ShowLinks(server, user, hops+1); } } /* Don't display the line if its a uline, hide ulines is on, and the user isnt an oper */ if ((Utils->HideULines) && (Current->IsULine()) && (!user->IsOper())) return; /* Or if the server is hidden and they're not an oper */ else if ((Current->Hidden) && (!user->IsOper())) return; user->WriteNumeric(RPL_LINKS, Current->GetName(), (((Utils->FlatLinks) && (!user->IsOper())) ? ServerInstance->Config->ServerName : Parent), InspIRCd::Format("%d %s", (((Utils->FlatLinks) && (!user->IsOper())) ? 0 : hops), Current->GetDesc().c_str())); }
ModResult ModuleSpanningTree::HandleSquit(const std::vector<std::string>& parameters, User* user) { TreeServer* s = Utils->FindServerMask(parameters[0]); if (s) { if (s == Utils->TreeRoot) { user->WriteNotice("*** SQUIT: Foolish mortal, you cannot make a server SQUIT itself! (" + parameters[0] + " matches local server name)"); return MOD_RES_DENY; } TreeSocket* sock = s->GetSocket(); if (sock) { ServerInstance->SNO->WriteToSnoMask('l',"SQUIT: Server \002%s\002 removed from network by %s",parameters[0].c_str(),user->nick.c_str()); sock->Squit(s,"Server quit by " + user->GetFullRealHost()); ServerInstance->SE->DelFd(sock); sock->Close(); } else { user->WriteNotice("*** SQUIT may not be used to remove remote servers. Please use RSQUIT instead."); } } else { user->WriteNotice("*** SQUIT: The server \002" + parameters[0] + "\002 does not exist on the network."); } return MOD_RES_DENY; }
void SpanningTreeUtilities::DoOneToOne(const CmdBuilder& params, Server* server) { TreeServer* ts = static_cast<TreeServer*>(server); TreeSocket* sock = ts->GetSocket(); if (sock) sock->WriteLine(params); }
ModResult ModuleSpanningTree::HandleVersion(const CommandBase::Params& parameters, User* user) { // We've already confirmed that !parameters.empty(), so this is safe TreeServer* found = Utils->FindServerMask(parameters[0]); if (found) { if (found == Utils->TreeRoot) { // Pass to default VERSION handler. return MOD_RES_PASSTHRU; } // If an oper wants to see the version then show the full version string instead of the normal, // but only if it is non-empty. // If it's empty it might be that the server is still syncing (full version hasn't arrived yet) // or the server is a 2.0 server and does not send a full version. bool showfull = ((user->IsOper()) && (!found->GetFullVersion().empty())); Numeric::Numeric numeric(RPL_VERSION); irc::tokenstream tokens(showfull ? found->GetFullVersion() : found->GetVersion()); for (std::string token; tokens.GetTrailing(token); ) numeric.push(token); user->WriteNumeric(numeric); } else { user->WriteNumeric(ERR_NOSUCHSERVER, parameters[0], "No such server"); } return MOD_RES_DENY; }
void ModuleSpanningTree::OnUserQuit(User* user, const std::string &reason, const std::string &oper_message) { if (IS_LOCAL(user)) { if (oper_message != reason) ServerInstance->PI->SendMetaData(user, "operquit", oper_message); CmdBuilder(user, "QUIT").push_last(reason).Broadcast(); } else { // Hide the message if one of the following is true: // - User is being quit due to a netsplit and quietbursts is on // - Server is a silent uline TreeServer* server = TreeServer::Get(user); bool hide = (((server->IsDead()) && (Utils->quiet_bursts)) || (server->IsSilentULine())); if (!hide) { ServerInstance->SNO.WriteToSnoMask('Q', "Client exiting on server %s: %s (%s) [%s]", user->server->GetName().c_str(), user->GetFullRealHost().c_str(), user->GetIPString().c_str(), oper_message.c_str()); } } // Regardless, update the UserCount TreeServer::Get(user)->UserCount--; }
ModResult ModuleSpanningTree::HandleVersion(const std::vector<std::string>& parameters, User* user) { // we've already checked if pcnt > 0, so this is safe TreeServer* found = Utils->FindServerMask(parameters[0]); if (found) { if (found == Utils->TreeRoot) { // Pass to default VERSION handler. return MOD_RES_PASSTHRU; } // If an oper wants to see the version then show the full version string instead of the normal, // but only if it is non-empty. // If it's empty it might be that the server is still syncing (full version hasn't arrived yet) // or the server is a 2.0 server and does not send a full version. bool showfull = ((user->IsOper()) && (!found->GetFullVersion().empty())); const std::string& Version = (showfull ? found->GetFullVersion() : found->GetVersion()); user->WriteNumeric(RPL_VERSION, ":%s", Version.c_str()); } else { user->WriteNumeric(ERR_NOSUCHSERVER, "%s :No such server", parameters[0].c_str()); } return MOD_RES_DENY; }
bool SpanningTreeProtocolInterface::SendEncapsulatedData(const std::string& targetmask, const std::string& cmd, const parameterlist& params, User* source) { if (!source) source = ServerInstance->FakeClient; CmdBuilder encap(source, "ENCAP"); // Are there any wildcards in the target string? if (targetmask.find_first_of("*?") != std::string::npos) { // Yes, send the target string as-is; servers will decide whether or not it matches them encap.push(targetmask).push(cmd).insert(params).Broadcast(); } else { // No wildcards which means the target string has to be the name of a known server TreeServer* server = Utils->FindServer(targetmask); if (!server) return false; // Use the SID of the target in the message instead of the server name encap.push(server->GetID()).push(cmd).insert(params).Unicast(server->ServerUser); } return true; }
void ModuleSpanningTree::OnGetServerDescription(const std::string &servername,std::string &description) { TreeServer* s = Utils->FindServer(servername); if (s) { description = s->GetDesc(); } }
bool SpanningTreeUtilities::DoOneToOne(const CmdBuilder& params, const std::string& target) { TreeServer* Route = this->BestRouteTo(target); if (!Route) return false; Route->GetSocket()->WriteLine(params); return true; }
bool SpanningTreeUtilities::DoOneToOne(const std::string& prefix, const std::string& command, const parameterlist& params, const std::string& target) { TreeServer* Route = this->BestRouteTo(target); if (!Route) return false; Route->GetSocket()->WriteLine(ConstructLine(prefix, command, params)); return true; }
void TreeServer::FinishBurstInternal() { this->bursting = false; SetNextPingTime(ServerInstance->Time() + Utils->PingFreq); SetPingFlag(); for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i) { TreeServer* child = *i; child->FinishBurstInternal(); } }
void TreeServer::FinishBurstInternal() { this->bursting = false; SetNextPingTime(ServerInstance->Time() + Utils->PingFreq); SetPingFlag(); for(unsigned int q=0; q < ChildCount(); q++) { TreeServer* child = GetChild(q); child->FinishBurstInternal(); } }
void CommandMap::ShowMap(TreeServer* Current, User* user, int depth, int &line, char* names, int &maxnamew, char* stats) { ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "ShowMap depth %d on line %d", depth, line); float percent; if (ServerInstance->Users->clientlist->size() == 0) { // If there are no users, WHO THE HELL DID THE /MAP?!?!?! percent = 0; } else { percent = Current->UserCount * 100.0 / ServerInstance->Users->clientlist->size(); } const std::string operdata = user->IsOper() ? MapOperInfo(Current) : ""; char* myname = names + 100 * line; char* mystat = stats + 50 * line; memset(myname, ' ', depth); int w = depth; if (user->IsOper()) { w += snprintf(myname + depth, 99 - depth, "%s (%s)", Current->GetName().c_str(), Current->GetID().c_str()); } else { w += snprintf(myname + depth, 99 - depth, "%s", Current->GetName().c_str()); } memset(myname + w, ' ', 100 - w); if (w > maxnamew) maxnamew = w; snprintf(mystat, 49, "%5d [%5.2f%%]%s", Current->UserCount, percent, operdata.c_str()); line++; if (user->IsOper() || !Utils->FlatLinks) depth = depth + 2; const TreeServer::ChildServers& servers = Current->GetChildren(); for (TreeServer::ChildServers::const_iterator i = servers.begin(); i != servers.end(); ++i) { TreeServer* child = *i; if (!user->IsOper()) { if (child->Hidden) continue; if ((Utils->HideULines) && (ServerInstance->ULine(child->GetName()))) continue; } ShowMap(child, user, depth, line, names, maxnamew, stats); } }
void ModuleSpanningTree::ShowMap(TreeServer* Current, User* user, int depth, int &line, char* names, int &maxnamew, char* stats) { ServerInstance->Logs->Log("map",LOG_DEBUG,"ShowMap depth %d on line %d", depth, line); float percent; if (ServerInstance->Users->clientlist->size() == 0) { // If there are no users, WHO THE HELL DID THE /MAP?!?!?! percent = 0; } else { percent = Current->UserCount * 100.0 / ServerInstance->Users->clientlist->size(); } const std::string operdata = user->IsOper() ? MapOperInfo(Current) : ""; char* myname = names + 100 * line; char* mystat = stats + 50 * line; memset(myname, ' ', depth); int w = depth; std::string servername = Current->GetName(); if (user->IsOper()) { w += snprintf(myname + depth, 99 - depth, "%s (%s)", servername.c_str(), Current->GetID().c_str()); } else { w += snprintf(myname + depth, 99 - depth, "%s", servername.c_str()); } memset(myname + w, ' ', 100 - w); if (w > maxnamew) maxnamew = w; snprintf(mystat, 49, "%5d [%5.2f%%]%s", Current->UserCount, percent, operdata.c_str()); line++; if (user->IsOper() || !Utils->FlatLinks) depth = depth + 2; for (unsigned int q = 0; q < Current->ChildCount(); q++) { TreeServer* child = Current->GetChild(q); if (!user->IsOper()) { if (child->Hidden) continue; if ((Utils->HideULines) && (ServerInstance->ULine(child->GetName()))) continue; } ShowMap(child, user, depth, line, names, maxnamew, stats); } }
CullResult TreeServer::cull() { // Recursively cull all servers that are under us in the tree for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i) { TreeServer* server = *i; server->cull(); } if (!IsRoot()) ServerUser->cull(); return classbase::cull(); }
/* * Some server somewhere in the network introducing another server. * -- w */ bool TreeSocket::RemoteServer(const std::string &prefix, parameterlist ¶ms) { if (params.size() < 5) { SendError("Protocol error - Not enough parameters for SERVER command"); return false; } std::string servername = params[0]; // password is not used for a remote server // hopcount is not used (ever) std::string sid = params[3]; std::string description = params[4]; TreeServer* ParentOfThis = Utils->FindServer(prefix); if (!ParentOfThis) { this->SendError("Protocol error - Introduced remote server from unknown server "+prefix); return false; } if (!ServerInstance->IsSID(sid)) { this->SendError("Invalid format server ID: "+sid+"!"); return false; } TreeServer* CheckDupe = Utils->FindServer(servername); if (CheckDupe) { this->SendError("Server "+servername+" already exists!"); ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+CheckDupe->GetName()+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, already exists. Closing link with " + ParentOfThis->GetName()); return false; } CheckDupe = Utils->FindServer(sid); if (CheckDupe) { this->SendError("Server ID "+sid+" already exists! You may want to specify the server ID for the server manually with <server:id> so they do not conflict."); ServerInstance->SNO->WriteToSnoMask('L', "Server \2"+servername+"\2 being introduced from \2" + ParentOfThis->GetName() + "\2 denied, server ID already exists on the network. Closing link with " + ParentOfThis->GetName()); return false; } Link* lnk = Utils->FindLink(servername); TreeServer *Node = new TreeServer(Utils, servername, description, sid, ParentOfThis,NULL, lnk ? lnk->Hidden : false); ParentOfThis->AddChild(Node); params[4] = ":" + params[4]; Utils->DoOneToAllButSender(prefix,"SERVER",params,prefix); ServerInstance->SNO->WriteToSnoMask('L', "Server \002"+ParentOfThis->GetName()+"\002 introduced server \002"+servername+"\002 ("+description+")"); return true; }
void TreeServer::FinishBurstInternal() { // Check is needed because 1202 protocol servers don't send the bursting state of a server, so servers // introduced during a netburst may later send ENDBURST which would normally decrease this counter if (behind_bursting > 0) behind_bursting--; ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "FinishBurstInternal() %s behind_bursting %u", GetName().c_str(), behind_bursting); for (ChildServers::const_iterator i = Children.begin(); i != Children.end(); ++i) { TreeServer* child = *i; child->FinishBurstInternal(); } }
CmdResult CommandAddLine::Handle(User* usr, std::vector<std::string>& params) { XLineFactory* xlf = ServerInstance->XLines->GetFactory(params[0]); const std::string& setter = usr->nick; if (!xlf) { ServerInstance->SNO->WriteToSnoMask('d',"%s sent me an unknown ADDLINE type (%s).",setter.c_str(),params[0].c_str()); return CMD_FAILURE; } XLine* xl = NULL; try { xl = xlf->Generate(ServerInstance->Time(), ConvToInt(params[4]), params[2], params[5], params[1]); } catch (ModuleException &e) { ServerInstance->SNO->WriteToSnoMask('d',"Unable to ADDLINE type %s from %s: %s", params[0].c_str(), setter.c_str(), e.GetReason().c_str()); return CMD_FAILURE; } xl->SetCreateTime(ConvToInt(params[3])); if (ServerInstance->XLines->AddLine(xl, NULL)) { if (xl->duration) { std::string timestr = InspIRCd::TimeString(xl->expiry); ServerInstance->SNO->WriteToSnoMask('X',"%s added %s%s on %s to expire on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", params[1].c_str(), timestr.c_str(), params[5].c_str()); } else { ServerInstance->SNO->WriteToSnoMask('X',"%s added permanent %s%s on %s: %s",setter.c_str(),params[0].c_str(),params[0].length() == 1 ? "-line" : "", params[1].c_str(),params[5].c_str()); } TreeServer* remoteserver = TreeServer::Get(usr); if (!remoteserver->IsBursting()) { ServerInstance->XLines->ApplyLines(); } return CMD_SUCCESS; } else { delete xl; return CMD_FAILURE; } }
/** Removes child nodes of this node, and of that node, etc etc. * This is used during netsplits to automatically tidy up the * server tree. It is slow, we don't use it for much else. */ void TreeServer::Tidy() { while (1) { std::vector<TreeServer*>::iterator a = Children.begin(); if (a == Children.end()) return; TreeServer* s = *a; s->Tidy(); s->cull(); Children.erase(a); delete s; } }
void SpanningTreeUtilities::DoOneToAllButSender(const std::string& prefix, const std::string& command, const parameterlist& params, TreeServer* omitroute) { std::string FullLine = ConstructLine(prefix, command, params); const TreeServer::ChildServers& children = TreeRoot->GetChildren(); for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { TreeServer* Route = *i; // Send the line if the route isn't the path to the one to be omitted if (Route != omitroute) { Route->GetSocket()->WriteLine(FullLine); } } }
void SpanningTreeUtilities::DoOneToAllButSender(const CmdBuilder& params, TreeServer* omitroute) { const std::string& FullLine = params.str(); const TreeServer::ChildServers& children = TreeRoot->GetChildren(); for (TreeServer::ChildServers::const_iterator i = children.begin(); i != children.end(); ++i) { TreeServer* Route = *i; // Send the line if the route isn't the path to the one to be omitted if (Route != omitroute) { Route->GetSocket()->WriteLine(FullLine); } } }
void SpanningTreeProtocolInterface::GetServerList(ServerList& sl) { for (server_hash::iterator i = Utils->serverlist.begin(); i != Utils->serverlist.end(); i++) { ServerInfo ps; ps.servername = i->second->GetName(); TreeServer* s = i->second->GetParent(); ps.parentname = s ? s->GetName() : ""; ps.usercount = i->second->UserCount; ps.opercount = i->second->OperCount; ps.gecos = i->second->GetDesc(); ps.latencyms = i->second->rtt; sl.push_back(ps); } }
/** send all users and their oper state/modes */ void TreeSocket::SendUsers() { char data[MAXBUF]; std::string dataline; for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++) { if (u->second->registered == REG_ALL) { TreeServer* theirserver = Utils->FindServer(u->second->server); if (theirserver) { snprintf(data,MAXBUF,":%s UID %s %lu %s %s %s %s %s %lu +%s :%s", theirserver->GetID().c_str(), /* Prefix: SID */ u->second->uuid.c_str(), /* 0: UUID */ (unsigned long)u->second->age, /* 1: TS */ u->second->nick.c_str(), /* 2: Nick */ u->second->host.c_str(), /* 3: Displayed Host */ u->second->dhost.c_str(), /* 4: Real host */ u->second->ident.c_str(), /* 5: Ident */ u->second->GetIPString().c_str(), /* 6: IP string */ (unsigned long)u->second->signon, /* 7: Signon time for WHOWAS */ u->second->FormatModes(true), /* 8...n: Modes and params */ u->second->fullname.c_str()); /* size-1: GECOS */ this->WriteLine(data); if (u->second->IsOper()) { snprintf(data,MAXBUF,":%s OPERTYPE %s", u->second->uuid.c_str(), u->second->oper->name.c_str()); this->WriteLine(data); } if (u->second->IsAway()) { snprintf(data,MAXBUF,":%s AWAY %ld :%s", u->second->uuid.c_str(), (long)u->second->awaytime, u->second->awaymsg.c_str()); this->WriteLine(data); } } for(Extensible::ExtensibleStore::const_iterator i = u->second->GetExtList().begin(); i != u->second->GetExtList().end(); i++) { ExtensionItem* item = i->first; std::string value = item->serialize(FORMAT_NETWORK, u->second, i->second); if (!value.empty()) Utils->Creator->ProtoSendMetaData(this, u->second, item->name, value); } FOREACH_MOD(I_OnSyncUser,OnSyncUser(u->second,Utils->Creator,this)); } } }
ModResult ModuleSpanningTree::HandleConnect(const CommandBase::Params& parameters, User* user) { for (std::vector<reference<Link> >::iterator i = Utils->LinkBlocks.begin(); i < Utils->LinkBlocks.end(); i++) { Link* x = *i; if (InspIRCd::Match(x->Name, parameters[0], ascii_case_insensitive_map)) { if (InspIRCd::Match(ServerInstance->Config->ServerName, x->Name, ascii_case_insensitive_map)) { user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: Server \002%s\002 is ME, not connecting.", x->Name.c_str())); return MOD_RES_DENY; } TreeServer* CheckDupe = Utils->FindServer(x->Name); if (!CheckDupe) { user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: Connecting to server: \002%s\002 (%s:%d)", x->Name.c_str(), (x->HiddenFromStats ? "<hidden>" : x->IPAddr.c_str()), x->Port)); ConnectServer(x); return MOD_RES_DENY; } else { user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: Server \002%s\002 already exists on the network and is connected via \002%s\002", x->Name.c_str(), CheckDupe->GetParent()->GetName().c_str())); return MOD_RES_DENY; } } } user->WriteRemoteNotice(InspIRCd::Format("*** CONNECT: No server matching \002%s\002 could be found in the config file.", parameters[0].c_str())); return MOD_RES_DENY; }