]> git.ipfire.org Git - thirdparty/sarg.git/blob - redirector.c
Add support to decompress xz files
[thirdparty/sarg.git] / redirector.c
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)
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 idata = year*10000+mon*100+day;
191 if(idata < dfrom || idata > duntil)
192 return;
193 }
194
195 user=UserBuf;
196 PUser=process_user(&user,ip,&id_is_ip);
197 if (PUser!=USERERR_NoError) return;
198
199 uinfo=userinfo_find_from_id(user);
200 if (!uinfo) {
201 uinfo=userinfo_create(user,(id_is_ip) ? NULL : ip);
202 uinfo->no_report=true;
203 if (Ip2Name && id_is_ip) {
204 strcpy(IpBuf,user);
205 ip2name(IpBuf,sizeof(IpBuf));
206 user=IpBuf;
207 }
208 user_find(userlabel,MAX_USER_LEN, user);
209 userinfo_label(uinfo,userlabel);
210 }
211 fprintf(fp_ou,"%s\t%04d%02d%02d\t%s\t%s\t%s\t",uinfo->id,year,mon,day,hour,ip,url);
212 if (source[0] && list[0])
213 fprintf(fp_ou,"%s/%s\n",source,list);
214 else if (source[0])
215 fprintf(fp_ou,"%s\n",source);
216 else
217 fprintf(fp_ou,"%s\n",list);
218 redirector_count++;
219 }
220
221 static void read_log(const char *wentp, FILE *fp_ou,int dfrom,int duntil)
222 {
223 FileObject *fp_in = NULL;
224 char *buf;
225 int i;
226 longline line;
227
228 if(debug) {
229 debuga(__FILE__,__LINE__,_("Reading redirector log file \"%s\"\n"),wentp);
230 }
231
232 /* With squidGuard, you can log groups in only one log file.
233 We must parse each log files only one time. Example :
234 dest porn {
235 domainlist porn/domains
236 urllist porn/urls
237 log file1.log
238 }
239 dest aggressive {
240 domainlist aggressive/domains
241 urllist aggressive/urls
242 log file2.log
243 }
244 dest audio-video {
245 domainlist audio-video/domains
246 urllist audio-video/urls
247 log file1.log
248 }
249 */
250 for (i=0; i<nfiles_done; i++)
251 if (!strcmp(wentp, files_done[i])) return;
252
253 nfiles_done++;
254 files_done = realloc(files_done, nfiles_done*sizeof(char *));
255 if (!files_done) {
256 debuga(__FILE__,__LINE__,_("Not enough memory to store the name of the new redirector log to be read - %s\n"),strerror(errno));
257 exit(EXIT_FAILURE);
258 }
259 files_done[nfiles_done-1] = strdup(wentp);
260 if (!files_done[nfiles_done-1]) {
261 debuga(__FILE__,__LINE__,_("Not enough memory to store the name of the new redirector log to be read - %s\n"),strerror(errno));
262 exit(EXIT_FAILURE);
263 }
264
265 if ((fp_in=FileObject_Open(wentp))==NULL) {
266 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wentp,FileObject_GetLastOpenError());
267 exit(EXIT_FAILURE);
268 }
269
270 if ((line=longline_create())==NULL) {
271 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),wentp);
272 exit(EXIT_FAILURE);
273 }
274
275 while ((buf=longline_read(fp_in,line)) != NULL) {
276 parse_log(fp_ou,buf,dfrom,duntil);
277 }
278 if (FileObject_Close(fp_in)) {
279 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),wentp,FileObject_GetLastCloseError());
280 exit(EXIT_FAILURE);
281 }
282 longline_destroy(&line);
283 return;
284 }
285
286
287 void redirector_log(void)
288 {
289 FILE *fp_ou = NULL, *fp_guard = NULL;
290 char buf[MAXLEN];
291 char guard_in[MAXLEN];
292 char logdir[MAXLEN];
293 char user[MAXLEN];
294 char tmp6[MAXLEN];
295 int i;
296 int y;
297 int cstatus;
298 int dfrom, duntil;
299 char *str;
300 char *str2;
301
302 str2 = user;
303
304 if(SquidGuardConf[0] == '\0' && NRedirectorLogs == 0) {
305 if (debugz>=LogLevel_Process) debugaz(__FILE__,__LINE__,_("No redirector logs provided to produce that kind of report\n"));
306 return;
307 }
308
309 snprintf(guard_in,sizeof(guard_in),"%s/redirector.int_unsort",tmp);
310 if((fp_ou=fopen(guard_in,"w"))==NULL) {
311 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),guard_in,strerror(errno));
312 exit(EXIT_FAILURE);
313 }
314
315 getperiod_torange(&period,&dfrom,&duntil);
316
317 if (NRedirectorLogs>0) {
318 for (i=0 ; i<NRedirectorLogs ; i++)
319 read_log(RedirectorLogs[i],fp_ou,dfrom,duntil);
320 } else {
321 if(access(SquidGuardConf, R_OK) != 0) {
322 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),SquidGuardConf,strerror(errno));
323 exit(EXIT_FAILURE);
324 }
325
326 if((fp_guard=fopen(SquidGuardConf,"r"))==NULL) {
327 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),SquidGuardConf,strerror(errno));
328 exit(EXIT_FAILURE);
329 }
330
331 logdir[0]=0;
332 while(fgets(buf,sizeof(buf),fp_guard)!=NULL) {
333 fixendofline(buf);
334 if((str=get_param_value("logdir",buf))!=NULL) {
335 /*
336 We want to tolerate spaces inside the directory name but we must also
337 remove the trailing spaces left by the editor after the directory name.
338 This should not be a problem as nobody use a file name with trailing spaces.
339 */
340 for (y=strlen(str)-1 ; y>=0 && (unsigned char)str[y]<=' ' ; y--);
341 if (y>=sizeof(logdir)-1) y=sizeof(logdir)-2;
342 logdir[y+1] = '\0';
343 while (y>=0) {
344 logdir[y] = str[y];
345 y--;
346 }
347 } else if((str=get_param_value("log",buf))!=NULL) {
348 if((str2=get_param_value("anonymous",str))!=NULL)
349 str=str2;
350
351 /*
352 If logdir is defined, we prepend it to the log file name, otherwise, we assume
353 the log directive provides an absolute file name to the log file. Therefore,
354 we don't need to add an additionnal / at the beginning of the log file name.
355 */
356 y=(logdir[0]) ? sprintf(wentp,"%s/",logdir) : 0;
357 /*
358 Spaces are allowed in the name of the log file. The file name ends at the first #
359 because it is assumed it is an end of line comment. Any space before the # is then
360 removed. Any control character (i.e. a character with a code lower than 32) ends
361 the file name. That includes the terminating zero.
362 */
363 while((unsigned char)*str>=' ' && *str!='#' && y<sizeof(wentp)-1)
364 wentp[y++]=*str++;
365 if(*str=='#') {
366 str--;
367 while(*str==' ' && y>0) {
368 str--;
369 y--;
370 }
371 }
372 wentp[y]=0;
373 read_log(wentp,fp_ou,dfrom,duntil);
374 }
375 }
376 if (fclose(fp_guard)==EOF) {
377 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),SquidGuardConf,strerror(errno));
378 exit(EXIT_FAILURE);
379 }
380 }
381
382 if (fp_ou && fclose(fp_ou)==EOF) {
383 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),guard_in,strerror(errno));
384 exit(EXIT_FAILURE);
385 }
386
387 if (files_done) {
388 for (y=0; y<nfiles_done; y++)
389 if (files_done[y]) free(files_done[y]);
390 free(files_done);
391 }
392
393 if (redirector_count) {
394 snprintf(redirector_sorted,sizeof(redirector_sorted),"%s/redirector.int_log",tmp);
395 if(debug) {
396 debuga(__FILE__,__LINE__,_("Sorting file \"%s\"\n"),redirector_sorted);
397 }
398
399 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)) {
400 debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),guard_in,redirector_sorted);
401 exit(EXIT_FAILURE);
402 }
403 cstatus=system(tmp6);
404 if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
405 debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
406 debuga(__FILE__,__LINE__,_("sort command: %s\n"),tmp6);
407 exit(EXIT_FAILURE);
408 }
409 }
410
411 if (!KeepTempLog && unlink(guard_in)) {
412 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),guard_in,strerror(errno));
413 exit(EXIT_FAILURE);
414 }
415 return;
416 }
417
418 static void show_ignored_redirector(FILE *fp_ou,int count)
419 {
420 char ignored[80];
421
422 snprintf(ignored,sizeof(ignored),ngettext("%d more redirector entry not shown here&hellip;","%d more redirector entries not shown here&hellip;",count),count);
423 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);
424 }
425
426 void redirector_report(void)
427 {
428 FileObject *fp_in = NULL;
429 FILE *fp_ou = NULL;
430
431 char *buf;
432 char *url;
433 char report[MAXLEN];
434 char ip[45];
435 char rule[255];
436 char oip[45];
437 char user[MAXLEN];
438 char ouser[MAXLEN];
439 char data[15];
440 char hora[15];
441 char ouser2[255];
442 char oname[MAXLEN];
443 bool z=false;
444 int count=0;
445 long long int data2;
446 bool new_user;
447 struct getwordstruct gwarea;
448 const struct userinfostruct *uinfo;
449 struct tm t;
450 longline line;
451
452 ouser[0]='\0';
453 ouser2[0]='\0';
454
455 if(!redirector_count) {
456 if (debugz>=LogLevel_Process) {
457 if (redirector_sorted[0])
458 debugaz(__FILE__,__LINE__,_("Redirector report not generated because it is empty\n"));
459 }
460 return;
461 }
462
463 snprintf(report,sizeof(report),"%s/redirector.html",outdirname);
464
465 if((fp_in=FileObject_Open(redirector_sorted))==NULL) {
466 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),redirector_sorted,FileObject_GetLastOpenError());
467 exit(EXIT_FAILURE);
468 }
469
470 if((fp_ou=fopen(report,"w"))==NULL) {
471 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),report,strerror(errno));
472 exit(EXIT_FAILURE);
473 }
474
475 if ((line=longline_create())==NULL) {
476 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),redirector_sorted);
477 exit(EXIT_FAILURE);
478 }
479
480 write_html_header(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 3 : 1,_("Redirector report"),HTML_JS_NONE);
481 fputs("<tr><td class=\"header_c\">",fp_ou);
482 fprintf(fp_ou,_("Period: %s"),period.html);
483 fputs("</td></tr>\n",fp_ou);
484 fprintf(fp_ou,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Redirector report"));
485 close_html_header(fp_ou);
486
487 fputs("<div class=\"report\"><table cellpadding=1 cellspacing=2>\n",fp_ou);
488 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"));
489
490 while((buf=longline_read(fp_in,line))!=NULL) {
491 getword_start(&gwarea,buf);
492 if (getword(user,sizeof(user),&gwarea,'\t')<0) {
493 debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),redirector_sorted);
494 exit(EXIT_FAILURE);
495 }
496 if (getword_atoll(&data2,&gwarea,'\t')<0) {
497 debuga(__FILE__,__LINE__,_("Invalid date in file \"%s\"\n"),redirector_sorted);
498 exit(EXIT_FAILURE);
499 }
500 if (getword(hora,sizeof(hora),&gwarea,'\t')<0) {
501 debuga(__FILE__,__LINE__,_("Invalid time in file \"%s\"\n"),redirector_sorted);
502 exit(EXIT_FAILURE);
503 }
504 if (getword(ip,sizeof(ip),&gwarea,'\t')<0) {
505 debuga(__FILE__,__LINE__,_("Invalid IP address in file \"%s\"\n"),redirector_sorted);
506 exit(EXIT_FAILURE);
507 }
508 if (getword_ptr(buf,&url,&gwarea,'\t')<0) {
509 debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),redirector_sorted);
510 exit(EXIT_FAILURE);
511 }
512 if (getword(rule,sizeof(rule),&gwarea,'\n')<0) {
513 debuga(__FILE__,__LINE__,_("Invalid rule in file \"%s\"\n"),redirector_sorted);
514 exit(EXIT_FAILURE);
515 }
516
517 uinfo=userinfo_find_from_id(user);
518 if (!uinfo) {
519 debuga(__FILE__,__LINE__,_("Unknown user ID %s in file \"%s\"\n"),user,redirector_sorted);
520 exit(EXIT_FAILURE);
521 }
522
523 computedate(data2/10000,(data2/100)%100,data2%100,&t);
524 strftime(data,sizeof(data),"%x",&t);
525
526 new_user=false;
527 if(!z) {
528 strcpy(ouser,user);
529 strcpy(oip,ip);
530 strcpy(oname,ip);
531 if (Ip2Name && !uinfo->id_is_ip) ip2name(oname,sizeof(oname));
532 z=true;
533 new_user=true;
534 } else {
535 if(strcmp(ouser,user) != 0) {
536 strcpy(ouser,user);
537 new_user=true;
538 }
539 if(strcmp(oip,ip) != 0) {
540 strcpy(oip,ip);
541 strcpy(oname,ip);
542 if (Ip2Name && !uinfo->id_is_ip) ip2name(oname,sizeof(oname));
543 new_user=true;
544 }
545 }
546
547 if(SquidGuardReportLimit) {
548 if(strcmp(ouser2,uinfo->label) == 0) {
549 count++;
550 } else {
551 if(count>SquidGuardReportLimit && SquidGuardReportLimit>0)
552 show_ignored_redirector(fp_ou,count-SquidGuardReportLimit);
553 count=1;
554 strcpy(ouser2,uinfo->label);
555 }
556 if(count > SquidGuardReportLimit)
557 continue;
558 }
559
560 if (new_user)
561 fprintf(fp_ou,"<tr><td class=\"data2\">%s</td><td class=\"data2\">%s</td>",uinfo->label,ip);
562 else
563 fputs("<tr><td class=\"data2\"></td><td class=\"data2\"></td>",fp_ou);
564 fprintf(fp_ou,"<td class=\"data2\">%s-%s</td><td class=\"data2\">",data,hora);
565 output_html_link(fp_ou,url,100);
566 fprintf(fp_ou,"</td><td class=\"data2\">%s</td></tr>\n",rule);
567 }
568 if (FileObject_Close(fp_in)) {
569 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),redirector_sorted,FileObject_GetLastCloseError());
570 exit(EXIT_FAILURE);
571 }
572 longline_destroy(&line);
573
574 if(count>SquidGuardReportLimit && SquidGuardReportLimit>0)
575 show_ignored_redirector(fp_ou,count-SquidGuardReportLimit);
576
577 fputs("</table>\n",fp_ou);
578
579 if (RedirectorErrors>0)
580 {
581 fputs("<div class=\"warn\"><span>",fp_ou);
582 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);
583 fputs("</span></div>\n",fp_ou);
584 }
585
586 fputs("</div>\n",fp_ou);
587 write_html_trailer(fp_ou);
588 if (fclose(fp_ou)==EOF) {
589 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),report,strerror(errno));
590 exit(EXIT_FAILURE);
591 }
592
593 if (!KeepTempLog && unlink(redirector_sorted)) {
594 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),redirector_sorted,strerror(errno));
595 exit(EXIT_FAILURE);
596 }
597
598 return;
599 }