]> git.ipfire.org Git - thirdparty/sarg.git/blobdiff - getconf.c
Add support to decompress xz files
[thirdparty/sarg.git] / getconf.c
index c38c9ec92e63ee9bb01ef81a1cf2287ce5ba6f51..8c3060a13e6d7392d43a878db219ca985a21664a 100644 (file)
--- a/getconf.c
+++ b/getconf.c
@@ -1,6 +1,6 @@
 /*
  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
- *                                                            1998, 2012
+ *                                                            1998, 2015
  *
  * SARG donations:
  *      please look at http://sarg.sourceforge.net/donations.php
 
 #include "include/conf.h"
 #include "include/defs.h"
+#include "include/filelist.h"
 
 #define SET_LIST(list) list,sizeof(list)/sizeof(list[0])
 
+//! The configuration file from which the graph option was loaded
+char GraphConfigFile[MAXLEN]="";
+
+//! How many include directives were followed.
+static int IncludeLevel=0;
+
 extern numlist hours, weekdays;
+extern FileListObject AccessLog;
+extern int PerUserLimitsNumber;
+extern struct PerUserLimitStruct PerUserLimits[MAX_USER_LIMITS];
+extern enum PerUserFileCreationEnum PerUserFileCreation;
+extern char ImageDir[MAXLEN];
+extern FileListObject UserAgentLog;
+extern bool UserAgentFromCmdLine;
+extern char StripUserSuffix[MAX_USER_LEN];
+extern int StripSuffixLen;
 
 struct param_list
 {
@@ -49,6 +65,14 @@ struct sort_list
        unsigned long int value;
 };
 
+struct select_list
+{
+       //! The name of the value of the parameter.
+       const char *name;
+       //! The value to assign when the name is selected.
+       int value;
+};
+
 static struct param_list report_type_values[]=
 {
        {"users_sites",REPORT_TYPE_USERS_SITES,0},
@@ -60,6 +84,7 @@ static struct param_list report_type_values[]=
        {"auth_failures",REPORT_TYPE_AUTH_FAILURES,0},
        {"site_user_time_date",REPORT_TYPE_SITE_USER_TIME_DATE,0},
        {"downloads",REPORT_TYPE_DOWNLOADS,0},
+       {"user_agent",REPORT_TYPE_USERAGENT,0},
 };
 
 static struct param_list data_field_values[]=
@@ -80,6 +105,7 @@ static struct param_list topuserfields_values[]=
        {"NUM",TOPUSERFIELDS_NUM,0},
        {"DATE_TIME",TOPUSERFIELDS_DATE_TIME,0},
        {"USERID",TOPUSERFIELDS_USERID,0},
+       {"USERIP",TOPUSERFIELDS_USERIP,0},
        {"CONNECT",TOPUSERFIELDS_CONNECT,0},
        {"BYTES",TOPUSERFIELDS_BYTES,0},
        {"%BYTES",TOPUSERFIELDS_SETYB,0},
@@ -174,6 +200,7 @@ struct sort_list topsite_sort[]=
        {"BYTES",TOPSITE_SORT_BYTES},
        {"CONNECT",TOPSITE_SORT_CONNECT},
        {"TIME",TOPSITE_SORT_TIME},
+       {"USER",TOPSITE_SORT_USER},
 };
 
 struct sort_list user_sort[]=
@@ -184,6 +211,12 @@ struct sort_list user_sort[]=
        {"TIME",USER_SORT_TIME},
 };
 
+static struct select_list per_user_limit_create_file[]=
+{
+       {"always",PUFC_Always}, //always create an empty file
+       {"as_required",PUFC_AsRequired}, //create the file if necessary (no empty file is created)
+};
+
 static int is_param(const char *param,const char *buf)
 {
        int plen;
@@ -206,7 +239,7 @@ static int getparam_string(const char *param,char *buf,char *value,int value_siz
        while (*buf && (unsigned char)*buf<=' ') buf++;
 
        if (strlen(buf)>=value_size) {
-               debuga(_("The string value of parameter \"%s\" is too long\n"),param);
+               debuga(__FILE__,__LINE__,_("The string value of parameter \"%s\" is too long\n"),param);
                exit(EXIT_FAILURE);
        }
        strcpy(value,buf);
@@ -214,6 +247,31 @@ static int getparam_string(const char *param,char *buf,char *value,int value_siz
        return(1);
 }
 
+/*!
+ * Get a pointer to the beginning of the string value defined by the
+ * parameter. The returned value is NULL if the buffer doesn't contain
+ * the parameter.
+ *
+ * \param param The parameter to look for.
+ * \param buf The buffer containing the line read from the configuration
+ * file.
+ *
+ * \return A pointer to the beginning of the parameter value or NULL if
+ * the line is not for the requested parameter.
+ */
+static char *getparam_stringptr(const char *param,char *buf)
+{
+       int plen;
+
+       plen=strlen(param);
+       if (strncmp(buf,param,plen) != 0) return(NULL);
+       buf+=plen;
+       if ((unsigned char)*buf>' ') return(NULL);
+       while (*buf && (unsigned char)*buf<=' ') buf++;
+
+       return(buf);
+}
+
 static int getparam_quoted(const char *param,char *buf,char *value,int value_size)
 {
        int plen;
@@ -226,7 +284,7 @@ static int getparam_quoted(const char *param,char *buf,char *value,int value_siz
        while (*buf && (unsigned char)*buf<=' ') buf++;
 
        if (*buf != '\"') {
-               debuga(_("Missing double quote after parameter \"%s\"\n"),param);
+               debuga(__FILE__,__LINE__,_("Missing double quote after parameter \"%s\"\n"),param);
                exit(EXIT_FAILURE);
        }
        buf++;
@@ -238,7 +296,7 @@ static int getparam_quoted(const char *param,char *buf,char *value,int value_siz
        value[i]='\0';
 
        if (*buf != '\"') {
-               debuga(_("Missing double quote after parameter \"%s\" or value is more than %d bytes long\n"),param,value_size);
+               debuga(__FILE__,__LINE__,_("Missing double quote after parameter \"%s\" or value is more than %d bytes long\n"),param,value_size);
                exit(EXIT_FAILURE);
        }
        fixnone(value);
@@ -259,11 +317,11 @@ static int getparam_2words(const char *param,char *buf,char *word1,int word1_siz
        for (i=0 ; i<word1_size && *buf && (unsigned char)*buf>' ' ; i++)
                word1[i]=*buf++;
        if (i>=word1_size) {
-               debuga(_("The first word of parameter \"%s\" is more than %d bytes long\n"),param,word1_size-1);
+               debuga(__FILE__,__LINE__,_("The first word of parameter \"%s\" is more than %d bytes long\n"),param,word1_size-1);
                exit(EXIT_FAILURE);
        }
        if (*buf!=' ') {
-               debuga(_("Missing second word for parameter \"%s\"\n"),param);
+               debuga(__FILE__,__LINE__,_("Missing second word for parameter \"%s\"\n"),param);
                exit(EXIT_FAILURE);
        }
        word1[i]=0;
@@ -273,7 +331,7 @@ static int getparam_2words(const char *param,char *buf,char *word1,int word1_siz
        for (i=0 ; i<word2_size && *buf && (unsigned char)*buf>' ' ; i++)
                word2[i]=*buf++;
        if (i>=word2_size) {
-               debuga(_("The second word of parameter \"%s\" is more than %d bytes long\n"),param,word2_size-1);
+               debuga(__FILE__,__LINE__,_("The second word of parameter \"%s\" is more than %d bytes long\n"),param,word2_size-1);
                exit(EXIT_FAILURE);
        }
        word2[i]=0;
@@ -296,7 +354,7 @@ static int getparam_int(const char *param,char *buf,int *value)
 
        next=0;
        if (sscanf(buf,"%d%n",value,&next) != 1 || (unsigned char)buf[next] > ' ') {
-               debuga(_("The integer value of parameter \"%s\" is invalid\n"),param);
+               debuga(__FILE__,__LINE__,_("The integer value of parameter \"%s\" is invalid\n"),param);
                exit(EXIT_FAILURE);
        }
        return(1);
@@ -348,11 +406,11 @@ static int getparam_list(const char *param,struct param_list *options,int noptio
                }
                for (i=0 ; i<noptions && strcasecmp(buf,options[i].name) ; i++);
                if (i>=noptions) {
-                       debuga(_("Unknown value \"%s\" for parameter \"%s\"\n"),buf,param);
+                       debuga(__FILE__,__LINE__,_("Unknown value \"%s\" for parameter \"%s\"\n"),buf,param);
                        exit(EXIT_FAILURE);
                }
                if ((*value & options[i].exclude)!=0) {
-                       debuga(_("Value \"%s\" conflicts with other selected values for parameter \"%s\"\n"),buf,param);
+                       debuga(__FILE__,__LINE__,_("Value \"%s\" conflicts with other selected values for parameter \"%s\"\n"),buf,param);
                        exit(EXIT_FAILURE);
                }
                *value|=options[i].value;
@@ -383,7 +441,7 @@ static int getparam_sort(const char *param,struct sort_list *options,int noption
        }
        for (i=0 ; i<noptions && strcasecmp(buf,options[i].name) ; i++);
        if (i>=noptions) {
-               debuga(_("Unknown sort criterion \"%s\" for parameter \"%s\"\n"),buf,param);
+               debuga(__FILE__,__LINE__,_("Unknown sort criterion \"%s\" for parameter \"%s\"\n"),buf,param);
                exit(EXIT_FAILURE);
        }
        *value=options[i].value;
@@ -398,7 +456,7 @@ static int getparam_sort(const char *param,struct sort_list *options,int noption
                if (strcasecmp(order,"reverse")==0 || strcasecmp(order,"D")==0) {
                        *value|=SORT_REVERSE;
                } else if (strcasecmp(order,"normal")!=0 && strcasecmp(order,"A")!=0) {
-                       debuga(_("Unknown sort order \"%s\" for parameter \"%s\"\n"),order,param);
+                       debuga(__FILE__,__LINE__,_("Unknown sort order \"%s\" for parameter \"%s\"\n"),order,param);
                        exit(EXIT_FAILURE);
                }
        }
@@ -407,17 +465,139 @@ static int getparam_sort(const char *param,struct sort_list *options,int noption
        return(1);
 }
 
-static void parmtest(char *buf)
+static int getparam_select(const char *param,struct select_list *options,int noptions,char *buf,int *value)
+{
+       int plen;
+       char *str;
+       int i;
+
+       plen=strlen(param);
+       if (strncmp(buf,param,plen) != 0) return(0);
+       buf+=plen;
+       if ((unsigned char)*buf>' ') return(0);
+       while (*buf && (unsigned char)*buf<=' ') buf++;
+
+       str=buf;
+       while (*buf && (unsigned char)*buf>' ' && *buf!=';') buf++;
+       *buf='\0';
+       for (i=0 ; i<noptions && strcasecmp(str,options[i].name) ; i++);
+       if (i>=noptions) {
+               debuga(__FILE__,__LINE__,_("Unknown value \"%s\" for parameter \"%s\"\n"),str,param);
+               exit(EXIT_FAILURE);
+       }
+       *value=options[i].value;
+       return(1);
+}
+
+static int getparam_userlimit(const char *param,char *buf)
+{
+       int plen;
+       char *file_begin,*file_end;
+       int limit;
+       int digit;
+       char *str;
+       int i;
+       enum PerUserOutputEnum output;
+       const struct
+       {
+               const char *name;
+               enum PerUserOutputEnum value;
+       } output_types[]=
+       {
+               {"id",PUOE_UserId},
+               {"ip",PUOE_UserIp},
+       };
+
+       plen=strlen(param);
+       if (strncmp(buf,param,plen) != 0) return(0);
+       buf+=plen;
+       if ((unsigned char)*buf>' ') return(0);
+       while (*buf && (unsigned char)*buf<=' ') buf++;
+
+       /*
+       options are made of a file name, an integer limit and an optional
+       integer flag. The file name may contain spaces. We keep searching
+       until a valid number is found after a space.
+       */
+       file_begin=buf;
+       do {
+               while (*buf && (unsigned char)*buf>' ') buf++;
+               if (*buf!=' ') {
+                       debuga(__FILE__,__LINE__,_("Missing limit in per_user_limit\n"));
+                       exit(EXIT_FAILURE);
+               }
+               file_end=buf;
+               while (*buf && (unsigned char)*buf<=' ') buf++;
+               limit=0;
+               while (*buf && isdigit(*buf)) {
+                       digit=*buf-'0';
+                       if (limit>=(INT_MAX-digit)/10) break;
+                       limit=limit*10+digit;
+                       buf++;
+               }
+       } while (*buf && *buf!=' ');
+
+       output=PUOE_UserId;
+       if (*buf==' ') {
+               while (*buf && (unsigned char)*buf<=' ') buf++;
+               str=buf;
+               while (*buf && (unsigned char)*buf>' ') buf++;
+               *buf='\0';
+               for (i=sizeof(output_types)/sizeof(output_types[0])-1 ; i>=0 ; i--)
+                       if (strcasecmp(output_types[i].name,str)==0) {
+                               output=output_types[i].value;
+                               break;
+                       }
+               if (i<0) {
+                       debuga(__FILE__,__LINE__,_("Invalid output type in per_user_limit\n"));
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       if (PerUserLimitsNumber>=MAX_USER_LIMITS) {
+               debuga(__FILE__,__LINE__,_("Too many per_user_limit\n"));
+               exit(EXIT_FAILURE);
+       }
+       *file_end='\0';
+       safe_strcpy(PerUserLimits[PerUserLimitsNumber].File,file_begin,sizeof(PerUserLimits[PerUserLimitsNumber].File));
+       PerUserLimits[PerUserLimitsNumber].Limit=limit;
+       PerUserLimits[PerUserLimitsNumber].Output=output;
+       PerUserLimitsNumber++;
+
+       return(1);
+}
+
+static void ccharset(char *CharSet)
+{
+       if (strcmp(CharSet,"Latin2") == 0) strcpy(CharSet,"ISO-8859-2");
+       else if (strcmp(CharSet,"Latin3") == 0) strcpy(CharSet,"ISO-8859-3");
+       else if (strcmp(CharSet,"Latin4") == 0) strcpy(CharSet,"ISO-8859-4");
+       else if (strcmp(CharSet,"Cyrillic") == 0) strcpy(CharSet,"ISO-8859-5");
+       else if (strcmp(CharSet,"Arabic") == 0) strcpy(CharSet,"ISO-8859-6");
+       else if (strcmp(CharSet,"Greek") == 0) strcpy(CharSet,"ISO-8859-7");
+       else if (strcmp(CharSet,"Hebrew") == 0) strcpy(CharSet,"ISO-8859-8");
+       else if (strcmp(CharSet,"Latin5") == 0) strcpy(CharSet,"ISO-8859-9");
+       else if (strcmp(CharSet,"Latin6") == 0) strcpy(CharSet,"ISO-8859-10");
+       else if (strcmp(CharSet,"Japan") == 0) strcpy(CharSet,"EUC-JP");
+       else if (strcmp(CharSet,"Koi8-r") == 0) strcpy(CharSet,"KOI8-R");
+       /*
+        * Any other encoding name is left unchanged.
+        */
+       return;
+}
+
+static void parmtest(char *buf,const char *File)
 {
        char wbuf[2048];
        struct getwordstruct gwarea;
+       int iVal;
 
        while (*buf && (unsigned char)*buf<=' ') buf++;
 
        if(*buf == '#' || *buf == '\0')
                return;
 
-       if(debugz)
+       if(debugz>=LogLevel_Process)
                printf(_("SARG: TAG: %s\n"),buf);
 
        if (getparam_string("background_color",buf,BgColor,sizeof(BgColor))>0) return;
@@ -456,7 +636,9 @@ static void parmtest(char *buf)
 
        if (getparam_quoted("title",buf,Title,sizeof(Title))>0) return;
 
-       if (getparam_bool("resolve_ip",buf,&Ip2Name)>0) return;
+       if (strncasecmp(buf,"resolve_ip",10)==0) {
+               if (ip2name_config(buf+10)>0) return;
+       }
 
        if (getparam_bool("user_ip",buf,&UserIp)>0) return;
 
@@ -465,17 +647,16 @@ static void parmtest(char *buf)
        if (is_param("date_format",buf)) {
                getword_start(&gwarea,buf);
                if (getword_multisep(wbuf,sizeof(wbuf),&gwarea,' ')<0) {
-                       debuga(_("Maybe you have a broken record or garbage in \"date_format\" parameter\n"));
+                       debuga(__FILE__,__LINE__,_("Invalid record in \"date_format\" parameter\n"));
                        exit(EXIT_FAILURE);
                }
-               strncpy(DateFormat,gwarea.current,1);
-               fixnone(DateFormat);
+               DateFormat=gwarea.current[0];
                return;
        }
 
        if (is_param("hours",buf)) {
                if( getnumlist( buf, &hours, 24, 24 ) ) {
-                       debuga(_("Error: Invalid syntax in hours tag!\n"));
+                       debuga(__FILE__,__LINE__,_("Error: Invalid syntax in hours tag!\n"));
                        exit( 1 );
                }
                return;
@@ -483,7 +664,7 @@ static void parmtest(char *buf)
 
        if (is_param("weekdays",buf)) {
                if( getnumlist( buf, &weekdays, 7, 7 ) ) {
-                       debuga(_("Error: Invalid syntax in weekdays tag!\n"));
+                       debuga(__FILE__,__LINE__,_("Error: Invalid syntax in weekdays tag!\n"));
                        exit( 1 );
                }
                return;
@@ -495,12 +676,13 @@ static void parmtest(char *buf)
 
        if (is_param("access_log",buf)>0) {
                if (AccessLogFromCmdLine==0) {
-                       if (NAccessLog>=MAXLOGS) {
-                               debuga(_("Too many log files in configuration file\n"));
+                       char *FileName=getparam_stringptr("access_log",buf);
+                       if (!AccessLog)
+                               AccessLog=FileList_Create();
+                       if (!FileList_AddFile(AccessLog,FileName)) {
+                               debuga(__FILE__,__LINE__,_("Not enough memory to store the input log file names\n"));
                                exit(EXIT_FAILURE);
                        }
-                       getparam_string("access_log",buf,AccessLog[NAccessLog],MAX_LOG_FILELEN);
-                       NAccessLog++;
                }
                return;
        }
@@ -508,7 +690,7 @@ static void parmtest(char *buf)
        if (is_param("redirector_log",buf)>0) {
                if (RedirectorLogFromCmdLine==0) {
                        if (NRedirectorLogs>=MAX_REDIRECTOR_LOGS) {
-                               debuga(_("Too many redirector log files in configuration file\n"));
+                               debuga(__FILE__,__LINE__,_("Too many redirector log files in configuration file\n"));
                                exit(EXIT_FAILURE);
                        }
                        getparam_string("redirector_log",buf,RedirectorLogs[NRedirectorLogs],MAX_REDIRECTOR_FILELEN);
@@ -517,7 +699,18 @@ static void parmtest(char *buf)
                return;
        }
 
-       if (getparam_string("useragent_log",buf,UserAgentLog,sizeof(UserAgentLog))>0) return;
+       if (is_param("useragent_log",buf)>0) {
+               if (!UserAgentFromCmdLine) {
+                       if (!UserAgentLog)
+                               UserAgentLog=FileList_Create();
+                       char *FileName=getparam_stringptr("useragent_log",buf);
+                       if (!FileList_AddFile(UserAgentLog,FileName)) {
+                               debuga(__FILE__,__LINE__,_("Not enough memory to store a user agent file name\n"));
+                               exit(EXIT_FAILURE);
+                       }
+               }
+               return;
+       }
 
        if (getparam_string("exclude_hosts",buf,ExcludeHosts,sizeof(ExcludeHosts))>0) return;
 
@@ -537,8 +730,10 @@ static void parmtest(char *buf)
 
        if (getparam_string("output_email",buf,OutputEmail,sizeof(OutputEmail))>0) return;
 
-       if (getparam_2words("per_user_limit",buf,PerUserLimitFile,sizeof(PerUserLimitFile),wbuf,sizeof(wbuf))>0) {
-               PerUserLimit=atoi(wbuf);
+       if (getparam_userlimit("per_user_limit",buf)>0) return;
+
+       if (getparam_select("per_user_limit_file_create",SET_LIST(per_user_limit_create_file),buf,&iVal)>0) {
+               PerUserFileCreation=(enum PerUserFileCreationEnum)iVal;
                return;
        }
 
@@ -605,6 +800,8 @@ static void parmtest(char *buf)
 
        if (getparam_bool("show_read_statistics",buf,&ShowReadStatistics)>0) return;
 
+       if (getparam_bool("show_read_percent",buf,&ShowReadPercent)>0) return;
+
        if (getparam_list("topuser_fields",SET_LIST(topuserfields_values),buf,&TopUserFields)>0) return;
 
        if (getparam_bool("bytes_in_sites_users_report",buf,&BytesInSitesUsersReport)>0) return;
@@ -648,18 +845,18 @@ static void parmtest(char *buf)
        if (getparam_bool("user_authentication",buf,&UserAuthentication)>0) return;
 
        if (getparam_string("AuthUserTemplateFile",buf,wbuf,sizeof(wbuf))>0) {
-               char dir[MAXLEN];
-
                if (is_absolute(wbuf)) {
                        if (strlen(wbuf)>=sizeof(AuthUserTemplateFile)) {
-                               debuga(_("Template file name is too long in parameter \"AuthUserTemplateFile\"\n"));
+                               debuga(__FILE__,__LINE__,_("Template file name is too long in parameter \"AuthUserTemplateFile\"\n"));
                                exit(EXIT_FAILURE);
                        }
                        safe_strcpy(AuthUserTemplateFile,wbuf,sizeof(AuthUserTemplateFile));
                } else {
-                       safe_strcpy(dir,ConfigFile,sizeof(dir));
+                       char dir[MAXLEN];
+
+                       safe_strcpy(dir,File,sizeof(dir));
                        if (snprintf(AuthUserTemplateFile,sizeof(AuthUserTemplateFile),"%s/%s",dirname(dir),wbuf)>=sizeof(AuthUserTemplateFile)) {
-                               debuga(_("Template file name is too long in parameter \"AuthUserTemplateFile\"\n"));
+                               debuga(__FILE__,__LINE__,_("Template file name is too long in parameter \"AuthUserTemplateFile\"\n"));
                                exit(EXIT_FAILURE);
                        }
                }
@@ -677,9 +874,10 @@ static void parmtest(char *buf)
        if (getparam_bool("graphs",buf,&Graphs)>0) {
 #ifndef HAVE_GD
                if (Graphs)
-                       debugaz(_("No graphs available as sarg was not compiled with libgd. Set \"graphs\" to \"no\" in %s to disable this warning\n"),
-                               ConfigFile);
+                       debugaz(__FILE__,__LINE__,_("No graphs available as sarg was not compiled with libgd. Set \"graphs\" to \"no\" in %s to disable this warning\n"),
+                               File);
 #endif
+               safe_strcpy(GraphConfigFile,File,sizeof(GraphConfigFile));
                return;
        }
 
@@ -687,7 +885,7 @@ static void parmtest(char *buf)
 
        if (getparam_string("redirector_log_format",buf,RedirectorLogFormat,sizeof(RedirectorLogFormat))>0) return;
        if (getparam_string("squidguard_log_format",buf,RedirectorLogFormat,sizeof(RedirectorLogFormat))>0) {
-               debuga(_("squidguard_log_format is deprecated and has been replaced by redirector_log_format. Please update your configuration file.\n"));
+               debuga(__FILE__,__LINE__,_("squidguard_log_format is deprecated and has been replaced by redirector_log_format. Please update your configuration file.\n"));
                return;
        }
 
@@ -696,19 +894,19 @@ static void parmtest(char *buf)
                /*
                Due to an old bug in sarg before version 2.3, the option was having the opposite action than implied by the name.
                */
-               debuga(_("redirector_ignore_date is deprecated and has been replaced by redirector_filter_out_date that does the action implied by its name as opposed to redirector_ignore_date. Please update your configuration file.\n"));
+               debuga(__FILE__,__LINE__,_("redirector_ignore_date is deprecated and has been replaced by redirector_filter_out_date that does the action implied by its name as opposed to redirector_ignore_date. Please update your configuration file.\n"));
                RedirectorFilterOutDate=!RedirectorFilterOutDate;
                return;
        }
        if (getparam_bool("squidguard_ignore_date",buf,&RedirectorFilterOutDate)>0) {
-               debuga(_("squidguard_ignore_date is deprecated and has been replaced by redirector_filter_out_date that does the action implied by its name as opposed to squidguard_ignore_date. Please update your configuration file.\n"));
+               debuga(__FILE__,__LINE__,_("squidguard_ignore_date is deprecated and has been replaced by redirector_filter_out_date that does the action implied by its name as opposed to squidguard_ignore_date. Please update your configuration file.\n"));
                RedirectorFilterOutDate=!RedirectorFilterOutDate;
                return;
        }
 
        if (getparam_bool("dansguardian_filter_out_date",buf,&DansguardianFilterOutDate)>0) return;
        if (getparam_bool("dansguardian_ignore_date",buf,&DansguardianFilterOutDate)>0) {
-               debuga(_("dansguardian_ignore_date is deprecated and has been replaced by dansguardian_filter_out_date that does the action implied by its name as opposed to dansguardian_ignore_date. Please update your configuration file.\n"));
+               debuga(__FILE__,__LINE__,_("dansguardian_ignore_date is deprecated and has been replaced by dansguardian_filter_out_date that does the action implied by its name as opposed to dansguardian_ignore_date. Please update your configuration file.\n"));
                DansguardianFilterOutDate=!DansguardianFilterOutDate;
                return;
        }
@@ -717,6 +915,11 @@ static void parmtest(char *buf)
 
        if (getparam_list("ntlm_user_format",SET_LIST(ntml_userformat_values),buf,&NtlmUserFormat)>0) return;
 
+       if (getparam_string("strip_user_suffix",buf,StripUserSuffix,sizeof(StripUserSuffix))>0) {
+               StripSuffixLen=strlen(StripUserSuffix);
+               return;
+       }
+
        if (getparam_string("realtime_types",buf,RealtimeTypes,sizeof(RealtimeTypes))>0) return;
 
        if (getparam_list("realtime_unauthenticated_records",SET_LIST(realtime_unauth_values),buf,&RealtimeUnauthRec)>0) return;
@@ -741,12 +944,22 @@ static void parmtest(char *buf)
 
        if (getparam_string("LDAPTargetAttr",buf,LDAPTargetAttr,sizeof(LDAPTargetAttr))>0) return;
 
+       if (getparam_string("LDAPNativeCharset",buf,LDAPNativeCharset,sizeof(LDAPNativeCharset))>0) return;
+
        if (getparam_string("graph_font",buf,GraphFont,sizeof(GraphFont))>0) return;
 
        if (getparam_string("sorttable",buf,SortTableJs,sizeof(SortTableJs))>0) return;
 
        if (getparam_string("hostalias",buf,HostAliasFile,sizeof(HostAliasFile))>0) return;
-       
+
+       if (getparam_string("useralias",buf,UserAliasFile,sizeof(UserAliasFile))>0) return;
+
+       if (getparam_bool("keep_temp_log",buf,&KeepTempLog)>0) return;
+
+       if (getparam_int("max_successive_log_errors",buf,&NumLogSuccessiveErrors)>0) return;
+
+       if (getparam_int("max_total_log_errors",buf,&NumLogTotalErrors)>0) return;
+
        if(strstr(buf,"squid24") != 0) {
                squid24=true;
                return;
@@ -755,44 +968,65 @@ static void parmtest(char *buf)
        if(strstr(buf,"byte_cost") != 0) {
                getword_start(&gwarea,buf);
                if (getword_multisep(wbuf,sizeof(wbuf),&gwarea,' ')<0) {
-                       debuga(_("The \"byte_cost\" parameter of the configuration file is invalid\n"));
+                       debuga(__FILE__,__LINE__,_("The \"byte_cost\" parameter of the configuration file is invalid\n"));
                        exit(EXIT_FAILURE);
                }
                cost=atol(gwarea.current);
                if (getword_multisep(wbuf,sizeof(wbuf),&gwarea,' ')<0) {
-                       debuga(_("The \"byte_cost\" parameter of the configuration file is invalid\n"));
+                       debuga(__FILE__,__LINE__,_("The \"byte_cost\" parameter of the configuration file is invalid\n"));
                        exit(EXIT_FAILURE);
                }
                nocost=my_atoll(gwarea.current);
                return;
        }
 
+       if (getparam_string("image_dir",buf,ImageDir,sizeof(ImageDir))>0) return;
+
        printf(_("SARG: Unknown option %s\n"),buf);
 }
 
-void getconf(void)
+void getconf(const char *File)
 {
        FILE *fp_in;
        char buf[MAXLEN];
+       char IncludeFile[MAXLEN];
+
+       IncludeLevel++;
+       if (debug) {
+               if (IncludeLevel<=1)
+                       debuga(__FILE__,__LINE__,_("Loading configuration file \"%s\"\n"),File);
+               else
+                       debuga(__FILE__,__LINE__,_("Including configuration file \"%s\"\n"),File);
+       }
 
-       if(debug)
-               debuga(_("Loading configuration from %s\n"),ConfigFile);
+       // stop if include files are producing a loop
+       if (IncludeLevel>5) {
+               debuga(__FILE__,__LINE__,_("Too many nested configuration files included in \"%s\""),ConfigFile);
+               exit(EXIT_FAILURE);
+       }
 
-       if ((fp_in = fopen(ConfigFile, "r")) == NULL) {
-               debuga(_("(getconf) Cannot open file %s\n"),ConfigFile);
+       if ((fp_in = fopen(File, "r")) == NULL) {
+               debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),File,strerror(errno));
                exit(EXIT_FAILURE);
        }
 
        while (fgets(buf, sizeof(buf), fp_in) != NULL) {
                fixendofline(buf);
 
-               if(debugm)
-                       printf("SYSCONFDIR %s\n",buf);
+               if (getparam_string("include",buf,IncludeFile,sizeof(IncludeFile))>0) {
+                       getconf(IncludeFile);
+                       continue;
+               }
 
-               parmtest(buf);
+               if (debugz>=LogLevel_Data)
+                       printf("SYSCONFDIR %s\n",buf);
 
+               parmtest(buf,File);
        }
 
-       fclose(fp_in);
-       return;
+       if (fclose(fp_in)==EOF) {
+               debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),File,strerror(errno));
+               exit(EXIT_FAILURE);
+       }
+       IncludeLevel--;
 }