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);
308 std::string ports = tag->getString("port");
311 irc::portparser portrange(ports, false);
312 while (int port = portrange.GetToken())
313 me->ports.insert(port);
316 ClassMap::iterator oldMask = oldBlocksByMask.find(typeMask);
317 if (oldMask != oldBlocksByMask.end())
319 ConnectClass* old = oldMask->second;
320 oldBlocksByMask.erase(oldMask);
330 static std::string GetServerName()
334 if (gethostname(hostname, sizeof(hostname)) == 0)
336 std::string name(hostname);
337 if (name.find('.') == std::string::npos)
340 if (name.length() <= ServerInstance->Config->Limits.MaxHost && InspIRCd::IsHost(name))
344 return "irc.example.com";
347 void ServerConfig::Fill()
349 ConfigTag* options = ConfValue("options");
350 ConfigTag* security = ConfValue("security");
351 ConfigTag* server = ConfValue("server");
354 ServerName = server->getString("name", GetServerName(), InspIRCd::IsHost);
356 sid = server->getString("id");
357 if (!sid.empty() && !InspIRCd::IsSID(sid))
358 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.");
360 CaseMapping = options->getString("casemapping", "rfc1459");
361 if (CaseMapping == "ascii")
362 national_case_insensitive_map = ascii_case_insensitive_map;
363 else if (CaseMapping == "rfc1459")
364 national_case_insensitive_map = rfc_case_insensitive_map;
366 throw CoreException("<options:casemapping> must be set to 'ascii', or 'rfc1459'");
370 std::string name = server->getString("name");
371 if (!name.empty() && name != ServerName)
372 throw CoreException("You must restart to change the server name");
374 std::string nsid = server->getString("id");
375 if (!nsid.empty() && nsid != sid)
376 throw CoreException("You must restart to change the server id");
378 std::string casemapping = options->getString("casemapping");
379 // Ignore this value if CaseMapping is set to something the core doesn't provide (i.e., m_nationalchars).
380 if (!casemapping.empty() && casemapping != CaseMapping && (CaseMapping == "ascii" || CaseMapping == "rfc1459"))
381 throw CoreException("You must restart to change the server casemapping");
384 SoftLimit = ConfValue("performance")->getUInt("softlimit", (SocketEngine::GetMaxFds() > 0 ? SocketEngine::GetMaxFds() : LONG_MAX), 10);
385 CCOnConnect = ConfValue("performance")->getBool("clonesonconnect", true);
386 MaxConn = ConfValue("performance")->getUInt("somaxconn", SOMAXCONN);
387 TimeSkipWarn = ConfValue("performance")->getDuration("timeskipwarn", 2, 0, 30);
388 XLineMessage = options->getString("xlinemessage", options->getString("moronbanner", "You're banned!"));
389 ServerDesc = server->getString("description", "Configure Me");
390 Network = server->getString("network", "Network");
391 NetBufferSize = ConfValue("performance")->getInt("netbuffersize", 10240, 1024, 65534);
392 CustomVersion = security->getString("customversion");
393 HideBans = security->getBool("hidebans");
394 HideServer = security->getString("hideserver", security->getString("hidewhois"));
395 SyntaxHints = options->getBool("syntaxhints");
396 FullHostInTopic = options->getBool("hostintopic");
397 MaxTargets = security->getUInt("maxtargets", 20, 1, 31);
398 DefaultModes = options->getString("defaultmodes", "not");
399 PID = ConfValue("pid")->getString("file");
400 MaxChans = ConfValue("channels")->getUInt("users", 20);
401 OperMaxChans = ConfValue("channels")->getUInt("opers", 0);
402 c_ipv4_range = ConfValue("cidr")->getUInt("ipv4clone", 32, 1, 32);
403 c_ipv6_range = ConfValue("cidr")->getUInt("ipv6clone", 128, 1, 128);
404 Limits = ServerLimits(ConfValue("limits"));
405 Paths = ServerPaths(ConfValue("path"));
406 NoSnoticeStack = options->getBool("nosnoticestack", false);
408 std::string defbind = options->getString("defaultbind");
409 if (stdalgo::string::equalsci(defbind, "ipv4"))
411 WildcardIPv6 = false;
413 else if (stdalgo::string::equalsci(defbind, "ipv6"))
420 int socktest = socket(AF_INET6, SOCK_STREAM, 0);
422 WildcardIPv6 = false;
424 SocketEngine::Close(socktest);
427 ReadXLine(this, "badip", "ipmask", ServerInstance->XLines->GetFactory("Z"));
428 ReadXLine(this, "badnick", "nick", ServerInstance->XLines->GetFactory("Q"));
429 ReadXLine(this, "badhost", "host", ServerInstance->XLines->GetFactory("K"));
430 ReadXLine(this, "exception", "host", ServerInstance->XLines->GetFactory("E"));
432 const std::string restrictbannedusers = options->getString("restrictbannedusers", "yes");
433 if (stdalgo::string::equalsci(restrictbannedusers, "no"))
434 RestrictBannedUsers = ServerConfig::BUT_NORMAL;
435 else if (stdalgo::string::equalsci(restrictbannedusers, "silent"))
436 RestrictBannedUsers = ServerConfig::BUT_RESTRICT_SILENT;
437 else if (stdalgo::string::equalsci(restrictbannedusers, "yes"))
438 RestrictBannedUsers = ServerConfig::BUT_RESTRICT_NOTIFY;
440 throw CoreException(restrictbannedusers + " is an invalid <options:restrictbannedusers> value, at " + options->getTagLocation());
443 // WARNING: it is not safe to use most of the codebase in this function, as it
444 // will run in the config reader thread
445 void ServerConfig::Read()
447 /* Load and parse the config file, if there are any errors then explode */
449 ParseStack stack(this);
452 valid = stack.ParseFile(ServerInstance->ConfigFileName, 0);
454 catch (CoreException& err)
457 errstr << err.GetReason() << std::endl;
461 void ServerConfig::Apply(ServerConfig* old, const std::string &useruid)
467 * These values can only be set on boot. Keep their old values. Do it before we send messages so we actually have a servername.
469 this->CaseMapping = old->CaseMapping;
470 this->ServerName = old->ServerName;
471 this->sid = old->sid;
472 this->cmdline = old->cmdline;
475 /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */
478 // Ensure the user has actually edited ther config.
479 ConfigTagList dietags = ConfTags("die");
480 if (dietags.first != dietags.second)
482 errstr << "Your configuration has not been edited correctly!" << std::endl;
483 for (ConfigIter iter = dietags.first; iter != dietags.second; ++iter)
485 ConfigTag* tag = iter->second;
486 const std::string reason = tag->getString("reason", "You left a <die> tag in your config", 1);
487 errstr << reason << " (at " << tag->getTagLocation() << ")" << std::endl;
493 // Handle special items
494 CrossCheckOperClassType();
495 CrossCheckConnectBlocks(old);
497 catch (CoreException &ce)
499 errstr << ce.GetReason() << std::endl;
502 // Check errors before dealing with failed binds, since continuing on failed bind is wanted in some circumstances.
503 valid = errstr.str().empty();
505 // write once here, to try it out and make sure its ok
507 ServerInstance->WritePID(this->PID, !old);
509 ConfigTagList binds = ConfTags("bind");
510 if (binds.first == binds.second)
511 errstr << "Possible configuration error: you have not defined any <bind> blocks." << std::endl
512 << "You will need to do this if you want clients to be able to connect!" << std::endl;
516 // On first run, ports are bound later on
518 ServerInstance->BindPorts(pl);
521 std::cout << "Warning! Some of your listener" << (pl.size() == 1 ? "s" : "") << " failed to bind:" << std::endl;
522 for (FailedPortList::const_iterator iter = pl.begin(); iter != pl.end(); ++iter)
524 const FailedPort& fp = *iter;
525 errstr << " " << fp.sa.str() << ": " << strerror(fp.error) << std::endl
526 << " " << "Created from <bind> tag at " << fp.tag->getTagLocation() << std::endl;
531 User* user = useruid.empty() ? NULL : ServerInstance->FindUUID(useruid);
535 ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "There were errors in your configuration file:");
539 while (errstr.good())
542 getline(errstr, line, '\n');
545 // On startup, print out to console (still attached at this point)
547 std::cout << line << std::endl;
548 // If a user is rehashing, tell them directly
550 user->WriteRemoteNotice(InspIRCd::Format("*** %s", line.c_str()));
552 ServerInstance->SNO->WriteGlobalSno('a', line);
556 errstr.str(std::string());
558 /* No old configuration -> initial boot, nothing more to do here */
563 ServerInstance->Exit(EXIT_STATUS_CONFIG);
570 // If there were errors processing configuration, don't touch modules.
577 user->WriteRemoteNotice("*** Successfully rehashed server.");
578 ServerInstance->SNO->WriteGlobalSno('a', "*** Successfully rehashed server.");
581 void ServerConfig::ApplyModules(User* user)
583 std::vector<std::string> added_modules;
584 ModuleManager::ModuleMap removed_modules = ServerInstance->Modules->GetModules();
586 ConfigTagList tags = ConfTags("module");
587 for(ConfigIter i = tags.first; i != tags.second; ++i)
589 ConfigTag* tag = i->second;
591 if (tag->readString("name", name))
593 name = ModuleManager::ExpandModName(name);
594 // if this module is already loaded, the erase will succeed, so we need do nothing
595 // otherwise, we need to add the module (which will be done later)
596 if (removed_modules.erase(name) == 0)
597 added_modules.push_back(name);
601 for (ModuleManager::ModuleMap::iterator i = removed_modules.begin(); i != removed_modules.end(); ++i)
603 const std::string& modname = i->first;
604 // Don't remove core_*.so, just remove m_*.so
605 if (InspIRCd::Match(modname, "core_*.so", ascii_case_insensitive_map))
607 if (ServerInstance->Modules->Unload(i->second))
609 ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH UNLOADED MODULE: %s", modname.c_str());
612 user->WriteNumeric(RPL_UNLOADEDMODULE, modname, InspIRCd::Format("Module %s successfully unloaded.", modname.c_str()));
614 ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully unloaded.", modname.c_str());
619 user->WriteNumeric(ERR_CANTUNLOADMODULE, modname, InspIRCd::Format("Failed to unload module %s: %s", modname.c_str(), ServerInstance->Modules->LastError().c_str()));
621 ServerInstance->SNO->WriteGlobalSno('a', "Failed to unload module %s: %s", modname.c_str(), ServerInstance->Modules->LastError().c_str());
625 for (std::vector<std::string>::iterator adding = added_modules.begin(); adding != added_modules.end(); adding++)
627 // Skip modules which are already loaded.
628 if (ServerInstance->Modules->Find(*adding))
631 if (ServerInstance->Modules->Load(*adding))
633 ServerInstance->SNO->WriteGlobalSno('a', "*** REHASH LOADED MODULE: %s",adding->c_str());
635 user->WriteNumeric(RPL_LOADEDMODULE, *adding, InspIRCd::Format("Module %s successfully loaded.", adding->c_str()));
637 ServerInstance->SNO->WriteGlobalSno('a', "Module %s successfully loaded.", adding->c_str());
642 user->WriteNumeric(ERR_CANTLOADMODULE, *adding, InspIRCd::Format("Failed to load module %s: %s", adding->c_str(), ServerInstance->Modules->LastError().c_str()));
644 ServerInstance->SNO->WriteGlobalSno('a', "Failed to load module %s: %s", adding->c_str(), ServerInstance->Modules->LastError().c_str());
649 ConfigTag* ServerConfig::ConfValue(const std::string &tag)
651 ConfigTagList found = config_data.equal_range(tag);
652 if (found.first == found.second)
654 ConfigTag* rv = found.first->second;
656 if (found.first != found.second)
657 ServerInstance->Logs->Log("CONFIG", LOG_DEFAULT, "Multiple <" + tag + "> tags found; only first will be used "
658 "(first at " + rv->getTagLocation() + "; second at " + found.first->second->getTagLocation() + ")");
662 ConfigTagList ServerConfig::ConfTags(const std::string& tag)
664 return config_data.equal_range(tag);
667 std::string ServerConfig::Escape(const std::string& str, bool xml)
670 for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
675 escaped += xml ? """ : "\"";
678 escaped += xml ? "&" : "&";
681 escaped += xml ? "\\" : "\\\\";
691 void ConfigReaderThread::Run()
697 void ConfigReaderThread::Finish()
699 ServerConfig* old = ServerInstance->Config;
700 ServerInstance->Logs->Log("CONFIG", LOG_DEBUG, "Switching to new configuration...");
701 ServerInstance->Config = this->Config;
702 Config->Apply(old, TheUserUID);
707 * Apply the changed configuration from the rehash.
709 * XXX: The order of these is IMPORTANT, do not reorder them without testing
712 ServerInstance->Users.RehashCloneCounts();
713 ServerInstance->XLines->CheckELines();
714 ServerInstance->XLines->ApplyLines();
715 User* user = ServerInstance->FindUUID(TheUserUID);
717 ConfigStatus status(user);
718 const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules();
719 for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i)
723 ServerInstance->Logs->Log("MODULE", LOG_DEBUG, "Rehashing " + i->first);
724 i->second->ReadConfig(status);
726 catch (CoreException& modex)
728 ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Exception caught: " + modex.GetReason());
730 user->WriteNotice(i->first + ": " + modex.GetReason());
734 // The description of this server may have changed - update it for WHOIS etc.
735 ServerInstance->FakeClient->server->description = Config->ServerDesc;
737 ServerInstance->ISupport.Build();
739 ServerInstance->Logs->CloseLogs();
740 ServerInstance->Logs->OpenFileLogs();
742 if (Config->RawLog && !old->RawLog)
743 ServerInstance->Users->ServerNoticeAll("*** Raw I/O logging is enabled on this server. All messages, passwords, and commands are being recorded.");
750 ServerInstance->Config = old;