* | Inspire Internet Relay Chat Daemon |
* +------------------------------------+
*
- * InspIRCd is copyright (C) 2002-2006 ChatSpike-Dev.
- * E-mail:
- * <brain@chatspike.net>
- * <Craig@chatspike.net>
- *
- * Written by Craig Edwards, Craig McLure, and others.
+ * InspIRCd: (C) 2002-2007 InspIRCd Development Team
+ * See: http://www.inspircd.org/wiki/index.php/Credits
+ *
* This program is free but copyrighted software; see
- * the file COPYING for details.
+ * the file COPYING for details.
*
* ---------------------------------------------------
*/
return (x != IOHookModule.end() ? x->second : NULL);
}
+Module* ServerConfig::GetIOHook(InspSocket* is)
+{
+ std::map<InspSocket*,Module*>::iterator x = SocketIOHookModule.find(is);
+ return (x != SocketIOHookModule.end() ? x->second : NULL);
+}
+
bool ServerConfig::AddIOHook(int port, Module* iomod)
{
if (!GetIOHook(port))
}
else
{
- ModuleException err("Port already hooked by another module");
- throw(err);
+ throw ModuleException("Port already hooked by another module");
+ return false;
+ }
+}
+
+bool ServerConfig::AddIOHook(Module* iomod, InspSocket* is)
+{
+ if (!GetIOHook(is))
+ {
+ ServerInstance->Log(DEBUG,"Hooked inspsocket %08x", is);
+ SocketIOHookModule[is] = iomod;
+ is->IsIOHooked = true;
+ return true;
+ }
+ else
+ {
+ throw ModuleException("InspSocket derived class already hooked by another module");
return false;
}
}
return false;
}
+bool ServerConfig::DelIOHook(InspSocket* is)
+{
+ std::map<InspSocket*,Module*>::iterator x = SocketIOHookModule.find(is);
+ if (x != SocketIOHookModule.end())
+ {
+ SocketIOHookModule.erase(x);
+ return true;
+ }
+ return false;
+}
+
+void ServerConfig::Update005()
+{
+ std::stringstream out(data005);
+ std::string token;
+ std::string line5;
+ int token_counter = 0;
+ isupport.clear();
+ while (out >> token)
+ {
+ line5 = line5 + token + " ";
+ token_counter++;
+ if (token_counter >= 13)
+ {
+ char buf[MAXBUF];
+ snprintf(buf, MAXBUF, "%s:are supported by this server", line5.c_str());
+ isupport.push_back(buf);
+ line5 = "";
+ token_counter = 0;
+ }
+ }
+ char buf[MAXBUF];
+ snprintf(buf, MAXBUF, "%s:are supported by this server", line5.c_str());
+ isupport.push_back(buf);
+}
+
+void ServerConfig::Send005(userrec* 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());
+}
+
bool ServerConfig::CheckOnce(char* tag, bool bail, userrec* user)
{
int count = ConfValueEnum(this->config_data, tag);
return true;
}
-bool ValidateDie(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
-{
- if (!*data.GetString())
- {
- conf->GetInstance()->Log(DEFAULT,"Die value is set: \"%s\", terminating.", data.GetString());
- printf("\n\nERROR: %s\n\n", data.GetString());
- exit(ERROR);
- }
- return true;
-}
-
bool ValidateWhoWas(ServerConfig* conf, const char* tag, const char* value, ValueItem &data)
{
conf->WhoWasMaxKeep = conf->GetInstance()->Duration(data.GetString());
if (*allow)
{
- c.host = allow;
- c.type = CC_ALLOW;
- c.pass = password;
- c.registration_timeout = timeout;
- c.pingtime = pingfreq;
- c.flood = flood;
- c.threshold = threshold;
- c.sendqmax = sendq;
- c.recvqmax = recvq;
- c.maxlocal = localmax;
- c.maxglobal = globalmax;
-
-
- if (c.maxlocal == 0)
- c.maxlocal = 3;
- if (c.maxglobal == 0)
- c.maxglobal = 3;
- if (c.threshold == 0)
- {
- c.threshold = 1;
- c.flood = 999;
- conf->GetInstance()->Log(DEFAULT,"Warning: Connect allow line '%s' has no flood/threshold settings. Setting this tag to 999 lines in 1 second.",c.host.c_str());
- }
- if (c.sendqmax == 0)
- c.sendqmax = 262114;
- if (c.recvqmax == 0)
- c.recvqmax = 4096;
- if (c.registration_timeout == 0)
- c.registration_timeout = 90;
- if (c.pingtime == 0)
- c.pingtime = 120;
+ ConnectClass c(timeout, flood, allow, pingfreq, password, threshold, sendq, recvq, localmax, globalmax);
conf->Classes.push_back(c);
}
else
{
- c.host = deny;
- c.type = CC_DENY;
+ ConnectClass c(deny);
conf->Classes.push_back(c);
- conf->GetInstance()->Log(DEBUG,"Read connect class type DENY, host=%s",deny);
}
return true;
return true;
}
+void ServerConfig::ReportConfigError(const std::string &errormessage, bool bail, userrec* user)
+{
+ ServerInstance->Log(DEFAULT, "There were errors in your configuration file: %s", errormessage.c_str());
+ if (bail)
+ {
+ /* Unneeded because of the ServerInstance->Log() aboive? */
+ printf("There were errors in your configuration:\n%s\n\n",errormessage.c_str());
+ InspIRCd::Exit(ERROR);
+ }
+ else
+ {
+ std::string errors = errormessage;
+ std::string::size_type start;
+ unsigned int prefixlen;
+ start = 0;
+ /* ":ServerInstance->Config->ServerName NOTICE user->nick :" */
+ prefixlen = strlen(this->ServerName) + strlen(user->nick) + 11;
+ if (user)
+ {
+ user->WriteServ("NOTICE %s :There were errors in the configuration file:",user->nick);
+ while (start < errors.length())
+ {
+ user->WriteServ("NOTICE %s :%s",user->nick, errors.substr(start, 510 - prefixlen).c_str());
+ start += 510 - prefixlen;
+ }
+ }
+ else
+ {
+ ServerInstance->WriteOpers("There were errors in the configuration file:");
+ while (start < errors.length())
+ {
+ ServerInstance->WriteOpers(errors.substr(start, 360).c_str());
+ start += 360;
+ }
+ }
+ return;
+ }
+}
+
void ServerConfig::Read(bool bail, userrec* user)
{
static char debug[MAXBUF]; /* Temporary buffer for debugging value */
{"options", "nouserdns", new ValueContainerBool (&this->NoUserDns), DT_BOOLEAN, NoValidation},
{"options", "syntaxhints", new ValueContainerBool (&this->SyntaxHints), DT_BOOLEAN, NoValidation},
{"options", "cyclehosts", new ValueContainerBool (&this->CycleHosts), DT_BOOLEAN, NoValidation},
+ {"options", "ircumsgprefix", new ValueContainerBool (&this->UndernetMsgPrefix), DT_BOOLEAN, NoValidation},
{"pid", "file", new ValueContainerChar (this->PID), DT_CHARPTR, NoValidation},
{"whowas", "groupsize", new ValueContainerInt (&this->WhoWasGroupSize), DT_INTEGER, NoValidation},
{"whowas", "maxgroups", new ValueContainerInt (&this->WhoWasMaxGroups), DT_INTEGER, NoValidation},
{"whowas", "maxkeep", new ValueContainerChar (maxkeep), DT_CHARPTR, ValidateWhoWas},
- {"die", "value", new ValueContainerChar (this->DieValue), DT_CHARPTR, ValidateDie},
+ {"die", "value", new ValueContainerChar (this->DieValue), DT_CHARPTR, NoValidation},
{NULL}
};
}
else
{
- ServerInstance->Log(DEFAULT, "There were errors in your configuration:\n%s", errstr.str().c_str());
-
- if (bail)
- {
- /* Unneeded because of the ServerInstance->Log() aboive? */
- printf("There were errors in your configuration:\n%s",errstr.str().c_str());
- InspIRCd::Exit(ERROR);
- }
- else
- {
- std::string errors = errstr.str();
- std::string::size_type start;
- unsigned int prefixlen;
-
- start = 0;
- /* ":ServerInstance->Config->ServerName NOTICE user->nick :" */
- prefixlen = strlen(this->ServerName) + strlen(user->nick) + 11;
-
- if (user)
- {
- user->WriteServ("NOTICE %s :There were errors in the configuration file:",user->nick);
-
- while(start < errors.length())
- {
- user->WriteServ("NOTICE %s :%s",user->nick, errors.substr(start, 510 - prefixlen).c_str());
- start += 510 - prefixlen;
- }
- }
- else
- {
- ServerInstance->WriteOpers("There were errors in the configuration file:");
-
- while(start < errors.length())
- {
- ServerInstance->WriteOpers(errors.substr(start, 360).c_str());
- start += 360;
- }
- }
-
- return;
- }
+ ReportConfigError(errstr.str(), bail, user);
+ return;
}
- /* Check we dont have more than one of singular tags, or any of them missing
- */
- for (int Index = 0; Once[Index]; Index++)
- if (!CheckOnce(Once[Index], bail, user))
- return;
-
- /* Read the values of all the tags which occur once or not at all, and call their callbacks.
- */
- for (int Index = 0; Values[Index].tag; Index++)
+ /* The stuff in here may throw CoreException, be sure we're in a position to catch it. */
+ try
{
- char item[MAXBUF];
- ConfValue(this->config_data, Values[Index].tag, Values[Index].value, 0, item, MAXBUF);
- ValueItem vi(item);
-
- Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi);
+ /* Check we dont have more than one of singular tags, or any of them missing
+ */
+ for (int Index = 0; Once[Index]; Index++)
+ if (!CheckOnce(Once[Index], bail, user))
+ return;
- switch (Values[Index].datatype)
+ /* Read the values of all the tags which occur once or not at all, and call their callbacks.
+ */
+ for (int Index = 0; Values[Index].tag; Index++)
{
- case DT_CHARPTR:
+ char item[MAXBUF];
+ int dt = Values[Index].datatype;
+ bool allow_newlines = ((dt & DT_ALLOW_NEWLINE) > 0);
+ dt &= ~DT_ALLOW_NEWLINE;
+
+ ConfValue(this->config_data, Values[Index].tag, Values[Index].value, 0, item, MAXBUF, allow_newlines);
+ ValueItem vi(item);
+
+ Values[Index].validation_function(this, Values[Index].tag, Values[Index].value, vi);
+
+ switch (Values[Index].datatype)
+ {
+ case DT_CHARPTR:
{
ValueContainerChar* vcc = (ValueContainerChar*)Values[Index].val;
vcc->Set(vi.GetString(), strlen(vi.GetString()));
}
- break;
- case DT_INTEGER:
+ break;
+ case DT_INTEGER:
{
int val = vi.GetInteger();
ValueContainerInt* vci = (ValueContainerInt*)Values[Index].val;
vci->Set(&val, sizeof(int));
}
- break;
- case DT_BOOLEAN:
+ break;
+ case DT_BOOLEAN:
{
bool val = vi.GetBool();
ValueContainerBool* vcb = (ValueContainerBool*)Values[Index].val;
vcb->Set(&val, sizeof(bool));
}
- break;
- default:
- /* You don't want to know what happens if someones bad code sends us here. */
- break;
+ break;
+ default:
+ /* You don't want to know what happens if someones bad code sends us here. */
+ break;
+ }
+
+ /* We're done with this now */
+ delete Values[Index].val;
}
- /* We're done with this now */
- delete Values[Index].val;
- }
-
- /* Read the multiple-tag items (class tags, connect tags, etc)
- * and call the callbacks associated with them. We have three
- * callbacks for these, a 'start', 'item' and 'end' callback.
- */
- for (int Index = 0; MultiValues[Index].tag; Index++)
- {
- MultiValues[Index].init_function(this, MultiValues[Index].tag);
+ /* Read the multiple-tag items (class tags, connect tags, etc)
+ * and call the callbacks associated with them. We have three
+ * callbacks for these, a 'start', 'item' and 'end' callback.
+ */
+ for (int Index = 0; MultiValues[Index].tag; Index++)
+ {
+ MultiValues[Index].init_function(this, MultiValues[Index].tag);
- int number_of_tags = ConfValueEnum(this->config_data, MultiValues[Index].tag);
+ int number_of_tags = ConfValueEnum(this->config_data, MultiValues[Index].tag);
- for (int tagnum = 0; tagnum < number_of_tags; tagnum++)
- {
- ValueList vl;
- for (int valuenum = 0; MultiValues[Index].items[valuenum]; valuenum++)
+ for (int tagnum = 0; tagnum < number_of_tags; tagnum++)
{
- switch (MultiValues[Index].datatype[valuenum])
+ ValueList vl;
+ for (int valuenum = 0; MultiValues[Index].items[valuenum]; valuenum++)
{
- case DT_CHARPTR:
+ int dt = MultiValues[Index].datatype[valuenum];
+ bool allow_newlines = ((dt & DT_ALLOW_NEWLINE) > 0);
+ dt &= ~DT_ALLOW_NEWLINE;
+
+ switch (dt)
+ {
+ case DT_CHARPTR:
{
char item[MAXBUF];
- ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], tagnum, item, MAXBUF);
+ ConfValue(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], tagnum, item, MAXBUF, allow_newlines);
vl.push_back(ValueItem(item));
}
- break;
- case DT_INTEGER:
+ break;
+ case DT_INTEGER:
{
int item;
ConfValueInteger(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], tagnum, item);
vl.push_back(ValueItem(item));
}
- break;
- case DT_BOOLEAN:
+ break;
+ case DT_BOOLEAN:
{
bool item = ConfValueBool(this->config_data, MultiValues[Index].tag, MultiValues[Index].items[valuenum], tagnum);
vl.push_back(ValueItem(item));
}
- break;
- default:
- /* Someone was smoking craq if we got here, and we're all gonna die. */
- break;
+ break;
+ default:
+ /* Someone was smoking craq if we got here, and we're all gonna die. */
+ break;
+ }
}
+
+ MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype);
}
-
- MultiValues[Index].validation_function(this, MultiValues[Index].tag, (char**)MultiValues[Index].items, vl, MultiValues[Index].datatype);
+
+ MultiValues[Index].finish_function(this, MultiValues[Index].tag);
}
- MultiValues[Index].finish_function(this, MultiValues[Index].tag);
+ }
+
+ catch (CoreException &ce)
+ {
+ ReportConfigError(ce.GetReason(), bail, user);
+ return;
}
// write once here, to try it out and make sure its ok
if((ch == '#') && !in_quote)
in_comment = true;
- if(((ch == '\n') || (ch == '\r')) && in_quote)
+ /*if(((ch == '\n') || (ch == '\r')) && in_quote)
{
errorstream << "Got a newline within a quoted section, this is probably a typo: " << filename << ":" << linenumber << std::endl;
return false;
- }
+ }*/
switch(ch)
{
case '\n':
+ if (in_quote)
+ {
+ ServerInstance->Log(DEBUG, "Got \\n inside value");
+ line += '\n';
+ }
linenumber++;
case '\r':
- in_comment = false;
+ if (!in_quote)
+ in_comment = false;
case '\0':
continue;
case '\t':
}
}
- line += ch;
+ if (ch != '\r')
+ line += ch;
if(ch == '<')
{
bool in_quote;
got_name = got_key = in_quote = false;
-
- // std::cout << "ParseLine(data, '" << line << "', " << linenumber << ", stream)" << std::endl;
+
+ //std::cout << "ParseLine(data, '" << line << "', " << linenumber << ", stream)" << std::endl;
for(std::string::iterator c = line.begin(); c != line.end(); c++)
{
current_value += *c;
continue;
}
+ else if ((*c == '\n') && (in_quote))
+ {
+ /* Got a 'real' \n, treat it as part of the value */
+ current_value += '\n';
+ continue;
+ }
+ else if ((*c == '\r') && (in_quote))
+ /* Got a \r, drop it */
+ continue;
+
if (*c == '"')
{
if (!in_quote)
{
/* Leaving quotes, we have the value */
results.push_back(KeyVal(current_key, current_value));
-
+
// std::cout << "<" << tagname << ":" << current_key << "> " << current_value << std::endl;
in_quote = false;
return LoadConf(target, newfile, errorstream);
}
-bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length)
+bool ServerConfig::ConfValue(ConfigDataHash &target, const char* tag, const char* var, int index, char* result, int length, bool allow_linefeeds)
{
std::string value;
- bool r = ConfValue(target, std::string(tag), std::string(var), index, value);
+ bool r = ConfValue(target, std::string(tag), std::string(var), index, value, allow_linefeeds);
strlcpy(result, value.c_str(), length);
return r;
}
-bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result)
+bool ServerConfig::ConfValue(ConfigDataHash &target, const std::string &tag, const std::string &var, int index, std::string &result, bool allow_linefeeds)
{
ConfigDataHash::size_type pos = index;
if((pos >= 0) && (pos < target.count(tag)))
{
- ConfigDataHash::const_iterator iter = target.find(tag);
-
+ ConfigDataHash::iterator iter = target.find(tag);
+
for(int i = 0; i < index; i++)
iter++;
-
- for(KeyValList::const_iterator j = iter->second.begin(); j != iter->second.end(); j++)
+
+ for(KeyValList::iterator j = iter->second.begin(); j != iter->second.end(); j++)
{
if(j->first == var)
{
- result = j->second;
- return true;
+ if ((!allow_linefeeds) && (j->second.find('\n') != std::string::npos))
+ {
+ ServerInstance->Log(DEFAULT, "Value of <" + tag + ":" + var+ "> contains a linefeed, and linefeeds in this value are not permitted -- stripped to spaces.");
+ for (std::string::iterator n = j->second.begin(); n != j->second.end(); n++)
+ if (*n == '\n')
+ *n = ' ';
+ }
+ else
+ {
+ result = j->second;
+ return true;
+ }
}
}
}
{
ServerInstance->Log(DEBUG, "ConfValue got an out-of-range index %d, there are only %d occurences of %s", pos, target.count(tag), tag.c_str());
}
-
+
return false;
}