]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/inspircd_io.cpp
Removed lowercasing of servername on validation
[user/henk/code/inspircd.git] / src / inspircd_io.cpp
index 4fa87a5f18392776cd7920cc8488b2b46ab2a712..f4ab7ce071ea360ac33e41101015453cc51b528d 100644 (file)
@@ -42,6 +42,8 @@ extern int MODCOUNT;
 extern std::vector<Module*> modules;
 extern std::vector<ircd_module*> factory;
 
+std::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;
+
 ServerConfig::ServerConfig()
 {
        this->ClearStack();
@@ -260,7 +262,7 @@ bool ValidateServerName(const char* tag, const char* value, void* data)
                log(DEFAULT,"WARNING: <server:name> '%s' is not a fully-qualified domain name. Changed to '%s%c'",x,x,'.');
                charlcat(x,'.',MAXBUF);
        }
-       strlower(x);
+       //strlower(x);
        return true;
 }
 
@@ -316,16 +318,210 @@ bool ValidateRules(const char* tag, const char* value, void* data)
        return true;
 }
 
+/* Callback called before processing the first <connect> tag
+ */
+bool InitConnect(const char* tag)
+{
+       log(DEFAULT,"Reading connect classes...");
+       Config->Classes.clear();
+       return true;
+}
 
-void ServerConfig::Read(bool bail, userrec* user)
+/* Callback called to process a single <connect> tag
+ */
+bool DoConnect(const char* tag, char** entries, void** values, int* types)
 {
-       char debug[MAXBUF];
-       char CM1[MAXBUF],CM2[MAXBUF];
-       char ServName[MAXBUF],Value[MAXBUF];
-       char dataline[1024];
        ConnectClass c;
-       std::stringstream errstr;
+       char* allow = (char*)values[0]; /* Yeah, there are a lot of values. Live with it. */
+       char* deny = (char*)values[1];
+       char* password = (char*)values[2];
+       int* timeout = (int*)values[3];
+       int* pingfreq = (int*)values[4];
+       int* flood = (int*)values[5];
+       int* threshold = (int*)values[6];
+       int* sendq = (int*)values[7];
+       int* recvq = (int*)values[8];
+       int* localmax = (int*)values[9];
+       int* globalmax = (int*)values[10];
+
+       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;
+                       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;
+               Config->Classes.push_back(c);
+       }
+       else
+       {
+               c.host = deny;
+               c.type = CC_DENY;
+               Config->Classes.push_back(c);
+               log(DEBUG,"Read connect class type DENY, host=%s",deny);
+       }
+
+       return true;
+}
+
+/* Callback called when there are no more <connect> tags
+ */
+bool DoneConnect(const char* tag)
+{
+       log(DEBUG,"DoneConnect called for tag: %s",tag);
+       return true;
+}
+
+/* Callback called before processing the first <uline> tag
+ */
+bool InitULine(const char* tag)
+{
+       Config->ulines.clear();
+       return true;
+}
+
+/* Callback called to process a single <uline> tag
+ */
+bool DoULine(const char* tag, char** entries, void** values, int* types)
+{
+       char* server = (char*)values[0];
+       log(DEBUG,"Read ULINE '%s'",server);
+       Config->ulines.push_back(server);
+       return true;
+}
+
+/* Callback called when there are no more <uline> tags
+ */
+bool DoneULine(const char* tag)
+{
+       return true;
+}
+
+/* Callback called before processing the first <module> tag
+ */
+bool InitModule(const char* tag)
+{
+       old_module_names.clear();
+       new_module_names.clear();
+       added_modules.clear();
+       removed_modules.clear();
+       for (std::vector<std::string>::iterator t = Config->module_names.begin(); t != Config->module_names.end(); t++)
+       {
+               old_module_names.push_back(*t);
+       }
+       return true;
+}
+
+/* Callback called to process a single <module> tag
+ */
+bool DoModule(const char* tag, char** entries, void** values, int* types)
+{
+       char* modname = (char*)values[0];
+       new_module_names.push_back(modname);
+       return true;
+}
+
+/* Callback called when there are no more <module> tags
+ */
+bool DoneModule(const char* tag)
+{
+       // now create a list of new modules that are due to be loaded
+       // and a seperate list of modules which are due to be unloaded
+       for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)
+       {
+               bool added = true;
+
+               for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)
+               {
+                       if (*old == *_new)
+                               added = false;
+               }
+
+               if (added)
+                       added_modules.push_back(*_new);
+       }
+
+       for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)
+       {
+               bool removed = true;
+               for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)
+               {
+                       if (*newm == *oldm)
+                               removed = false;
+               }
+
+               if (removed)
+                       removed_modules.push_back(*oldm);
+       }
+       return true;
+}
+
+/* Callback called before processing the first <banlist> tag
+ */
+bool InitMaxBans(const char* tag)
+{
+       Config->maxbans.clear();
+       return true;
+}
+
+/* Callback called to process a single <banlist> tag
+ */
+bool DoMaxBans(const char* tag, char** entries, void** values, int* types)
+{
+       char* channel = (char*)values[0];
+       int* limit = (int*)values[1];
+       Config->maxbans[channel] = *limit;
+       return true;
+}
 
+/* Callback called when there are no more <banlist> tags.
+ */
+bool DoneMaxBans(const char* tag)
+{
+       return true;
+}
+
+void ServerConfig::Read(bool bail, userrec* user)
+{
+       char debug[MAXBUF];             /* Temporary buffer for debugging value */
+       char dataline[1024];            /* Temporary buffer for error output */
+       char* convert;                  /* Temporary buffer used for reading singular values into */
+       char* data[12];                 /* Temporary buffers for reading multiple occurance tags into */
+       void* ptr[12];                  /* Temporary pointers for passing to callbacks */
+       int r_i[12];                    /* Temporary array for casting */
+       int rem = 0, add = 0;           /* Number of modules added, number of modules removed */
+       std::stringstream errstr;       /* String stream containing the error output */
+
+       /* These tags MUST occur and must ONLY occur once in the config file */
+       static char* Once[] = { "server", "admin", "files", "power", "options", "pid", NULL };
+
+       /* These tags can occur ONCE or not at all */
        static InitialConfig Values[] = {
                {"options",     "softlimit",            &this->SoftLimit,               DT_INTEGER, ValidateSoftLimit},
                {"options",     "somaxconn",            &this->MaxConn,                 DT_INTEGER, ValidateMaxConn},
@@ -356,11 +552,74 @@ void ServerConfig::Read(bool bail, userrec* user)
                {"options",     "hidebans",             &this->HideBans,                DT_BOOLEAN, NoValidation},
                {"options",     "hidewhois",            &this->HideWhoisServer,         DT_CHARPTR, NoValidation},
                {"options",     "tempdir",              &this->TempDir,                 DT_CHARPTR, ValidateTempDir},
+               {"pid",         "file",                 &this->PID,                     DT_CHARPTR, NoValidation},
                {NULL}
        };
-       
+
+       /* These tags can occur multiple times, and therefore they have special code to read them
+        * which is different to the code for reading the singular tags listed above.
+        */
+       static MultiConfig MultiValues[] = {
+
+               {"connect",
+                               {"allow",       "deny",         "password",     "timeout",      "pingfreq",     "flood",
+                               "threshold",    "sendq",        "recvq",        "localmax",     "globalmax",    NULL},
+                               {DT_CHARPTR,    DT_CHARPTR,     DT_CHARPTR,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER,
+                                DT_INTEGER,    DT_INTEGER,     DT_INTEGER,     DT_INTEGER,     DT_INTEGER},
+                               InitConnect, DoConnect, DoneConnect},
+
+               {"uline",
+                               {"server",      NULL},
+                               {DT_CHARPTR},
+                               InitULine,DoULine,DoneULine},
+
+               {"banlist",
+                               {"chan",        "limit",        NULL},
+                               {DT_CHARPTR,    DT_INTEGER},
+                               InitMaxBans, DoMaxBans, DoneMaxBans},
+
+               {"module",
+                               {"name",        NULL},
+                               {DT_CHARPTR},
+                               InitModule, DoModule, DoneModule},
+
+               {"badip",
+                               {"reason",      "ipmask",       NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitXLine, DoZLine, DoneXLine},
+
+               {"badnick",
+                               {"reason",      "nick",         NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitXLine, DoQLine, DoneXLine},
+
+               {"badhost",
+                               {"reason",      "host",         NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitXLine, DoKLine, DoneXLine},
+
+               {"exception",
+                               {"reason",      "host",         NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitXLine, DoELine, DoneXLine},
+
+               {"type",
+                               {"name",        "classes",      NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitTypes, DoType, DoneClassesAndTypes},
+
+               {"class",
+                               {"name",        "commands",     NULL},
+                               {DT_CHARPTR,    DT_CHARPTR},
+                               InitClasses, DoClass, DoneClassesAndTypes},
+
+               {NULL}
+       };
+
        include_stack.clear();
 
+       /* Initially, load the config into memory, bail if there are errors
+        */
        if (!LoadConf(CONFIG_FILE,&Config->config_f,&errstr))
        {
                errstr.seekg(0);
@@ -396,15 +655,14 @@ void ServerConfig::Read(bool bail, userrec* user)
                }
        }
 
-       /* Check we dont have more than one of singular tags
+       /* Check we dont have more than one of singular tags, or any of them missing
         */
-       if (!CheckOnce("server",bail,user) || !CheckOnce("admin",bail,user) || !CheckOnce("files",bail,user)
-               || !CheckOnce("power",bail,user) || !CheckOnce("options",bail,user) || !CheckOnce("pid",bail,user))
-       {
-               return;
-       }
+       for (int Index = 0; Once[Index]; Index++)
+               if (!CheckOnce(Once[Index],bail,user))
+                       return;
 
-       char* convert;
+       /* 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++)
        {
                int* val_i = (int*) Values[Index].val;
@@ -437,161 +695,64 @@ void ServerConfig::Read(bool bail, userrec* user)
                Values[Index].validation_function(Values[Index].tag, Values[Index].value, Values[Index].val);
        }
 
-       log(DEFAULT,"Reading connect classes...");
-       Classes.clear();
+       /* Claim memory for use when reading multiple tags
+        */
+       for (int n = 0; n < 12; n++)
+               data[n] = new char[MAXBUF];
 
-       for (int i = 0; i < ConfValueEnum("connect",&Config->config_f); i++)
+       /* 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++)
        {
-               *Value = 0;
-               ConfValue("connect","allow",i,Value,&Config->config_f);
-               if (*Value)
-               {
-                       c.host = Value;
-                       c.type = CC_ALLOW;
-                       *Value = 0;
-                       ConfValue("connect","password",i,Value,&Config->config_f);
-                       c.pass = Value;
-                       c.registration_timeout = ConfValueInteger("connect","timeout",i,&Config->config_f); // default is 2 minutes
-                       c.pingtime = ConfValueInteger("connect","pingfreq",i,&Config->config_f);
-                       c.flood = ConfValueInteger("connect","flood",i,&Config->config_f);
-                       c.threshold = ConfValueInteger("connect","threshold",i,&Config->config_f);
-                       c.sendqmax = ConfValueInteger("connect","sendq",i,&Config->config_f);
-                       c.recvqmax = ConfValueInteger("connect","recvq",i,&Config->config_f);
-                       c.maxlocal = ConfValueInteger("connect","localmax",i,&Config->config_f);
-                       c.maxglobal = ConfValueInteger("connect","globalmax",i,&Config->config_f);
-
-                       
-                       if (c.maxlocal == 0)
-                       {
-                               c.maxlocal = 3;
-                       }
+               MultiValues[Index].init_function(MultiValues[Index].tag);
 
-                       if (c.maxglobal == 0)
-                       {
-                               c.maxglobal = 3;
-                       }
+               int number_of_tags = ConfValueEnum((char*)MultiValues[Index].tag, &this->config_f);
 
-                       if (c.threshold == 0)
+               for (int tagnum = 0; tagnum < number_of_tags; tagnum++)
+               {
+                       for (int valuenum = 0; MultiValues[Index].items[valuenum]; valuenum++)
                        {
-                               c.threshold = 1;
-                               c.flood = 999;
-                               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());
-                       }
+                               ConfValue((char*)MultiValues[Index].tag,(char*)MultiValues[Index].items[valuenum], tagnum, data[valuenum], &this->config_f);
 
-                       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;
+                               switch (MultiValues[Index].datatype[valuenum])
+                               {
+                                       case DT_CHARPTR:
+                                               ptr[valuenum] = data[valuenum];
+                                       break;
+                                       case DT_INTEGER:
+                                               r_i[valuenum] = atoi(data[valuenum]);
+                                               ptr[valuenum] = &r_i[valuenum];
+                                       break;
+                                       case DT_BOOLEAN:
+                                               r_i[valuenum] = ((*data[valuenum] == tolower('y')) || (*data[valuenum] == tolower('t')) || (*data[valuenum] == '1'));
+                                               ptr[valuenum] = &r_i[valuenum];
+                                       break;
+                                       default:
+                                       break;
+                               }
                        }
-
-                       Classes.push_back(c);
+                       MultiValues[Index].validation_function(MultiValues[Index].tag, (char**)MultiValues[Index].items, ptr, MultiValues[Index].datatype);
                }
-               else
-               {
-                       ConfValue("connect","deny",i,Value,&Config->config_f);
-                       c.host = Value;
-                       c.type = CC_DENY;
-                       Classes.push_back(c);
-                       log(DEBUG,"Read connect class type DENY, host=%s",c.host.c_str());
-               }
-       }
-
-       Config->ulines.clear();
 
-       for (int i = 0; i < ConfValueEnum("uline",&Config->config_f); i++)
-       {   
-               ConfValue("uline","server",i,ServName,&Config->config_f);
-               {
-                       log(DEBUG,"Read ULINE '%s'",ServName);
-                       Config->ulines.push_back(ServName);
-               }
+               MultiValues[Index].finish_function(MultiValues[Index].tag);
        }
 
-       maxbans.clear();
-
-       for (int count = 0; count < Config->ConfValueEnum("banlist",&Config->config_f); count++)
-       {
-               Config->ConfValue("banlist","chan",count,CM1,&Config->config_f);
-               Config->ConfValue("banlist","limit",count,CM2,&Config->config_f);
-               maxbans[CM1] = atoi(CM2);
-       }
-
-       ReadClassesAndTypes();
-       log(DEFAULT,"Reading K lines,Q lines and Z lines from config...");
-       read_xline_defaults();
-       log(DEFAULT,"Applying K lines, Q lines and Z lines...");
-       apply_lines(APPLY_ALL);
+       /* Free any memory we claimed
+        */
+       for (int n = 0; n < 12; n++)
+               delete[] data[n];
 
-       ConfValue("pid","file",0,Config->PID,&Config->config_f);
        // write once here, to try it out and make sure its ok
        WritePID(Config->PID);
 
        log(DEFAULT,"Done reading configuration file, InspIRCd is now starting.");
+
+       /* If we're rehashing, let's load any new modules, and unload old ones
+        */
        if (!bail)
        {
-               log(DEFAULT,"Adding and removing modules due to rehash...");
-
-               std::vector<std::string> old_module_names, new_module_names, added_modules, removed_modules;
-
-               // store the old module names
-               for (std::vector<std::string>::iterator t = module_names.begin(); t != module_names.end(); t++)
-               {
-                       old_module_names.push_back(*t);
-               }
-
-               // get the new module names
-               for (int count2 = 0; count2 < ConfValueEnum("module",&Config->config_f); count2++)
-               {
-                       ConfValue("module","name",count2,Value,&Config->config_f);
-                       new_module_names.push_back(Value);
-               }
-
-               // now create a list of new modules that are due to be loaded
-               // and a seperate list of modules which are due to be unloaded
-               for (std::vector<std::string>::iterator _new = new_module_names.begin(); _new != new_module_names.end(); _new++)
-               {
-                       bool added = true;
-
-                       for (std::vector<std::string>::iterator old = old_module_names.begin(); old != old_module_names.end(); old++)
-                       {
-                               if (*old == *_new)
-                                       added = false;
-                       }
-
-                       if (added)
-                               added_modules.push_back(*_new);
-               }
-
-               for (std::vector<std::string>::iterator oldm = old_module_names.begin(); oldm != old_module_names.end(); oldm++)
-               {
-                       bool removed = true;
-                       for (std::vector<std::string>::iterator newm = new_module_names.begin(); newm != new_module_names.end(); newm++)
-                       {
-                               if (*newm == *oldm)
-                                       removed = false;
-                       }
-
-                       if (removed)
-                               removed_modules.push_back(*oldm);
-               }
-
-               /*
-                * now we have added_modules, a vector of modules to be loaded,
-                * and removed_modules, a vector of modules
-                * to be removed.
-                */
-               int rem = 0, add = 0;
                if (!removed_modules.empty())
                        for (std::vector<std::string>::iterator removing = removed_modules.begin(); removing != removed_modules.end(); removing++)
                        {
@@ -634,7 +795,6 @@ void ServerConfig::Read(bool bail, userrec* user)
        }
 }
 
-
 void Exit (int status)
 {
        if (Config->log_file)
@@ -679,7 +839,7 @@ void Start (void)
        printf("Name concept:\t\t\033[1;32mLord_Zathras\033[0m\n\n");
 }
 
-void WritePID(std::string filename)
+void WritePID(const std::string &filename)
 {
        ofstream outfile(filename.c_str());
        if (outfile.is_open())