dns_timeout = DieDelay = 5;
MaxTargets = 20;
NetBufferSize = 10240;
- SoftLimit = MAXCLIENTS;
+ SoftLimit = Instance->SE->GetMaxFds();
MaxConn = SOMAXCONN;
MaxWhoResults = 0;
debugging = 0;
include_stack.clear();
}
-Module* ServerConfig::GetIOHook(int port)
-{
- std::map<int,Module*>::iterator x = IOHookModule.find(port);
- return (x != IOHookModule.end() ? x->second : NULL);
-}
-
Module* ServerConfig::GetIOHook(BufferedSocket* is)
{
std::map<BufferedSocket*,Module*>::iterator x = SocketIOHookModule.find(is);
return (x != SocketIOHookModule.end() ? x->second : NULL);
}
-bool ServerConfig::AddIOHook(int port, Module* iomod)
-{
- if (!GetIOHook(port))
- {
- IOHookModule[port] = iomod;
- return true;
- }
- else
- {
- throw ModuleException("Port already hooked by another module");
- return false;
- }
-}
-
bool ServerConfig::AddIOHook(Module* iomod, BufferedSocket* is)
{
if (!GetIOHook(is))
}
}
-bool ServerConfig::DelIOHook(int port)
-{
- std::map<int,Module*>::iterator x = IOHookModule.find(port);
- if (x != IOHookModule.end())
- {
- IOHookModule.erase(x);
- return true;
- }
- return false;
-}
-
bool ServerConfig::DelIOHook(BufferedSocket* is)
{
std::map<BufferedSocket*,Module*>::iterator x = SocketIOHookModule.find(is);
void ServerConfig::Send005(User* user)
{
for (std::vector<std::string>::iterator line = ServerInstance->Config->isupport.begin(); line != ServerInstance->Config->isupport.end(); line++)
- user->WriteServ("005 %s %s", user->nick, line->c_str());
+ user->WriteNumeric(005, "%s %s", user->nick, line->c_str());
}
bool ServerConfig::CheckOnce(const char* tag)
bool ValidateSoftLimit(ServerConfig* conf, const char*, const char*, ValueItem &data)
{
- if ((data.GetInteger() < 1) || (data.GetInteger() > MAXCLIENTS))
+ if ((data.GetInteger() < 1) || (data.GetInteger() > conf->GetInstance()->SE->GetMaxFds()))
{
- conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: <options:softlimit> value is greater than %d or less than 0, set to %d.",MAXCLIENTS,MAXCLIENTS);
- data.Set(MAXCLIENTS);
+ conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: <options:softlimit> value is greater than %d or less than 0, set to %d.",conf->GetInstance()->SE->GetMaxFds(),conf->GetInstance()->SE->GetMaxFds());
+ data.Set(conf->GetInstance()->SE->GetMaxFds());
}
return true;
}
bool ValidateServerName(ServerConfig* conf, const char*, const char*, ValueItem &data)
{
+ conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Validating server name");
/* If we already have a servername, and they changed it, we should throw an exception. */
- if ((strcasecmp(conf->ServerName, data.GetString())) && (*conf->ServerName))
- {
- throw CoreException("Configuration error: You cannot change your servername at runtime! Please restart your server for this change to be applied.");
- /* We don't actually reach this return of course... */
- return false;
- }
- if (!strchr(data.GetString(),'.'))
+ if (!strchr(data.GetString(), '.'))
{
conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"WARNING: <server:name> '%s' is not a fully-qualified domain name. Changed to '%s%c'",data.GetString(),data.GetString(),'.');
std::string moo = std::string(data.GetString()).append(".");
bool ValidateSID(ServerConfig* conf, const char*, const char*, ValueItem &data)
{
+ conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Validating server id");
+
const char *sid = data.GetString();
if (*sid && !conf->GetInstance()->IsSID(sid))
throw CoreException(std::string(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.");
}
+ strlcpy(conf->sid, sid, 5);
+
return true;
}
{
conf->GetInstance()->Logs->Log("CONFIG",DEFAULT,"Reading connect classes...");
- for (ClassVector::iterator i = conf->Classes.begin(); i != conf->Classes.end(); i++)
- {
- ConnectClass *c = *i;
-
- conf->GetInstance()->Logs->Log("CONFIG",DEBUG, "Address of class is %p", c);
- }
-
for (ClassVector::iterator i = conf->Classes.begin(); i != conf->Classes.end() ; )
{
ConnectClass* c = *i;
ServerInstance->SNO->WriteToSnoMask('A', "There were errors in the configuration file:");
while (start < errors.length())
{
- ServerInstance->SNO->WriteToSnoMask('A', errors.substr(start, 360).c_str());
+ ServerInstance->SNO->WriteToSnoMask('A', errors.substr(start, 360));
start += 360;
}
}
/* These tags can occur ONCE or not at all */
InitialConfig Values[] = {
- {"options", "softlimit", MAXCLIENTS_S, new ValueContainerUInt (&this->SoftLimit), DT_INTEGER, ValidateSoftLimit},
+ {"options", "softlimit", "0", new ValueContainerUInt (&this->SoftLimit), DT_INTEGER, ValidateSoftLimit},
{"options", "somaxconn", SOMAXCONN_S, new ValueContainerInt (&this->MaxConn), DT_INTEGER, ValidateMaxConn},
{"options", "moronbanner", "Youre banned!", new ValueContainerChar (this->MoronBanner), DT_CHARPTR, NoValidation},
- {"server", "name", "", new ValueContainerChar (this->ServerName), DT_HOSTNAME, ValidateServerName},
+ {"server", "name", "", new ValueContainerChar (this->ServerName), DT_HOSTNAME|DT_BOOTONLY, ValidateServerName},
{"server", "description", "Configure Me", new ValueContainerChar (this->ServerDesc), DT_CHARPTR, NoValidation},
{"server", "network", "Network", new ValueContainerChar (this->Network), DT_NOSPACES, NoValidation},
- {"server", "id", "", new ValueContainerChar (this->sid), DT_CHARPTR, ValidateSID},
+ {"server", "id", "", new ValueContainerChar (this->sid), DT_CHARPTR|DT_BOOTONLY, ValidateSID},
{"admin", "name", "", new ValueContainerChar (this->AdminName), DT_CHARPTR, NoValidation},
{"admin", "email", "Mis@configu.red", new ValueContainerChar (this->AdminEmail), DT_CHARPTR, NoValidation},
{"admin", "nick", "Misconfigured", new ValueContainerChar (this->AdminNick), DT_CHARPTR, NoValidation},
InitTypes, DoType, DoneClassesAndTypes},
{"class",
- {"name", "commands", NULL},
- {"", "", NULL},
- {DT_NOSPACES, DT_CHARPTR},
+ {"name", "commands", "usermodes", "chanmodes", NULL},
+ {"", "", "", "", NULL},
+ {DT_NOSPACES, DT_CHARPTR, DT_CHARPTR, DT_CHARPTR},
InitClasses, DoClass, DoneClassesAndTypes},
{NULL,
/* Make a copy here so if it fails then we can carry on running with an unaffected config */
newconfig.clear();
- if (this->LoadConf(newconfig, ServerInstance->ConfigFileName, errstr))
+ if (this->DoInclude(newconfig, ServerInstance->ConfigFileName, errstr))
{
/* If we succeeded, set the ircd config to the new one */
ServerInstance->Threads->Mutex(true);
int dt = Values[Index].datatype;
bool allow_newlines = ((dt & DT_ALLOW_NEWLINE) > 0);
bool allow_wild = ((dt & DT_ALLOW_WILD) > 0);
+ bool bootonly = ((dt & DT_BOOTONLY) > 0);
dt &= ~DT_ALLOW_NEWLINE;
dt &= ~DT_ALLOW_WILD;
+ dt &= ~DT_BOOTONLY;
+
+ /* Silently ignore boot only values */
+ if (bootonly && !bail)
+ continue;
ConfValue(this->config_data, Values[Index].tag, Values[Index].value, Values[Index].default_value, 0, item, MAXBUF, allow_newlines);
ValueItem vi(item);
throw CoreException("One or more values in your configuration file failed to validate. Please see your ircd.log for more information.");
ServerInstance->Threads->Mutex(true);
- switch (Values[Index].datatype)
+ switch (dt)
{
case DT_NOSPACES:
{
ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val;
this->ValidateHostname(vi.GetString(), Values[Index].tag, Values[Index].value);
vcc->Set(vi.GetString(), strlen(vi.GetString()) + 1);
+ ServerInstance->Logs->Log("CONFIG",DEFAULT,"Got %s", vi.GetString());
}
break;
case DT_IPADDRESS:
// write once here, to try it out and make sure its ok
ServerInstance->WritePID(this->PID);
- ServerInstance->Log(DEFAULT,"Done reading configuration file.");
-
/* Switch over logfiles */
ServerInstance->Logs->CloseLogs();
ServerInstance->Logs->OpenFileLogs();
+ ServerInstance->Logs->Log("CONFIG", DEFAULT, "Done reading configuration file.");
+
/* If we're rehashing, let's load any new modules, and unload old ones
*/
if (!bail)
ServerInstance->SNO->WriteToSnoMask('A', "*** REHASH UNLOADED MODULE: %s",removing->c_str());
if (user)
- user->WriteServ("973 %s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());
+ user->WriteNumeric(973, "%s %s :Module %s successfully unloaded.",user->nick, removing->c_str(), removing->c_str());
rem++;
}
else
{
if (user)
- user->WriteServ("972 %s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ServerInstance->Modules->LastError().c_str());
+ user->WriteNumeric(972, "%s %s :Failed to unload module %s: %s",user->nick, removing->c_str(), removing->c_str(), ServerInstance->Modules->LastError().c_str());
}
}
}
ServerInstance->SNO->WriteToSnoMask('A', "*** REHASH LOADED MODULE: %s",adding->c_str());
if (user)
- user->WriteServ("975 %s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());
+ user->WriteNumeric(975, "%s %s :Module %s successfully loaded.",user->nick, adding->c_str(), adding->c_str());
add++;
}
else
{
if (user)
- user->WriteServ("974 %s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str());
+ user->WriteNumeric(974, "%s %s :Failed to load module %s: %s",user->nick, adding->c_str(), adding->c_str(), ServerInstance->Modules->LastError().c_str());
}
}
}
- ServerInstance->Log(DEFAULT,"Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size());
+ ServerInstance->Logs->Log("CONFIG", DEFAULT, "Successfully unloaded %lu of %lu modules and loaded %lu of %lu modules.",(unsigned long)rem,(unsigned long)removed_modules.size(),(unsigned long)add,(unsigned long)added_modules.size());
ServerInstance->Threads->Mutex(false);
}
-bool ServerConfig::LoadConf(ConfigDataHash &target, const char* filename, std::ostringstream &errorstream)
+bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const char* filename, std::ostringstream &errorstream)
{
- std::ifstream conf(filename);
std::string line;
char ch;
long linenumber;
in_quote = false;
in_comment = false;
+ ServerInstance->Logs->Log("CONFIG", DEBUG, "Reading %s", filename);
+
/* Check if the file open failed first */
if (!conf)
{
return false;
}
- /* Fix the chmod of the file to restrict it to the current user and group */
- chmod(filename,0600);
-
for (unsigned int t = 0; t < include_stack.size(); t++)
{
if (std::string(filename) == include_stack[t])
include_stack.push_back(filename);
/* Start reading characters... */
- while (conf.get(ch))
+ while (!feof(conf))
{
-
+ ch = fgetc(conf);
/*
* Fix for moronic windows issue spotted by Adremelech.
* Some windows editors save text files as utf-16, which is
{
line += ch;
char real_character;
- if (conf.get(real_character))
+ if (!feof(conf))
{
+ real_character = fgetc(conf);
if (real_character == 'n')
real_character = '\n';
line += real_character;
}
-bool ServerConfig::LoadConf(ConfigDataHash &target, const std::string &filename, std::ostringstream &errorstream)
+bool ServerConfig::LoadConf(ConfigDataHash &target, FILE* &conf, const std::string &filename, std::ostringstream &errorstream)
{
- return this->LoadConf(target, filename.c_str(), errorstream);
+ return this->LoadConf(target, conf, filename.c_str(), errorstream);
}
bool ServerConfig::ParseLine(ConfigDataHash &target, std::string &line, long &linenumber, std::ostringstream &errorstream)
if (!this->DoInclude(target, current_value, errorstream))
return false;
}
+ else if ((tagname == "include") && (current_key == "executable"))
+ {
+ /* Pipe an executable and use its stdout as config data */
+ if (!this->DoPipe(target, current_value, errorstream))
+ return false;
+ }
current_key.clear();
current_value.clear();
return true;
}
+bool ServerConfig::DoPipe(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream)
+{
+ FILE* conf = popen(file.c_str(), "r");
+ bool ret = false;
+
+ if (conf)
+ {
+ ret = LoadConf(target, conf, file.c_str(), errorstream);
+ pclose(conf);
+ }
+ else
+ errorstream << "Couldn't execute: " << file << std::endl;
+
+ return ret;
+}
+
bool ServerConfig::DoInclude(ConfigDataHash &target, const std::string &file, std::ostringstream &errorstream)
{
std::string confpath;
}
}
- return LoadConf(target, newfile, errorstream);
+ FILE* conf = fopen(newfile.c_str(), "r");
+ bool ret = false;
+
+ if (conf)
+ {
+ ret = LoadConf(target, conf, newfile, errorstream);
+ fclose(conf);
+ }
+ else
+ errorstream << "Couldn't open config file: " << file << std::endl;
+
+ return ret;
}
bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds)
{
for (operclass_t::iterator n = conf->operclass.begin(); n != conf->operclass.end(); n++)
{
- if (n->second)
- delete[] n->second;
+ if (n->second.commandlist)
+ delete[] n->second.commandlist;
+ if (n->second.cmodelist)
+ delete[] n->second.cmodelist;
+ if (n->second.umodelist)
+ delete[] n->second.umodelist;
}
}
/*
* XXX should this be in a class? -- w00t
*/
-bool DoClass(ServerConfig* conf, const char*, char**, ValueList &values, int*)
+bool DoClass(ServerConfig* conf, const char* tag, char**, ValueList &values, int*)
{
const char* ClassName = values[0].GetString();
const char* CommandList = values[1].GetString();
+ const char* UModeList = values[2].GetString();
+ const char* CModeList = values[3].GetString();
+
+ for (const char* c = UModeList; *c; ++c)
+ {
+ if ((*c < 'A' || *c > 'z') && *c != '*')
+ {
+ throw CoreException("Character " + std::string(1, *c) + " is not a valid mode in <class:usermodes>");
+ }
+ }
+ for (const char* c = CModeList; *c; ++c)
+ {
+ if ((*c < 'A' || *c > 'z') && *c != '*')
+ {
+ throw CoreException("Character " + std::string(1, *c) + " is not a valid mode in <class:chanmodes>");
+ }
+ }
- conf->operclass[ClassName] = strnewdup(CommandList);
+ conf->operclass[ClassName].commandlist = strnewdup(CommandList);
+ conf->operclass[ClassName].umodelist = strnewdup(UModeList);
+ conf->operclass[ClassName].cmodelist = strnewdup(CModeList);
return true;
}