anope

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

servers.cpp (8042B)

      1 /* Routines to maintain a list of connected servers
      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 "services.h"
     13 #include "modules.h"
     14 #include "xline.h"
     15 #include "servers.h"
     16 #include "bots.h"
     17 #include "regchannel.h"
     18 #include "protocol.h"
     19 #include "config.h"
     20 #include "channels.h"
     21 
     22 /* Anope */
     23 Server *Me = NULL;
     24 
     25 Anope::map<Server *> Servers::ByName;
     26 Anope::map<Server *> Servers::ByID;
     27 
     28 std::set<Anope::string> Servers::Capab;
     29 
     30 Server::Server(Server *up, const Anope::string &sname, unsigned shops, const Anope::string &desc, const Anope::string &ssid, bool jupe) : name(sname), hops(shops), description(desc), sid(ssid), uplink(up), users(0)
     31 {
     32 	syncing = true;
     33 	juped = jupe;
     34 	quitting = false;
     35 
     36 	Servers::ByName[sname] = this;
     37 	if (!ssid.empty())
     38 		Servers::ByID[ssid] = this;
     39 
     40 	Log(this, "connect") << "has connected to the network (uplinked to " << (this->uplink ? this->uplink->GetName() : "no uplink") << ")";
     41 
     42 	/* Add this server to our uplinks leaf list */
     43 	if (this->uplink)
     44 	{
     45 		this->uplink->AddLink(this);
     46 
     47 		/* Check to be sure this isn't a juped server */
     48 		if (Me == this->uplink && !juped)
     49 		{
     50 			/* Now do mode related stuff as we know what modes exist .. */
     51 			for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
     52 			{
     53 				BotInfo *bi = it->second;
     54 				Anope::string modes = !bi->botmodes.empty() ? ("+" + bi->botmodes) : IRCD->DefaultPseudoclientModes;
     55 
     56 				bi->SetModesInternal(bi, modes.c_str());
     57 				for (unsigned i = 0; i < bi->botchannels.size(); ++i)
     58 				{
     59 					size_t h = bi->botchannels[i].find('#');
     60 					if (h == Anope::string::npos)
     61 						continue;
     62 					Anope::string chname = bi->botchannels[i].substr(h);
     63 					Channel *c = Channel::Find(chname);
     64 					if (c && c->FindUser(bi))
     65 					{
     66 						Anope::string want_modes = bi->botchannels[i].substr(0, h);
     67 						for (unsigned j = 0; j < want_modes.length(); ++j)
     68 						{
     69 							ChannelMode *cm = ModeManager::FindChannelModeByChar(want_modes[j]);
     70 							if (cm == NULL)
     71 								cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_modes[j]));
     72 							if (cm && cm->type == MODE_STATUS)
     73 							{
     74 								MessageSource ms = bi;
     75 								c->SetModeInternal(ms, cm, bi->nick);
     76 							}
     77 						}
     78 					}
     79 				}
     80 			}
     81 
     82 			IRCD->SendBOB();
     83 
     84 			for (unsigned i = 0; i < Me->GetLinks().size(); ++i)
     85 			{
     86 				Server *s = Me->GetLinks()[i];
     87 
     88 				if (s->juped)
     89 					IRCD->SendServer(s);
     90 			}
     91 
     92 			/* We make the bots go online */
     93 			for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
     94 			{
     95 				User *u = it->second;
     96 
     97 				BotInfo *bi = BotInfo::Find(u->GetUID());
     98 				if (bi)
     99 				{
    100 					XLine x(bi->nick, "Reserved for services");
    101 					IRCD->SendSQLine(NULL, &x);
    102 				}
    103 
    104 				IRCD->SendClientIntroduction(u);
    105 				if (bi)
    106 					bi->introduced = true;
    107 			}
    108 
    109 			for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
    110 			{
    111 				Channel *c = it->second;
    112 
    113 				if (c->users.empty())
    114 					IRCD->SendChannel(c);
    115 				else
    116 					for (Channel::ChanUserList::const_iterator cit = c->users.begin(), cit_end = c->users.end(); cit != cit_end; ++cit)
    117 						IRCD->SendJoin(cit->second->user, c, &cit->second->status);
    118 
    119 				for (Channel::ModeList::const_iterator it2 = c->GetModes().begin(); it2 != c->GetModes().end(); ++it2)
    120 				{
    121 					ChannelMode *cm = ModeManager::FindChannelModeByName(it2->first);
    122 					if (!cm || cm->type != MODE_LIST)
    123 						continue;
    124 					ModeManager::StackerAdd(c->ci->WhoSends(), c, cm, true, it2->second);
    125 				}
    126 
    127 				if (!c->topic.empty() && !c->topic_setter.empty())
    128 					IRCD->SendTopic(c->ci->WhoSends(), c);
    129 
    130 				c->syncing = true;
    131 			}
    132 		}
    133 	}
    134 
    135 	FOREACH_MOD(OnNewServer, (this));
    136 }
    137 
    138 Server::~Server()
    139 {
    140 	Log(this, "quit") << "quit from " << (this->uplink ? this->uplink->GetName() : "no uplink") << " for " << this->quit_reason;
    141 
    142 	for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
    143 	{
    144 		User *u = it->second;
    145 
    146 		if (u->server == this)
    147 		{
    148 			u->Quit(this->quit_reason);
    149 			u->server = NULL;
    150 		}
    151 	}
    152 
    153 	Log(LOG_DEBUG) << "Finished removing all users for " << this->GetName();
    154 
    155 	if (this->uplink)
    156 		this->uplink->DelLink(this);
    157 
    158 	for (unsigned i = this->links.size(); i > 0; --i)
    159 		this->links[i - 1]->Delete(this->quit_reason);
    160 
    161 	Servers::ByName.erase(this->name);
    162 	if (!this->sid.empty())
    163 		Servers::ByID.erase(this->sid);
    164 }
    165 
    166 void Server::Delete(const Anope::string &reason)
    167 {
    168 	this->quit_reason = reason;
    169 	this->quitting = true;
    170 	FOREACH_MOD(OnServerQuit, (this));
    171 	delete this;
    172 }
    173 
    174 const Anope::string &Server::GetName() const
    175 {
    176 	return this->name;
    177 }
    178 
    179 unsigned Server::GetHops() const
    180 {
    181 	return this->hops;
    182 }
    183 
    184 void Server::SetDescription(const Anope::string &desc)
    185 {
    186 	this->description = desc;
    187 }
    188 
    189 const Anope::string &Server::GetDescription() const
    190 {
    191 	return this->description;
    192 }
    193 
    194 void Server::SetSID(const Anope::string &nsid)
    195 {
    196 	if (!this->sid.empty())
    197 		throw CoreException("Server already has an id?");
    198 	this->sid = nsid;
    199 	Servers::ByID[nsid] = this;
    200 }
    201 
    202 const Anope::string &Server::GetSID() const
    203 {
    204 	if (!this->sid.empty() && IRCD->RequiresID)
    205 		return this->sid;
    206 	else
    207 		return this->name;
    208 }
    209 
    210 const Anope::string &Server::GetQuitReason() const
    211 {
    212 	return this->quit_reason;
    213 }
    214 
    215 const std::vector<Server *> &Server::GetLinks() const
    216 {
    217 	return this->links;
    218 }
    219 
    220 Server *Server::GetUplink()
    221 {
    222 	return this->uplink;
    223 }
    224 
    225 void Server::AddLink(Server *s)
    226 {
    227 	this->links.push_back(s);
    228 
    229 	Log(this, "connect") << "introduced " << s->GetName();
    230 }
    231 
    232 void Server::DelLink(Server *s)
    233 {
    234 	if (this->links.empty())
    235 		throw CoreException("Server::DelLink called on " + this->GetName() + " for " + s->GetName() + " but we have no links?");
    236 
    237 	for (unsigned i = 0, j = this->links.size(); i < j; ++i)
    238 	{
    239 		if (this->links[i] == s)
    240 		{
    241 			this->links.erase(this->links.begin() + i);
    242 			break;
    243 		}
    244 	}
    245 
    246 	Log(this, "quit") << "quit " << s->GetName();
    247 }
    248 
    249 void Server::Sync(bool sync_links)
    250 {
    251 	if (this->IsSynced())
    252 		return;
    253 
    254 	syncing = false;
    255 
    256 	Log(this, "sync") << "is done syncing";
    257 
    258 	FOREACH_MOD(OnServerSync, (this));
    259 
    260 	if (sync_links && !this->links.empty())
    261 	{
    262 		for (unsigned i = 0, j = this->links.size(); i < j; ++i)
    263 			this->links[i]->Sync(true);
    264 	}
    265 
    266 	bool me = this->GetUplink() && this->GetUplink() == Me;
    267 
    268 	if (me)
    269 	{
    270 		FOREACH_MOD(OnPreUplinkSync, (this));
    271 	}
    272 
    273 	for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end;)
    274 	{
    275 		Channel *c = it->second;
    276 		++it;
    277 
    278 		if (c->syncing)
    279 			c->Sync();
    280 	}
    281 
    282 	if (me)
    283 	{
    284 		IRCD->SendEOB();
    285 		Me->Sync(false);
    286 
    287 		FOREACH_MOD(OnUplinkSync, (this));
    288 
    289 		if (!Anope::NoFork)
    290 		{
    291 			Log(LOG_TERMINAL) << "Successfully linked, launching into background...";
    292 			Anope::Fork();
    293 		}
    294 	}
    295 }
    296 
    297 bool Server::IsSynced() const
    298 {
    299 	return !syncing;
    300 }
    301 
    302 void Server::Unsync()
    303 {
    304 	syncing = true;
    305 }
    306 
    307 bool Server::IsULined() const
    308 {
    309 	if (this == Me)
    310 		return true;
    311 
    312 	for (unsigned i = 0; i < Config->Ulines.size(); ++i)
    313 		if (Config->Ulines[i].equals_ci(this->GetName()))
    314 			return true;
    315 	return false;
    316 }
    317 
    318 bool Server::IsJuped() const
    319 {
    320 	return juped;
    321 }
    322 
    323 bool Server::IsQuitting() const
    324 {
    325 	return quitting;
    326 }
    327 
    328 void Server::Notice(BotInfo *source, const Anope::string &message)
    329 {
    330 	if (Config->UsePrivmsg && Config->DefPrivmsg)
    331 		IRCD->SendGlobalPrivmsg(source, this, message);
    332 	else
    333 		IRCD->SendGlobalNotice(source, this, message);
    334 }
    335 
    336 Server *Server::Find(const Anope::string &name, bool name_only)
    337 {
    338 	Anope::map<Server *>::iterator it;
    339 
    340 	if (!name_only)
    341 	{
    342 		it = Servers::ByID.find(name);
    343 		if (it != Servers::ByID.end())
    344 			return it->second;
    345 	}
    346 
    347 	it = Servers::ByName.find(name);
    348 	if (it != Servers::ByName.end())
    349 		return it->second;
    350 
    351 	return NULL;
    352 }
    353 
    354 Server* Servers::GetUplink()
    355 {
    356 	for (unsigned i = 0; Me && i < Me->GetLinks().size(); ++i)
    357 		if (!Me->GetLinks()[i]->IsJuped())
    358 			return Me->GetLinks()[i];
    359 	return NULL;
    360 }