2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2019 Matt Schatz <genius3000@g3k.solutions>
5 * Copyright (C) 2013-2016 Attila Molnar <attilamolnar@hush.com>
6 * Copyright (C) 2013-2014, 2016-2019 Sadie Powell <sadie@witchery.services>
7 * Copyright (C) 2013 Daniel Vassdal <shutter@canternet.org>
8 * Copyright (C) 2012 Robby <robby@chatbelgie.be>
9 * Copyright (C) 2012 Justin Crawford <Justasic@Gmail.com>
10 * Copyright (C) 2012 DjSlash <djslash@djslash.org>
11 * Copyright (C) 2012 ChrisTX <xpipe@hotmail.de>
12 * Copyright (C) 2009-2011 Daniel De Graaf <danieldg@inspircd.org>
13 * Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
14 * Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
15 * Copyright (C) 2007-2010 Robin Burchell <robin+git@viroteck.net>
16 * Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
17 * Copyright (C) 2006-2008 Craig Edwards <brain@inspircd.org>
19 * This file is part of InspIRCd. InspIRCd is free software: you can
20 * redistribute it and/or modify it under the terms of the GNU General Public
21 * License as published by the Free Software Foundation, version 2.
23 * This program is distributed in the hope that it will be useful, but WITHOUT
24 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
25 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36 #include "exitcodes.h"
37 #include "configparser.h"
40 ServerLimits::ServerLimits(ConfigTag* tag)
41 : NickMax(tag->getUInt("maxnick", 30))
42 , ChanMax(tag->getUInt("maxchan", 64))
43 , MaxModes(tag->getUInt("maxmodes", 20))
44 , IdentMax(tag->getUInt("maxident", 10))
45 , MaxQuit(tag->getUInt("maxquit", 255))
46 , MaxTopic(tag->getUInt("maxtopic", 307))
47 , MaxKick(tag->getUInt("maxkick", 255))
48 , MaxReal(tag->getUInt("maxreal", tag->getUInt("maxgecos", 128)))
49 , MaxAway(tag->getUInt("maxaway", 200))
50 , MaxLine(tag->getUInt("maxline", 512))
51 , MaxHost(tag->getUInt("maxhost", 64))
55 ServerConfig::ServerPaths::ServerPaths(ConfigTag* tag)
56 : Config(tag->getString("configdir", INSPIRCD_CONFIG_PATH))
57 , Data(tag->getString("datadir", INSPIRCD_DATA_PATH))
58 , Log(tag->getString("logdir", INSPIRCD_LOG_PATH))
59 , Module(tag->getString("moduledir", INSPIRCD_MODULE_PATH))
63 static ConfigTag* CreateEmptyTag()
66 return ConfigTag::create("empty", "<auto>", 0, items);
69 ServerConfig::ServerConfig()
70 : EmptyTag(CreateEmptyTag())
74 , NoSnoticeStack(false)
78 ServerConfig::~ServerConfig()
83 static void ReadXLine(ServerConfig* conf, const std::string& tag, const std::string& key, XLineFactory* make)
85 insp::flat_set<std::string> configlines;
87 ConfigTagList tags = conf->ConfTags(tag);
88 for(ConfigIter i = tags.first; i != tags.second; ++i)
90 ConfigTag* ctag = i->second;
92 const std::string mask = ctag->getString(key);
94 throw CoreException("<" + tag + ":" + key + "> missing at " + ctag->getTagLocation());
96 const std::string reason = ctag->getString("reason");
98 throw CoreException("<" + tag + ":reason> missing at " + ctag->getTagLocation());
100 XLine* xl = make->Generate(ServerInstance->Time(), 0, ServerInstance->Config->ServerName, reason, mask);
101 xl->from_config = true;
102 configlines.insert(xl->Displayable());
103 if (!ServerInstance->XLines->AddLine(xl, NULL))
107 ServerInstance->XLines->ExpireRemovedConfigLines(make->GetType(), configlines);
110 typedef std::map<std::string, ConfigTag*> LocalIndex;
111 void ServerConfig::CrossCheckOperClassType()
113 LocalIndex operclass;
114 ConfigTagList tags = ConfTags("class");
115 for(ConfigIter i = tags.first; i != tags.second; ++i)
117 ConfigTag* tag = i->second;
118 std::string name = tag->getString("name");
120 throw CoreException("<class:name> missing from tag at " + tag->getTagLocation());
121 if (operclass.find(name) != operclass.end())
122 throw CoreException("Duplicate class block with name " + name + " at " + tag->getTagLocation());
123 operclass[name] = tag;
125 tags = ConfTags("type");
126 for(ConfigIter i = tags.first; i != tags.second; ++i)
128 ConfigTag* tag = i->second;
129 std::string name = tag->getString("name");
131 throw CoreException("<type:name> is missing from tag at " + tag->getTagLocation());
132 if (OperTypes.find(name) != OperTypes.end())
133 throw CoreException("Duplicate type block with name " + name + " at " + tag->getTagLocation());
135 OperInfo* ifo = new OperInfo(name);
136 OperTypes[name] = ifo;
137 ifo->type_block = tag;
139 std::string classname;
140 irc::spacesepstream str(tag->getString("classes"));
141 while (str.GetToken(classname))
143 LocalIndex::iterator cls = operclass.find(classname);
144 if (cls == operclass.end())
145 throw CoreException("Oper type " + name + " has missing class " + classname);
146 ifo->class_blocks.push_back(cls->second);
150 tags = ConfTags("oper");
151 for(ConfigIter i = tags.first; i != tags.second; ++i)
153 ConfigTag* tag = i->second;
155 std::string name = tag->getString("name");
157 throw CoreException("<oper:name> missing from tag at " + tag->getTagLocation());
159 std::string type = tag->getString("type");
160 OperIndex::iterator tblk = OperTypes.find(type);
161 if (tblk == OperTypes.end())
162 throw CoreException("Oper block " + name + " has missing type " + type);
163 if (oper_blocks.find(name) != oper_blocks.end())
164 throw CoreException("Duplicate oper block with name " + name + " at " + tag->getTagLocation());
166 OperInfo* ifo = new OperInfo(type);
167 ifo->oper_block = tag;
168 ifo->type_block = tblk->second->type_block;
169 ifo->class_blocks.assign(tblk->second->class_blocks.begin(), tblk->second->class_blocks.end());
170 oper_blocks[name] = ifo;
174 void ServerConfig::CrossCheckConnectBlocks(ServerConfig* current)
176 typedef std::map<std::string, ConnectClass*> ClassMap;
177 ClassMap oldBlocksByMask;
180 for(ClassVector::iterator i = current->Classes.begin(); i != current->Classes.end(); ++i)
182 ConnectClass* c = *i;
183 if (c->name.compare(0, 8, "unnamed-", 8))
185 oldBlocksByMask["n" + c->name] = c;
187 else if (c->type == CC_ALLOW || c->type == CC_DENY)
189 std::string typeMask = (c->type == CC_ALLOW) ? "a" : "d";
191 oldBlocksByMask[typeMask] = c;
196 size_t blk_count = config_data.count("connect");
199 // No connect blocks found; make a trivial default block
201 ConfigTag* tag = ConfigTag::create("connect", "<auto>", 0, items);
202 (*items)["allow"] = "*";
203 config_data.insert(std::make_pair("connect", tag));
207 Classes.resize(blk_count);
208 std::map<std::string, size_t> names;
210 bool try_again = true;
211 for(size_t tries = 0; try_again; tries++)
214 ConfigTagList tags = ConfTags("connect");
216 for(ConfigIter it = tags.first; it != tags.second; ++it, ++i)
218 ConfigTag* tag = it->second;
222 ConnectClass* parent = NULL;
223 std::string parentName = tag->getString("parent");
224 if (!parentName.empty())
226 std::map<std::string, size_t>::const_iterator parentIter = names.find(parentName);
227 if (parentIter == names.end())
230 // couldn't find parent this time. If it's the last time, we'll never find it.
231 if (tries >= blk_count)
232 throw CoreException("Could not find parent connect class \"" + parentName + "\" for connect block at " + tag->getTagLocation());
235 parent = Classes[parentIter->second];
238 std::string name = tag->getString("name");
239 std::string mask, typeMask;
242 if (tag->readString("allow", mask, false))
245 typeMask = 'a' + mask;
247 else if (tag->readString("deny", mask, false))
250 typeMask = 'd' + mask;
252 else if (!name.empty())
256 typeMask = 'n' + mask;
260 throw CoreException("Connect class must have allow, deny, or name specified at " + tag->getTagLocation());
265 name = "unnamed-" + ConvToStr(i);
269 typeMask = 'n' + name;
272 if (names.find(name) != names.end())
273 throw CoreException("Two connect classes with name \"" + name + "\" defined!");
276 ConnectClass* me = parent ?
277 new ConnectClass(tag, type, mask, *parent) :
278 new ConnectClass(tag, type, mask);
282 me->registration_timeout = tag->getDuration("timeout", me->registration_timeout);
283 me->pingtime = tag->getDuration("pingfreq", me->pingtime);
285 if (tag->readString("sendq", sendq))
287 // attempt to guess a good hard/soft sendq from a single value
288 unsigned long value = strtoul(sendq.c_str(), NULL, 10);
290 me->softsendqmax = value / 16;
292 me->softsendqmax = value;
293 me->hardsendqmax = value * 8;
295 me->softsendqmax = tag->getUInt("softsendq", me->softsendqmax);
296 me->hardsendqmax = tag->getUInt("hardsendq", me->hardsendqmax);
297 me->recvqmax = tag->getUInt("recvq", me->recvqmax);
298 me->penaltythreshold = tag->getUInt("threshold", me->penaltythreshold);
299 me->commandrate = tag->getUInt("commandrate", me->commandrate);
300 me->fakelag = tag->getBool("fakelag", me->fakelag);
301 me->maxlocal = tag->getUInt("localmax", me->maxlocal);
302 me->maxglobal = tag->getUInt("globalmax", me->maxglobal);
303 me->maxchans = tag->getUInt("maxchans", me->maxchans);
304 me->maxconnwarn = tag->getBool("maxconnwarn", me->maxconnwarn);
305 me->limit = tag->getUInt("limit", me->limit);
306 me->resolvehostnames = tag->getBool("resolvehostnames", me->resolvehostnames);
307 me->password = tag->getString("password", me->password);
309 me->passwordhash = tag->getString("hash", me->passwordhash);
310 if (!me->password.empty() && (me->passwordhash.empty() || stdalgo::string::equalsci(me->passwordhash, "plaintext")))
312 ServerInstance->Logs->Log("CONNECTCLASS", LOG_DEFAULT, "<connect> tag '%s' at %s contains an plain text password, this is insecure!",
313 name.c_str(), tag->getTagLocation().c_str());
316 std::string ports = tag->getString("port");
319 irc::portparser portrange(ports, false);
320 while (int port = portrange.GetToken())
321 me->ports.insert(port);
324 ClassMap::iterator oldMask = oldBlocksByMask.find(typeMask);
325 if (oldMask != oldBlocksByMask.end())
327 ConnectClass* old = oldMask->second;
328 oldBlocksByMask.erase(oldMask);
338 static std::string GetServerName()
342 if (gethostname(hostname, sizeof(hostname)) == 0)
344 std::string name(hostname);
345 if (name.find('.') == std::string::npos)
348 if (name.length() <= ServerInstance->Config->Limits.MaxHost && InspIRCd::IsHost(name))
352 return "irc.example.com";
355 void ServerConfig::Fill()
357 ConfigTag* options = ConfValue("options");
358 ConfigTag* security = ConfValue("security");
359 ConfigTag* server = ConfValue("server");
362 ServerName = server->getString("name", GetServerName(), InspIRCd::IsHost);
364 sid = server->getString("id");
365 if (!sid.empty() && !InspIRCd::IsSID(sid))
366 throw CoreException(sid + " is not a valid server ID. A server ID must be 3 characters long, with the first character a digit and the next two characters a digit or letter.");
368 CaseMapping = options->getString("casemapping", "rfc1459");
369 if (CaseMapping == "ascii")
370 national_case_insensitive_map = ascii_case_insensitive_map;
371 else if (CaseMapping == "rfc1459")
372 national_case_insensitive_map = rfc_case_insensitive_map;
374 throw CoreException("<options:casemapping> must be set to 'ascii', or 'rfc1459'");
378 std::string name = server->getString("name");
379 if (!name.empty() && name != ServerName)
380 throw CoreException("You must restart to change the server name");
382 std::string nsid = server->getString("id");
383 if (!nsid.empty() && nsid != sid)
384 throw CoreException("You must restart to change the server id");
386 std::string casemapping = options->getString("casemapping");
387 // Ignore this value if CaseMapping is set to something the core doesn't provide (i.e., m_nationalchars).
388 if (!casemapping.empty() && casemapping != CaseMapping && (CaseMapping == "ascii" || CaseMapping == "rfc1459"))
389 throw CoreException("You must restart to change the server casemapping");
392 SoftLimit = ConfValue("performance")->getUInt("softlimit", (SocketEngine::GetMaxFds() > 0 ? SocketEngine::GetMaxFds() : LONG_MAX), 10);
393 CCOnConnect = ConfValue("performance")->getBool("clonesonconnect", true);
394 MaxConn = ConfValue("performance")->getUInt("somaxconn", SOMAXCONN);
395 TimeSkipWarn = ConfValue("performance")->getDuration("timeskipwarn", 2, 0, 30);
396 XLineMessage = options->getString("xlinemessage", options->getString("moronbanner", "You're banned!"));
397 ServerDesc = server->getString("description", "Configure Me");
398 Network = server->getString("network", "Network");
399 NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240, 1024, 65534);
400 CustomVersion = security->getString("customversion");
401 HideBans = security->getBool("hidebans");
402 HideServer = security->getString("hideserver", security->getString("hidewhois"));
403 SyntaxHints = options->getBool("syntaxhints");
404 FullHostInTopic = options->getBool("hostintopic");
405 MaxTargets = security->getUInt("maxtargets", 20, 1, 31);
406 DefaultModes = options->getString("defaultmodes", "not");
407 PID = ConfValue("pid")->getString("file");
408 MaxChans = ConfValue("channels")->getUInt("users", 20);
409 OperMaxChans = ConfValue("channels")->getUInt("opers", 0);
410 c_ipv4_range = ConfValue("cidr")->getUInt("ipv4clone", 32, 1, 32);
411 c_ipv6_range = ConfValue("cidr")->getUInt("ipv6clone", 128, 1, 128);
412 Limits = ServerLimits(ConfValue("limits"));
413 Paths = ServerPaths(ConfValue("path"));
414 NoSnoticeStack = options->getBool("nosnoticestack", false);
416 std::string defbind = options->getString("defaultbind");
417 if (stdalgo::string::equalsci(defbind, "ipv4"))
419 WildcardIPv6 = false;
421 else if (stdalgo::string::equalsci(defbind, "ipv6"))
428 int socktest = socket(AF_INET6, SOCK_STREAM, 0);
430 WildcardIPv6 = false;
432 SocketEngine::Close(socktest);
435 ReadXLine(this, "badip", "ipmask", ServerInstance->XLines->GetFactory("Z"));
436 ReadXLine(this, "badnick", "nick", ServerInstance->XLines->GetFactory("Q"));
437 ReadXLine(this, "badhost", "host", ServerInstance->XLines->GetFactory("K"));
438 ReadXLine(this, "exception", "host", ServerInstance->XLines->GetFactory("E"));
440 const std::string restrictbannedusers = options->getString("restrictbannedusers", "yes");
441 if (stdalgo::string::equalsci(restrictbannedusers, "no"))
442 RestrictBannedUsers = ServerConfig::BUT_NORMAL;
443 else if (stdalgo::string::equalsci(restrictbannedusers, "silent"))
444 RestrictBannedUsers = ServerConfig::BUT_RESTRICT_SILENT;
445 else if (stdalgo::string::equalsci(restrictbannedusers, "yes"))
446 RestrictBannedUsers = ServerConfig::BUT_RESTRICT_NOTIFY;
448 throw CoreException(restrictbannedusers + " is an invalid <options:restrictbannedusers> value, at " + options->getTagLocation());
451 // WARNING: it is not safe to use most of the codebase in this function, as it
452 // will run in the config reader thread
453 void ServerConfig::Read()
455 /* Load and parse the config file, if there are any errors then explode */
457 ParseStack stack(this);
460 valid = stack.ParseFile(ServerInstance->ConfigFileName, 0);
462 catch (CoreException& err)
465 errstr << err.GetReason() << std::endl;
469 void ServerConfig::Apply(ServerConfig* old, const std::string &useruid)
475 * These values can only be set on boot. Keep their old values. Do it before we send messages so we actually have a servername.
477 this->CaseMapping = old->CaseMapping;
478 this->ServerName = old->ServerName;
479 this->sid = old->sid;
480 this->cmdline = old->cmdline;
483 /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */
486 // Ensure the user has actually edited ther config.
487 ConfigTagList dietags = ConfTags("die");
488 if (dietags.first != dietags.second)
490 errstr << "Your configuration has not been edited correctly!" << std::endl;
491 for (ConfigIter iter = dietags.first; iter != dietags.second; ++iter)
493 ConfigTag* tag = iter->second;
494 const std::string reason = tag->getString("reason", "You left a <die> tag in your config", 1);
495 errstr << reason << " (at " << tag->getTagLocation() << ")" << std::endl;
501 // Handle special items
502 CrossCheckOperClassType();
503 CrossCheckConnectBlocks(old);
505 catch (CoreException &ce)
507 errstr << ce.GetReason() << std::endl;
510 // Check errors before dealing with failed binds, since continuing on failed bind is wanted in some circumstances.
511 valid = errstr.str().empty();
513 // write once here, to try it out and make sure its ok
515 ServerInstance->WritePID(this->PID, !old);
517 ConfigTagList binds = ConfTags("bind");
518 if (binds.first == binds.second)
519 errstr << "Possible configuration error: you have not defined any <bind> blocks." << std::endl
520 << "You will need to do this if you want clients to be able to connect!" << std::endl;
524 // On first run, ports are bound later on
526 ServerInstance->BindPorts(pl);
529 std::cout << "Warning! Some of your listener" << (pl.size() == 1 ? "s" : "") << " failed to bind:" << std::endl;
530 for (FailedPortList::const_iterator iter = pl.begin(); iter != pl.end(); ++iter)
532 const FailedPort& fp = *iter;
533 errstr << " " << fp.sa.str() << ": " << strerror(fp.error) << std::endl
534 << " " << "Created from <bind> tag at " << fp.tag->getTagLocation() << std::endl;
539 User* user = useruid.empty() ? NULL : ServerInstance->FindUUID(useruid);
543 ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "There were errors in your configuration file:");
547 while (errstr.good())
550 getline(errstr, line, '\n');
553 // On startup, print out to console (still attached at this point)
555 std::cout << line << std::endl;
556 // If a user is rehashing, tell them directly
558 user->WriteRemoteNotice(InspIRCd::Format("*** %s", line.c_str()));
560 ServerInstance->SNO->WriteGlobalSno('a', line);
564 errstr.str(std::string());
566 /* No old configuration -> initial boot, nothing more to do here */
571 ServerInstance->Exit(EXIT_STATUS_CONFIG);
578 // If there were errors processing configuration, don't touch modules.
585 user->WriteRemoteNotice("*** Successfully rehashed server.");
586 ServerInstance->SNO->WriteGlobalSno('a', "*** Successfully rehashed server.");
589 void ServerConfig::ApplyModules(User* user)
591 std::vector<std::string> added_modules;
592 ModuleManager::ModuleMap removed_modules = ServerInstance->Modules->GetModules();
594 ConfigTagList tags = ConfTags("module");
595 for(ConfigIter i = tags.first; i != tags.second; ++i)
597 ConfigTag* tag = i->second;
599 if (tag->readString("name", name))
601 name = ModuleManager::ExpandModName(name);
602 // if this module is already loaded, the erase will succeed, so we need do nothing
603 // otherwise, we need to add the module (which will be done later)
604 if (removed_modules.erase(name) == 0)
605 added_modules.push_back(name);
609 for (ModuleManager::ModuleMap::iterator i = removed_modules.begin(); i != removed_modules.end(); ++i)
611 const std::string& modname = i->first;
612 // Don't remove core_*.so, just remove m_*.so
613 if (InspIRCd::Match(modname, "core_*.so", ascii_case_insensitive_map))
615 if (ServerInstance->Modules->Unload(i->second))
617 ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH UNLOADED MODULE: %s", modname.c_str());
620 user->WriteNumeric(RPL_UNLOADEDMODULE, modname, InspIRCd::Format("Module %s successfully unloaded.", modname.c_str()));
622 ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully unloaded.", modname.c_str());
627 user->WriteNumeric(ERR_CANTUNLOADMODULE, modname, InspIRCd::Format("Failed to unload module %s: %s", modname.c_str(), ServerInstance->Modules->LastError().c_str()));
629 ServerInstance->SNO->WriteGlobalSno('a', "Failed to unload module %s: %s", modname.c_str(), ServerInstance->Modules->LastError().c_str());
633 for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)
635 // Skip modules which are already loaded.
636 if (ServerInstance->Modules->Find(*adding))
639 if (ServerInstance->Modules->Load(*adding))
641 ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH LOADED MODULE: %s",adding->c_str());
643 user->WriteNumeric(RPL_LOADEDMODULE, *adding, InspIRCd::Format("Module %s successfully loaded.", adding->c_str()));
645 ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully loaded.", adding->c_str());
650 user->WriteNumeric(ERR_CANTLOADMODULE, *adding, InspIRCd::Format("Failed to load module %s: %s", adding->c_str(), ServerInstance->Modules->LastError().c_str()));
652 ServerInstance->SNO->WriteGlobalSno('a', "Failed to load module %s: %s", adding->c_str(), ServerInstance->Modules->LastError().c_str());
657 ConfigTag* ServerConfig::ConfValue(const std::string &tag)
659 ConfigTagList found = config_data.equal_range(tag);
660 if (found.first == found.second)
662 ConfigTag* rv = found.first->second;
664 if (found.first != found.second)
665 ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Multiple <" + tag + "> tags found; only first will be used "
666 "(first at " + rv->getTagLocation() + "; second at " + found.first->second->getTagLocation() + ")");
670 ConfigTagList ServerConfig::ConfTags(const std::string& tag)
672 return config_data.equal_range(tag);
675 std::string ServerConfig::Escape(const std::string& str, bool xml)
678 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
683 escaped += xml ? """ : "\"";
686 escaped += xml ? "&" : "&";
689 escaped += xml ? "\\" : "\\\\";
699 void ConfigReaderThread::Run()
705 void ConfigReaderThread::Finish()
707 ServerConfig* old = ServerInstance->Config;
708 ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Switching to new configuration...");
709 ServerInstance->Config = this->Config;
710 Config->Apply(old, TheUserUID);
715 * Apply the changed configuration from the rehash.
717 * XXX: The order of these is IMPORTANT, do not reorder them without testing
720 ServerInstance->Users.RehashCloneCounts();
721 ServerInstance->XLines->CheckELines();
722 ServerInstance->XLines->ApplyLines();
723 User* user = ServerInstance->FindUUID(TheUserUID);
725 ConfigStatus status(user);
726 const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
727 for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
731 ServerInstance->Logs->Log("MODULE", LOG_DEBUG, "Rehashing " + i->first);
732 i->second->ReadConfig(status);
734 catch (CoreException& modex)
736 ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Exception caught: " + modex.GetReason());
738 user->WriteNotice(i->first + ": " + modex.GetReason());
742 // The description of this server may have changed - update it for WHOIS etc.
743 ServerInstance->FakeClient->server->description = Config->ServerDesc;
745 ServerInstance->ISupport.Build();
747 ServerInstance->Logs->CloseLogs();
748 ServerInstance->Logs->OpenFileLogs();
750 if (Config->RawLog && !old->RawLog)
751 ServerInstance->Users->ServerNoticeAll("*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.");
758 ServerInstance->Config = old;