servers.cpp

Go to the documentation of this file.
00001 /* Routines to maintain a list of connected servers
00002  *
00003  * (C) 2003-2013 Anope Team
00004  * Contact us at team@anope.org
00005  *
00006  * Please read COPYING and README for further details.
00007  *
00008  * Based on the original code of Epona by Lara.
00009  * Based on the original code of Services by Andy Church.
00010  *
00011  */
00012 
00013 #include "services.h"
00014 #include "modules.h"
00015 #include "xline.h"
00016 #include "servers.h"
00017 #include "bots.h"
00018 #include "regchannel.h"
00019 #include "protocol.h"
00020 #include "config.h"
00021 #include "channels.h"
00022 
00023 /* Anope */
00024 Server *Me = NULL;
00025 
00026 std::set<Anope::string> Servers::Capab;
00027 
00028 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)
00029 {
00030         syncing = true;
00031         juped = jupe;
00032 
00033         Log(this, "connect") << "uplinked to " << (this->uplink ? this->uplink->GetName() : "no uplink") << " connected to the network";
00034 
00035         /* Add this server to our uplinks leaf list */
00036         if (this->uplink)
00037         {
00038                 this->uplink->AddLink(this);
00039 
00040                 /* Check to be sure this isn't a juped server */
00041                 if (Me == this->uplink && !juped)
00042                 {
00043                         /* Now do mode related stuff as we know what modes exist .. */
00044                         for (botinfo_map::iterator it = BotListByNick->begin(), it_end = BotListByNick->end(); it != it_end; ++it)
00045                         {
00046                                 BotInfo *bi = it->second;
00047                                 Anope::string modes = !bi->botmodes.empty() ? ("+" + bi->botmodes) : IRCD->DefaultPseudoclientModes;
00048 
00049                                 bi->SetModesInternal(modes.c_str());
00050                                 for (unsigned i = 0; i < bi->botchannels.size(); ++i)
00051                                 {
00052                                         size_t h = bi->botchannels[i].find('#');
00053                                         if (h == Anope::string::npos)
00054                                                 continue;
00055                                         Anope::string chname = bi->botchannels[i].substr(h);
00056                                         Channel *c = Channel::Find(chname);
00057                                         if (c && c->FindUser(bi))
00058                                         {
00059                                                 Anope::string want_modes = bi->botchannels[i].substr(0, h);
00060                                                 for (unsigned j = 0; j < want_modes.length(); ++j)
00061                                                 {
00062                                                         ChannelMode *cm = ModeManager::FindChannelModeByChar(want_modes[j]);
00063                                                         if (cm == NULL)
00064                                                                 cm = ModeManager::FindChannelModeByChar(ModeManager::GetStatusChar(want_modes[j]));
00065                                                         if (cm && cm->type == MODE_STATUS)
00066                                                         {
00067                                                                 MessageSource ms = bi;
00068                                                                 c->SetModeInternal(ms, cm, bi->nick);
00069                                                         }
00070                                                 }
00071                                         }
00072                                 }
00073                         }
00074 
00075                         IRCD->SendBOB();
00076         
00077                         for (unsigned i = 0; i < Me->GetLinks().size(); ++i)
00078                         {
00079                                 Server *s = Me->GetLinks()[i];
00080 
00081                                 if (s->juped)
00082                                         IRCD->SendServer(s);
00083                         }
00084 
00085                         /* We make the bots go online */
00086                         for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end(); ++it)
00087                         {
00088                                 User *u = it->second;
00089 
00090                                 BotInfo *bi = BotInfo::Find(u->nick);
00091                                 if (bi)
00092                                 {
00093                                         XLine x(bi->nick, "Reserved for services");
00094                                         IRCD->SendSQLine(NULL, &x);
00095                                 }
00096 
00097                                 IRCD->SendClientIntroduction(u);
00098                                 if (bi)
00099                                         bi->introduced = true;
00100                         }
00101 
00102                         for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
00103                         {
00104                                 Channel *c = it->second;
00105                                 if (c->users.empty())
00106                                         IRCD->SendChannel(c);
00107                                 else
00108                                         for (User::ChanUserList::const_iterator cit = c->users.begin(), cit_end = c->users.end(); cit != cit_end; ++cit)
00109                                                 IRCD->SendJoin((*cit)->user, c, &(*cit)->status);
00110                         }
00111                 }
00112         }
00113 
00114         FOREACH_MOD(I_OnNewServer, OnNewServer(this));
00115 }
00116 
00117 Server::~Server()
00118 {
00119         Log(this, "quit") << "quit from " << (this->uplink ? this->uplink->GetName() : "no uplink") << " for " << this->quit_reason;
00120 
00121         if (Servers::Capab.count("NOQUIT") > 0 || Servers::Capab.count("QS") > 0)
00122         {
00123                 for (user_map::const_iterator it = UserListByNick.begin(); it != UserListByNick.end();)
00124                 {
00125                         User *u = it->second;
00126                         ++it;
00127 
00128                         if (u->server == this)
00129                         {
00130                                 NickAlias *na = NickAlias::Find(u->nick);
00131                                 if (na && !na->nc->HasExt("SUSPENDED") && (u->IsRecognized() || u->IsIdentified()))
00132                                 {
00133                                         na->last_seen = Anope::CurTime;
00134                                         if (!Config->NSHideNetSplitQuit)
00135                                                 na->last_quit = this->quit_reason;
00136                                 }
00137 
00138                                 u->Quit(this->quit_reason);
00139                                 u->server = NULL;
00140                         }
00141                 }
00142 
00143                 Log(LOG_DEBUG) << "Finished removing all users for " << this->GetName();
00144         }
00145 
00146         if (this->uplink)
00147                 this->uplink->DelLink(this);
00148 
00149         for (unsigned i = this->links.size(); i > 0; --i)
00150                 this->links[i - 1]->Delete(this->quit_reason);
00151 }
00152 
00153 void Server::Delete(const Anope::string &reason)
00154 {
00155         this->quit_reason = reason;
00156         FOREACH_MOD(I_OnServerQuit, OnServerQuit(this));
00157         delete this;
00158 }
00159 
00160 const Anope::string &Server::GetName() const
00161 {
00162         return this->name;
00163 }
00164 
00165 unsigned Server::GetHops() const
00166 {
00167         return this->hops;
00168 }
00169 
00170 void Server::SetDescription(const Anope::string &desc)
00171 {
00172         this->description = desc;
00173 }
00174 
00175 const Anope::string &Server::GetDescription() const
00176 {
00177         return this->description;
00178 }
00179 
00180 void Server::SetSID(const Anope::string &nsid)
00181 {
00182         this->sid = nsid;
00183 }
00184 
00185 const Anope::string &Server::GetSID() const
00186 {
00187         if (!this->sid.empty() && IRCD->RequiresID)
00188                 return this->sid;
00189         else
00190                 return this->name;
00191 }
00192 
00193 const std::vector<Server *> &Server::GetLinks() const
00194 {
00195         return this->links;
00196 }
00197 
00198 Server *Server::GetUplink()
00199 {
00200         return this->uplink;
00201 }
00202 
00203 void Server::AddLink(Server *s)
00204 {
00205         this->links.push_back(s);
00206 
00207         Log(this, "connect") << "introduced " << s->GetName();
00208 }
00209 
00210 void Server::DelLink(Server *s)
00211 {
00212         if (this->links.empty())
00213                 throw CoreException("Server::DelLink called on " + this->GetName() + " for " + s->GetName() + " but we have no links?");
00214 
00215         for (unsigned i = 0, j = this->links.size(); i < j; ++i)
00216         {
00217                 if (this->links[i] == s)
00218                 {
00219                         this->links.erase(this->links.begin() + i);
00220                         break;
00221                 }
00222         }
00223 
00224         Log(this, "quit") << "quit " << s->GetName();
00225 }
00226 
00227 void Server::Sync(bool sync_links)
00228 {
00229         if (this->IsSynced())
00230                 return;
00231 
00232         syncing = false;
00233 
00234         Log(this, "sync") << "is done syncing";
00235 
00236         FOREACH_MOD(I_OnServerSync, OnServerSync(this));
00237 
00238         if (sync_links && !this->links.empty())
00239         {
00240                 for (unsigned i = 0, j = this->links.size(); i < j; ++i)
00241                         this->links[i]->Sync(true);
00242         }
00243 
00244         if (this->GetUplink() && this->GetUplink() == Me)
00245         {
00246                 for (registered_channel_map::iterator it = RegisteredChannelList->begin(), it_end = RegisteredChannelList->end(); it != it_end; ++it)
00247                 {
00248                         ChannelInfo *ci = it->second;
00249                         if (ci->HasExt("PERSIST"))
00250                         {
00251                                 bool created = false;
00252                                 if (!ci->c)
00253                                 {
00254                                         ci->c = new Channel(ci->name, ci->time_registered);
00255                                         created = true;
00256                                 }
00257                                 if (ModeManager::FindChannelModeByName("PERM") != NULL)
00258                                 {
00259                                         ci->c->SetMode(NULL, "PERM");
00260                                         if (created)
00261                                                 IRCD->SendChannel(ci->c);
00262                                 }
00263                                 else
00264                                 {
00265                                         if (!ci->bi)
00266                                                 ci->WhoSends()->Assign(NULL, ci);
00267                                         if (ci->c->FindUser(ci->bi) == NULL)
00268                                                 ci->bi->Join(ci->c);
00269                                 }
00270                         }
00271                 }
00272 
00273                 FOREACH_MOD(I_OnPreUplinkSync, OnPreUplinkSync(this));
00274 
00275                 IRCD->SendEOB();
00276                 Me->Sync(false);
00277 
00278                 FOREACH_MOD(I_OnUplinkSync, OnUplinkSync(this));
00279 
00280                 for (channel_map::const_iterator it = ChannelList.begin(), it_end = ChannelList.end(); it != it_end; ++it)
00281                 {
00282                         Channel *c = it->second;
00283                         c->Sync();
00284                 }
00285 
00286                 if (!Anope::NoFork && Anope::AtTerm())
00287                 {
00288                         Log(LOG_TERMINAL) << "Successfully linked, launching into background...";
00289                         Anope::Fork();
00290                 }
00291         }
00292 }
00293 
00294 bool Server::IsSynced() const
00295 {
00296         return !syncing;
00297 }
00298 
00299 void Server::Unsync()
00300 {
00301         syncing = true;
00302 }
00303 
00304 bool Server::IsULined() const
00305 {
00306         if (this == Me)
00307                 return true;
00308 
00309         for (std::list<Anope::string>::const_iterator it = Config->Ulines.begin(), it_end = Config->Ulines.end(); it != it_end; ++it)
00310                 if (it->equals_ci(this->GetName()))
00311                         return true;
00312         return false;
00313 }
00314 
00315 bool Server::IsJuped() const
00316 {
00317         return juped;
00318 }
00319 
00320 void Server::Notice(const BotInfo *source, const Anope::string &message)
00321 {
00322         if (Config->NSDefFlags.count("MSG"))
00323                 IRCD->SendGlobalPrivmsg(source, this, message);
00324         else
00325                 IRCD->SendGlobalNotice(source, this, message);
00326 }
00327 
00328 Server *Server::Find(const Anope::string &name, Server *s)
00329 {
00330         Log(LOG_DEBUG_2) << "Server::Find called for " << name;
00331 
00332         if (!s)
00333                 s = Me;
00334         if (s->GetName().equals_ci(name) || s->GetSID().equals_cs(name))
00335                 return s;
00336 
00337         if (!s->GetLinks().empty())
00338         {
00339                 for (unsigned i = 0, j = s->GetLinks().size(); i < j; ++i)
00340                 {
00341                         Server *serv = s->GetLinks()[i];
00342 
00343                         if (serv->GetName().equals_ci(name) || serv->GetSID().equals_cs(name))
00344                                 return serv;
00345                         Log(LOG_DEBUG_2) << "Server::Find checking " << serv->GetName() << " server tree for " << name;
00346                         Server *server = Server::Find(name, serv);
00347                         if (server)
00348                                 return server;
00349                 }
00350         }
00351 
00352         return NULL;
00353 }
00354 
00355 /*************************************************************************/
00356 
00357 static inline char& nextID(char &c)
00358 {
00359         if (c == 'Z')
00360                 c = '0';
00361         else if (c != '9')
00362                 ++c;
00363         else
00364                 c = 'A';
00365         return c;
00366 }
00367 
00368 const Anope::string Servers::TS6_UID_Retrieve()
00369 {
00370         if (!IRCD || !IRCD->RequiresID)
00371                 return "";
00372 
00373         static Anope::string current_uid = "AAAAAA";
00374 
00375         while (User::Find(Config->Numeric + current_uid) != NULL)
00376         {
00377                 int current_len = current_uid.length() - 1;
00378                 while (current_len >= 0 && nextID(current_uid[current_len--]) == 'A');
00379         }
00380 
00381         return Config->Numeric + current_uid;
00382 }
00383 
00384 const Anope::string Servers::TS6_SID_Retrieve()
00385 {
00386         if (!IRCD || !IRCD->RequiresID)
00387                 return "";
00388 
00389         static Anope::string current_sid;
00390         if (current_sid.empty())
00391         {
00392                 current_sid = Config->Numeric;
00393                 if (current_sid.empty())
00394                         current_sid = "00A";
00395         }
00396 
00397         while (Server::Find(current_sid) != NULL)
00398         {
00399                 int current_len = current_sid.length() - 1;
00400                 while (current_len >= 0 && nextID(current_sid[current_len--]) == 'A');
00401         }
00402 
00403         return current_sid;
00404 }
00405 
00406 Server* Servers::GetUplink()
00407 {
00408         for (unsigned i = 0; Me && i < Me->GetLinks().size(); ++i)
00409                 if (!Me->GetLinks()[i]->IsJuped())
00410                         return Me->GetLinks()[i];
00411         return NULL;
00412 }
00413