"Fossies" - the Fresh Open Source Software Archive

Member "sarg-2.4.0/redirector.c" (24 Dec 2019, 19536 Bytes) of package /linux/privat/sarg-2.4.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "redirector.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.11_vs_2.4.0.

    1 /*
    2  * SARG Squid Analysis Report Generator      http://sarg.sourceforge.net
    3  *                                                            1998, 2015
    4  *
    5  * SARG donations:
    6  *      please look at http://sarg.sourceforge.net/donations.php
    7  * Support:
    8  *     http://sourceforge.net/projects/sarg/forums/forum/363374
    9  * ---------------------------------------------------------------------
   10  *
   11  *  This program is free software; you can redistribute it and/or modify
   12  *  it under the terms of the GNU General Public License as published by
   13  *  the Free Software Foundation; either version 2 of the License, or
   14  *  (at your option) any later version.
   15  *
   16  *  This program is distributed in the hope that it will be useful,
   17  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   18  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   19  *  GNU General Public License for more details.
   20  *
   21  *  You should have received a copy of the GNU General Public License
   22  *  along with this program; if not, write to the Free Software
   23  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   24  *
   25  */
   26 
   27 #include "include/conf.h"
   28 #include "include/defs.h"
   29 
   30 static char **files_done = NULL;
   31 static int nfiles_done = 0;
   32 
   33 //! The number of invalid lines found in the redirector report.
   34 static int RedirectorErrors=0;
   35 //! The file containing the sorted entries.
   36 static char redirector_sorted[MAXLEN]="";
   37 
   38 extern char StripUserSuffix[MAX_USER_LEN];
   39 extern int StripSuffixLen;
   40 
   41 static void parse_log(FILE *fp_ou,char *buf,int dfrom,int duntil,const struct ReadLogDataStruct *ReadFilter)
   42 {
   43     char leks[5], sep[2], res[MAXLEN];
   44     char hour[15];
   45     char source[128], list[128];
   46     char full_url[MAX_URL_LEN];
   47     const char *url;
   48     char UserBuf[MAX_USER_LEN];
   49     const char *user;
   50     char ip[45];
   51     char userlabel[MAX_USER_LEN];
   52     char IpBuf[MAX_USER_LEN];
   53     long long int lmon, lday, lyear;
   54     int mon, day, year;
   55     int  idata=0;
   56     bool id_is_ip;
   57     struct getwordstruct gwarea;
   58     struct getwordstruct gwarea1;
   59     struct userinfostruct *uinfo;
   60     enum UserProcessError PUser;
   61 
   62     getword_start(&gwarea,buf);
   63     if (RedirectorLogFormat[0] != '\0') {
   64         getword_start(&gwarea1,RedirectorLogFormat);
   65         leks[0]='\0';
   66         if (getword(leks,sizeof(leks),&gwarea1,'#')<0) {
   67             debuga(__FILE__,__LINE__,_("Invalid \"redirector_log_format\" option in your sarg.conf (too many characters before first tag)\n"));
   68             exit(EXIT_FAILURE);
   69         }
   70         year=0;
   71         mon=0;
   72         day=0;
   73         hour[0]='\0';
   74         source[0]='\0';
   75         list[0]='\0';
   76         ip[0]='\0';
   77         UserBuf[0]='\0';
   78         full_url[0]='\0';
   79         while(strcmp(leks,"end") != 0) {
   80             if (getword(leks,sizeof(leks),&gwarea1,'#')<0) {
   81                 debuga(__FILE__,__LINE__,_("Invalid \"redirector_log_format\" option in your sarg.conf (missing # at end of tag)\n"));
   82                 exit(EXIT_FAILURE);
   83             }
   84             if (getword(sep,sizeof(sep),&gwarea1,'#')<0) {
   85                 debuga(__FILE__,__LINE__,_("Invalid \"redirector_log_format\" option in your sarg.conf (too many characters in column separator)\n"));
   86                 exit(EXIT_FAILURE);
   87             }
   88             if (strcmp(leks,"end") != 0) {
   89                 if (getword_limit(res,sizeof(res),&gwarea,sep[0])<0) {
   90                     debuga(__FILE__,__LINE__,_("Parsing of tag \"%s\" in redirector log \"%s\" returned no result\n"),leks,wentp);
   91                     RedirectorErrors++;
   92                     return;
   93                 }
   94                 if (strcmp(leks,"year") == 0) {
   95                     year=atoi(res);
   96                 } else if (strcmp(leks,"mon") == 0) {
   97                     mon=atoi(res);
   98                 } else if (strcmp(leks,"day") == 0) {
   99                     day=atoi(res);
  100                 } else if (strcmp(leks,"hour") == 0) {
  101                     if (strlen(res)>=sizeof(hour)) {
  102                         debuga(__FILE__,__LINE__,_("Hour string too long in redirector log file \"%s\"\n"),wentp);
  103                         RedirectorErrors++;
  104                         return;
  105                     }
  106                     strcpy(hour,res);
  107                 } else if (strcmp(leks,"source") == 0) {
  108                     if (strlen(res)>=sizeof(source)) {
  109                         debuga(__FILE__,__LINE__,_("Banning source name too long in redirector log file \"%s\"\n"),wentp);
  110                         RedirectorErrors++;
  111                         return;
  112                     }
  113                     strcpy(source,res);
  114                 } else if (strcmp(leks,"list") == 0) {
  115                     if (strlen(res)>=sizeof(list)) {
  116                         debuga(__FILE__,__LINE__,_("Banning list name too long in redirector log file \"%s\"\n"),wentp);
  117                         RedirectorErrors++;
  118                         return;
  119                     }
  120                     strcpy(list,res);
  121                 } else if (strcmp(leks,"ip") == 0) {
  122                     if (strlen(res)>=sizeof(ip)) {
  123                         debuga(__FILE__,__LINE__,_("IP address too long in redirector log file \"%s\"\n"),wentp);
  124                         RedirectorErrors++;
  125                         return;
  126                     }
  127                     strcpy(ip,res);
  128                 } else if (strcmp(leks,"user") == 0) {
  129                     if (strlen(res)>=sizeof(UserBuf)) {
  130                         debuga(__FILE__,__LINE__,_("User ID too long in redirector log file \"%s\"\n"),wentp);
  131                         RedirectorErrors++;
  132                         return;
  133                     }
  134                     strcpy(UserBuf,res);
  135                 } else if (strcmp(leks,"url") == 0) {
  136                     /*
  137                      * Don't worry about the url being truncated as we only keep the host name
  138                      * any way...
  139                      */
  140                     safe_strcpy(full_url,res,sizeof(full_url));
  141                 }
  142             }
  143         }
  144     } else {
  145         if (getword_atoll(&lyear,&gwarea,'-')<0 || getword_atoll(&lmon,&gwarea,'-')<0 ||
  146                 getword_atoll(&lday,&gwarea,' ')<0) {
  147             debuga(__FILE__,__LINE__,_("Invalid date in file \"%s\"\n"),wentp);
  148             RedirectorErrors++;
  149             return;
  150         }
  151         year=(int)lyear;
  152         mon=(int)lmon;
  153         day=(int)lday;
  154         if (getword(hour,sizeof(hour),&gwarea,' ')<0) {
  155             debuga(__FILE__,__LINE__,_("Invalid time in file \"%s\"\n"),wentp);
  156             RedirectorErrors++;
  157             return;
  158         }
  159         if (getword_skip(MAXLEN,&gwarea,'(')<0 || getword(source,sizeof(source),&gwarea,'/')<0) {
  160             debuga(__FILE__,__LINE__,_("Invalid redirected source in file \"%s\"\n"),wentp);
  161             RedirectorErrors++;
  162             return;
  163         }
  164         if (getword(list,sizeof(list),&gwarea,'/')<0) {
  165             debuga(__FILE__,__LINE__,_("Invalid redirected list in file \"%s\"\n"),wentp);
  166             RedirectorErrors++;
  167             return;
  168         }
  169         if (getword_skip(MAXLEN,&gwarea,' ')<0 || getword_limit(full_url,sizeof(full_url),&gwarea,' ')<0) {
  170             debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),wentp);
  171             RedirectorErrors++;
  172             return;
  173         }
  174         if (getword(ip,sizeof(ip),&gwarea,'/')<0) {
  175             debuga(__FILE__,__LINE__,_("Invalid source IP in file \"%s\"\n"),wentp);
  176             RedirectorErrors++;
  177             return;
  178         }
  179         if (getword_skip(MAXLEN,&gwarea,' ')<0 || getword(UserBuf,sizeof(UserBuf),&gwarea,' ')<0) {
  180             debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),wentp);
  181             RedirectorErrors++;
  182             return;
  183         }
  184     }
  185     url=process_url(full_url,false);
  186 
  187     //sprintf(warea,"%04d%02d%02d",year,mon,day);
  188 
  189     if (RedirectorFilterOutDate)
  190     {
  191         idata = year*10000+mon*100+day;
  192         if (idata<dfrom || idata>duntil)
  193             return;
  194         if (ReadFilter->StartTime>=0 && ReadFilter->EndTime>=0)
  195         {
  196             int h,m,hmr;
  197 
  198             if (sscanf(hour,"%d:%d",&h,&m)!=2)
  199             {
  200                 debuga(__FILE__,__LINE__,_("Can't parse time \"%s\" found in \"%s\"\n"),hour,wentp);
  201                 RedirectorErrors++;
  202                 return;
  203             }
  204             hmr=h*100+m;
  205             if (hmr<ReadFilter->StartTime || hmr>=ReadFilter->EndTime)
  206                 return;
  207         }
  208     }
  209 
  210     user=UserBuf;
  211     PUser=process_user(&user,ip,&id_is_ip);
  212     if (PUser!=USERERR_NoError) return;
  213 
  214     uinfo=userinfo_find_from_id(user);
  215     if (!uinfo) {
  216         uinfo=userinfo_create(user,(id_is_ip) ? NULL : ip);
  217         uinfo->no_report=true;
  218         if (Ip2Name && id_is_ip) {
  219             strcpy(IpBuf,user);
  220             ip2name(IpBuf,sizeof(IpBuf));
  221             user=IpBuf;
  222         }
  223         user_find(userlabel,MAX_USER_LEN, user);
  224         userinfo_label(uinfo,userlabel);
  225     }
  226     fprintf(fp_ou,"%s\t%04d%02d%02d\t%s\t%s\t%s\t",uinfo->id,year,mon,day,hour,ip,url);
  227     if (source[0] && list[0])
  228         fprintf(fp_ou,"%s/%s\n",source,list);
  229     else if (source[0])
  230         fprintf(fp_ou,"%s\n",source);
  231     else
  232         fprintf(fp_ou,"%s\n",list);
  233     redirector_count++;
  234 }
  235 
  236 static void read_log(const char *wentp, FILE *fp_ou,int dfrom,int duntil,const struct ReadLogDataStruct *ReadFilter)
  237 {
  238     FileObject *fp_in = NULL;
  239     char *buf;
  240     int  i;
  241     longline line;
  242 
  243     if (debug) {
  244         debuga(__FILE__,__LINE__,_("Reading redirector log file \"%s\"\n"),wentp);
  245     }
  246 
  247     /* With squidGuard, you can log groups in only one log file.
  248         We must parse each log files only one time.  Example :
  249         dest porn {
  250             domainlist porn/domains
  251             urllist    porn/urls
  252             log file1.log
  253         }
  254         dest aggressive {
  255             domainlist aggressive/domains
  256             urllist    aggressive/urls
  257             log file2.log
  258         }
  259         dest audio-video {
  260             domainlist audio-video/domains
  261             urllist    audio-video/urls
  262             log file1.log
  263         }
  264     */
  265     for (i=0; i<nfiles_done; i++)
  266         if (!strcmp(wentp, files_done[i])) return;
  267 
  268     nfiles_done++;
  269     files_done = realloc(files_done, nfiles_done*sizeof(char *));
  270     if (!files_done) {
  271         debuga(__FILE__,__LINE__,_("Not enough memory to store the name of the new redirector log to be read - %s\n"),strerror(errno));
  272         exit(EXIT_FAILURE);
  273     }
  274     files_done[nfiles_done-1] = strdup(wentp);
  275     if (!files_done[nfiles_done-1]) {
  276         debuga(__FILE__,__LINE__,_("Not enough memory to store the name of the new redirector log to be read - %s\n"),strerror(errno));
  277         exit(EXIT_FAILURE);
  278     }
  279 
  280     if ((fp_in=decomp(wentp))==NULL) {
  281         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wentp,FileObject_GetLastOpenError());
  282         exit(EXIT_FAILURE);
  283     }
  284 
  285     if ((line=longline_create())==NULL) {
  286         debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),wentp);
  287         exit(EXIT_FAILURE);
  288     }
  289 
  290     while ((buf=longline_read(fp_in,line)) != NULL) {
  291         parse_log(fp_ou,buf,dfrom,duntil,ReadFilter);
  292     }
  293     if (FileObject_Close(fp_in)) {
  294         debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wentp,FileObject_GetLastCloseError());
  295         exit(EXIT_FAILURE);
  296     }
  297     longline_destroy(&line);
  298     return;
  299 }
  300 
  301 
  302 void redirector_log(const struct ReadLogDataStruct *ReadFilter)
  303 {
  304     FILE *fp_ou = NULL, *fp_guard = NULL;
  305     char buf[MAXLEN];
  306     char guard_in[MAXLEN];
  307     char logdir[MAXLEN];
  308     char user[MAXLEN];
  309     char tmp6[MAXLEN];
  310     int i;
  311     int  y;
  312     int cstatus;
  313     int dfrom, duntil;
  314     char *str;
  315     char *str2;
  316 
  317     str2 = user;
  318 
  319     if (SquidGuardConf[0] == '\0' && NRedirectorLogs == 0) {
  320         if (debugz>=LogLevel_Process) debugaz(__FILE__,__LINE__,_("No redirector logs provided to produce that kind of report\n"));
  321         return;
  322     }
  323 
  324     format_path(__FILE__, __LINE__, guard_in, sizeof(guard_in), "%s/redirector.int_unsort", tmp);
  325     if ((fp_ou=fopen(guard_in,"w"))==NULL) {
  326         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),guard_in,strerror(errno));
  327         exit(EXIT_FAILURE);
  328     }
  329 
  330     getperiod_torange(&period,&dfrom,&duntil);
  331 
  332     if (NRedirectorLogs>0) {
  333         for (i=0 ; i<NRedirectorLogs ; i++)
  334             read_log(RedirectorLogs[i],fp_ou,dfrom,duntil,ReadFilter);
  335     } else {
  336         if (access(SquidGuardConf, R_OK) != 0) {
  337             debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),SquidGuardConf,strerror(errno));
  338             exit(EXIT_FAILURE);
  339         }
  340 
  341         if ((fp_guard=fopen(SquidGuardConf,"r"))==NULL) {
  342             debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),SquidGuardConf,strerror(errno));
  343             exit(EXIT_FAILURE);
  344         }
  345 
  346         logdir[0]=0;
  347         while(fgets(buf,sizeof(buf),fp_guard)!=NULL) {
  348             fixendofline(buf);
  349             if ((str=get_param_value("logdir",buf))!=NULL) {
  350                 /*
  351                 We want to tolerate spaces inside the directory name but we must also
  352                 remove the trailing spaces left by the editor after the directory name.
  353                 This should not be a problem as nobody use a file name with trailing spaces.
  354                 */
  355                 for (y=strlen(str)-1 ; y>=0 && (unsigned char)str[y]<=' ' ; y--);
  356                 if (y>=sizeof(logdir)-1) y=sizeof(logdir)-2;
  357                 logdir[y+1] = '\0';
  358                 while (y>=0) {
  359                     logdir[y] = str[y];
  360                     y--;
  361                 }
  362             } else if ((str=get_param_value("log",buf))!=NULL) {
  363                 if ((str2=get_param_value("anonymous",str))!=NULL)
  364                     str=str2;
  365 
  366                 /*
  367                 If logdir is defined, we prepend it to the log file name, otherwise, we assume
  368                 the log directive provides an absolute file name to the log file. Therefore,
  369                 we don't need to add an additionnal / at the beginning of the log file name.
  370                 */
  371                 y=(logdir[0]) ? format_path(__FILE__, __LINE__, wentp, sizeof(wentp),"%s/", logdir) : 0;
  372                 /*
  373                 Spaces are allowed in the name of the log file. The file name ends at the first #
  374                 because it is assumed it is an end of line comment. Any space before the # is then
  375                 removed. Any control character (i.e. a character with a code lower than 32) ends
  376                 the file name. That includes the terminating zero.
  377                 */
  378                 while((unsigned char)*str>=' ' && *str!='#' && y<sizeof(wentp)-1)
  379                     wentp[y++]=*str++;
  380                 if (*str=='#') {
  381                     str--;
  382                     while(*str==' ' && y>0) {
  383                         str--;
  384                         y--;
  385                     }
  386                 }
  387                 wentp[y]=0;
  388                 read_log(wentp,fp_ou,dfrom,duntil,ReadFilter);
  389             }
  390         }
  391         if (fclose(fp_guard)==EOF) {
  392             debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),SquidGuardConf,strerror(errno));
  393             exit(EXIT_FAILURE);
  394         }
  395     }
  396 
  397     if (fp_ou && fclose(fp_ou)==EOF) {
  398         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),guard_in,strerror(errno));
  399         exit(EXIT_FAILURE);
  400     }
  401 
  402     if (files_done) {
  403         for (y=0; y<nfiles_done; y++)
  404             if (files_done[y]) free(files_done[y]);
  405         free(files_done);
  406     }
  407 
  408     if (redirector_count) {
  409         format_path(__FILE__,__LINE__, redirector_sorted, sizeof(redirector_sorted), "%s/redirector.int_log", tmp);
  410         if (debug) {
  411             debuga(__FILE__,__LINE__,_("Sorting file \"%s\"\n"),redirector_sorted);
  412         }
  413 
  414         if (snprintf(tmp6,sizeof(tmp6),"sort -t \"\t\" -k 1,1 -k 2,2 -k 4,4 \"%s\" -o \"%s\"",guard_in, redirector_sorted)>=sizeof(tmp6)) {
  415             debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),guard_in,redirector_sorted);
  416             exit(EXIT_FAILURE);
  417         }
  418         cstatus=system(tmp6);
  419         if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
  420             debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
  421             debuga(__FILE__,__LINE__,_("sort command: %s\n"),tmp6);
  422             exit(EXIT_FAILURE);
  423         }
  424     }
  425 
  426     if (!KeepTempLog && unlink(guard_in)) {
  427         debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),guard_in,strerror(errno));
  428         exit(EXIT_FAILURE);
  429     }
  430     return;
  431 }
  432 
  433 static void show_ignored_redirector(FILE *fp_ou,int count)
  434 {
  435     char ignored[80];
  436 
  437     snprintf(ignored,sizeof(ignored),ngettext("%d more redirector entry not shown here&hellip;","%d more redirector entries not shown here&hellip;",count),count);
  438     fprintf(fp_ou,"<tr><td class=\"data\"></td><td class=\"data\"></td><td class=\"data\"></td><td class=\"data2 more\">%s</td><td class=\"data\"></td></tr>\n",ignored);
  439 }
  440 
  441 void redirector_report(void)
  442 {
  443     FileObject *fp_in = NULL;
  444     FILE *fp_ou = NULL;
  445 
  446     char *buf;
  447     char *url;
  448     char report[MAXLEN];
  449     char ip[45];
  450     char rule[255];
  451     char oip[45];
  452     char user[MAXLEN];
  453     char ouser[MAXLEN];
  454     char data[15];
  455     char hora[15];
  456     char ouser2[255];
  457     char oname[MAXLEN];
  458     bool  z=false;
  459     int  count=0;
  460     long long int data2;
  461     bool new_user;
  462     struct getwordstruct gwarea;
  463     const struct userinfostruct *uinfo;
  464     struct tm t;
  465     longline line;
  466 
  467     ouser[0]='\0';
  468     ouser2[0]='\0';
  469 
  470     if (!redirector_count) {
  471         if (debugz>=LogLevel_Process) {
  472             if (redirector_sorted[0])
  473                 debugaz(__FILE__,__LINE__,_("Redirector report not generated because it is empty\n"));
  474         }
  475         return;
  476     }
  477 
  478     format_path(__FILE__,__LINE__, report, sizeof(report), "%s/redirector.html", outdirname);
  479 
  480     if ((fp_in=FileObject_Open(redirector_sorted))==NULL) {
  481         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),redirector_sorted,FileObject_GetLastOpenError());
  482         exit(EXIT_FAILURE);
  483     }
  484 
  485     if ((fp_ou=fopen(report,"w"))==NULL) {
  486         debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),report,strerror(errno));
  487         exit(EXIT_FAILURE);
  488     }
  489 
  490     if ((line=longline_create())==NULL) {
  491         debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),redirector_sorted);
  492         exit(EXIT_FAILURE);
  493     }
  494 
  495     write_html_header(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 3 : 1,_("Redirector report"),HTML_JS_NONE);
  496     fputs("<tr><td class=\"header_c\">",fp_ou);
  497     fprintf(fp_ou,_("Period: %s"),period.html);
  498     fputs("</td></tr>\n",fp_ou);
  499     fprintf(fp_ou,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Redirector report"));
  500     close_html_header(fp_ou);
  501 
  502     fputs("<div class=\"report\"><table cellpadding=1 cellspacing=2>\n",fp_ou);
  503     fprintf(fp_ou,"<tr><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th></tr>\n",_("USERID"),_("IP/NAME"),_("DATE/TIME"),_("ACCESSED SITE"),_("RULE"));
  504 
  505     while((buf=longline_read(fp_in,line))!=NULL) {
  506         getword_start(&gwarea,buf);
  507         if (getword(user,sizeof(user),&gwarea,'\t')<0) {
  508             debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),redirector_sorted);
  509             exit(EXIT_FAILURE);
  510         }
  511         if (getword_atoll(&data2,&gwarea,'\t')<0) {
  512             debuga(__FILE__,__LINE__,_("Invalid date in file \"%s\"\n"),redirector_sorted);
  513             exit(EXIT_FAILURE);
  514         }
  515         if (getword(hora,sizeof(hora),&gwarea,'\t')<0) {
  516             debuga(__FILE__,__LINE__,_("Invalid time in file \"%s\"\n"),redirector_sorted);
  517             exit(EXIT_FAILURE);
  518         }
  519         if (getword(ip,sizeof(ip),&gwarea,'\t')<0) {
  520             debuga(__FILE__,__LINE__,_("Invalid IP address in file \"%s\"\n"),redirector_sorted);
  521             exit(EXIT_FAILURE);
  522         }
  523         if (getword_ptr(buf,&url,&gwarea,'\t')<0) {
  524             debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),redirector_sorted);
  525             exit(EXIT_FAILURE);
  526         }
  527         if (getword(rule,sizeof(rule),&gwarea,'\n')<0) {
  528             debuga(__FILE__,__LINE__,_("Invalid rule in file \"%s\"\n"),redirector_sorted);
  529             exit(EXIT_FAILURE);
  530         }
  531 
  532         uinfo=userinfo_find_from_id(user);
  533         if (!uinfo) {
  534             debuga(__FILE__,__LINE__,_("Unknown user ID %s in file \"%s\"\n"),user,redirector_sorted);
  535             exit(EXIT_FAILURE);
  536         }
  537 
  538         computedate(data2/10000,(data2/100)%100,data2%100,&t);
  539         strftime(data,sizeof(data),"%x",&t);
  540 
  541         new_user=false;
  542         if (!z) {
  543             strcpy(ouser,user);
  544             strcpy(oip,ip);
  545             strcpy(oname,ip);
  546             if (Ip2Name && !uinfo->id_is_ip) ip2name(oname,sizeof(oname));
  547             z=true;
  548             new_user=true;
  549         } else {
  550             if (strcmp(ouser,user) != 0) {
  551                 strcpy(ouser,user);
  552                 new_user=true;
  553             }
  554             if (strcmp(oip,ip) != 0) {
  555                 strcpy(oip,ip);
  556                 strcpy(oname,ip);
  557                 if (Ip2Name && !uinfo->id_is_ip) ip2name(oname,sizeof(oname));
  558                 new_user=true;
  559             }
  560         }
  561 
  562         if (SquidGuardReportLimit) {
  563             if (strcmp(ouser2,uinfo->label) == 0) {
  564                 count++;
  565             } else {
  566                 if (count>SquidGuardReportLimit && SquidGuardReportLimit>0)
  567                     show_ignored_redirector(fp_ou,count-SquidGuardReportLimit);
  568                 count=1;
  569                 strcpy(ouser2,uinfo->label);
  570             }
  571             if (count > SquidGuardReportLimit)
  572                 continue;
  573         }
  574 
  575         if (new_user)
  576             fprintf(fp_ou,"<tr><td class=\"data2\">%s</td><td class=\"data2\">%s</td>",uinfo->label,ip);
  577         else
  578             fputs("<tr><td class=\"data2\"></td><td class=\"data2\"></td>",fp_ou);
  579         fprintf(fp_ou,"<td class=\"data2\">%s-%s</td><td class=\"data2\">",data,hora);
  580         output_html_link(fp_ou,url,100);
  581         fprintf(fp_ou,"</td><td class=\"data2\">%s</td></tr>\n",rule);
  582     }
  583     if (FileObject_Close(fp_in)) {
  584         debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),redirector_sorted,FileObject_GetLastCloseError());
  585         exit(EXIT_FAILURE);
  586     }
  587     longline_destroy(&line);
  588 
  589     if (count>SquidGuardReportLimit && SquidGuardReportLimit>0)
  590         show_ignored_redirector(fp_ou,count-SquidGuardReportLimit);
  591 
  592     fputs("</table>\n",fp_ou);
  593 
  594     if (RedirectorErrors>0)
  595     {
  596         fputs("<div class=\"warn\"><span>",fp_ou);
  597         fprintf(fp_ou,ngettext("%d error found in the log file. Some entries may be missing.","%d errors found in the log file. Some entries may be missing.",RedirectorErrors),RedirectorErrors);
  598         fputs("</span></div>\n",fp_ou);
  599     }
  600 
  601     fputs("</div>\n",fp_ou);
  602     write_html_trailer(fp_ou);
  603     if (fclose(fp_ou)==EOF) {
  604         debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),report,strerror(errno));
  605         exit(EXIT_FAILURE);
  606     }
  607 
  608     if (!KeepTempLog && unlink(redirector_sorted)) {
  609         debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),redirector_sorted,strerror(errno));
  610         exit(EXIT_FAILURE);
  611     }
  612 
  613     return;
  614 }