]> git.ipfire.org Git - thirdparty/sarg.git/blob - redirector.c
Rewrite the useragent log processing
[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 dfrom=(period.start.tm_year+1900)*10000+(period.start.tm_mon+1)*100+period.start.tm_mday;
316 duntil=(period.end.tm_year+1900)*10000+(period.end.tm_mon+1)*100+period.end.tm_mday;
317
318 if (NRedirectorLogs>0) {
319 for (i=0 ; i<NRedirectorLogs ; i++)
320 read_log(RedirectorLogs[i],fp_ou,dfrom,duntil);
321 } else {
322 if(access(SquidGuardConf, R_OK) != 0) {
323 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),SquidGuardConf,strerror(errno));
324 exit(EXIT_FAILURE);
325 }
326
327 if((fp_guard=fopen(SquidGuardConf,"r"))==NULL) {
328 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),SquidGuardConf,strerror(errno));
329 exit(EXIT_FAILURE);
330 }
331
332 logdir[0]=0;
333 while(fgets(buf,sizeof(buf),fp_guard)!=NULL) {
334 fixendofline(buf);
335 if((str=get_param_value("logdir",buf))!=NULL) {
336 /*
337 We want to tolerate spaces inside the directory name but we must also
338 remove the trailing spaces left by the editor after the directory name.
339 This should not be a problem as nobody use a file name with trailing spaces.
340 */
341 for (y=strlen(str)-1 ; y>=0 && (unsigned char)str[y]<=' ' ; y--);
342 if (y>=sizeof(logdir)-1) y=sizeof(logdir)-2;
343 logdir[y+1] = '\0';
344 while (y>=0) {
345 logdir[y] = str[y];
346 y--;
347 }
348 } else if((str=get_param_value("log",buf))!=NULL) {
349 if((str2=get_param_value("anonymous",str))!=NULL)
350 str=str2;
351
352 /*
353 If logdir is defined, we prepend it to the log file name, otherwise, we assume
354 the log directive provides an absolute file name to the log file. Therefore,
355 we don't need to add an additionnal / at the beginning of the log file name.
356 */
357 y=(logdir[0]) ? sprintf(wentp,"%s/",logdir) : 0;
358 /*
359 Spaces are allowed in the name of the log file. The file name ends at the first #
360 because it is assumed it is an end of line comment. Any space before the # is then
361 removed. Any control character (i.e. a character with a code lower than 32) ends
362 the file name. That includes the terminating zero.
363 */
364 while((unsigned char)*str>=' ' && *str!='#' && y<sizeof(wentp)-1)
365 wentp[y++]=*str++;
366 if(*str=='#') {
367 str--;
368 while(*str==' ' && y>0) {
369 str--;
370 y--;
371 }
372 }
373 wentp[y]=0;
374 read_log(wentp,fp_ou,dfrom,duntil);
375 }
376 }
377 if (fclose(fp_guard)==EOF) {
378 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),SquidGuardConf,strerror(errno));
379 exit(EXIT_FAILURE);
380 }
381 }
382
383 if (fp_ou && fclose(fp_ou)==EOF) {
384 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),guard_in,strerror(errno));
385 exit(EXIT_FAILURE);
386 }
387
388 if (files_done) {
389 for (y=0; y<nfiles_done; y++)
390 if (files_done[y]) free(files_done[y]);
391 free(files_done);
392 }
393
394 if (redirector_count) {
395 snprintf(redirector_sorted,sizeof(redirector_sorted),"%s/redirector.int_log",tmp);
396 if(debug) {
397 debuga(__FILE__,__LINE__,_("Sorting file \"%s\"\n"),redirector_sorted);
398 }
399
400 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)) {
401 debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),guard_in,redirector_sorted);
402 exit(EXIT_FAILURE);
403 }
404 cstatus=system(tmp6);
405 if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
406 debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
407 debuga(__FILE__,__LINE__,_("sort command: %s\n"),tmp6);
408 exit(EXIT_FAILURE);
409 }
410 }
411
412 if (!KeepTempLog && unlink(guard_in)) {
413 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),guard_in,strerror(errno));
414 exit(EXIT_FAILURE);
415 }
416 return;
417 }
418
419 static void show_ignored_redirector(FILE *fp_ou,int count)
420 {
421 char ignored[80];
422
423 snprintf(ignored,sizeof(ignored),ngettext("%d more redirector entry not shown here&hellip;","%d more redirector entries not shown here&hellip;",count),count);
424 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);
425 }
426
427 void redirector_report(void)
428 {
429 FileObject *fp_in = NULL;
430 FILE *fp_ou = NULL;
431
432 char *buf;
433 char *url;
434 char report[MAXLEN];
435 char ip[45];
436 char rule[255];
437 char oip[45];
438 char user[MAXLEN];
439 char ouser[MAXLEN];
440 char data[15];
441 char hora[15];
442 char ouser2[255];
443 char oname[MAXLEN];
444 bool z=false;
445 int count=0;
446 long long int data2;
447 bool new_user;
448 struct getwordstruct gwarea;
449 const struct userinfostruct *uinfo;
450 struct tm t;
451 longline line;
452
453 ouser[0]='\0';
454 ouser2[0]='\0';
455
456 if(!redirector_count) {
457 if (debugz>=LogLevel_Process) {
458 if (redirector_sorted[0])
459 debugaz(__FILE__,__LINE__,_("Redirector report not generated because it is empty\n"));
460 }
461 return;
462 }
463
464 snprintf(report,sizeof(report),"%s/redirector.html",outdirname);
465
466 if((fp_in=FileObject_Open(redirector_sorted))==NULL) {
467 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),redirector_sorted,FileObject_GetLastOpenError());
468 exit(EXIT_FAILURE);
469 }
470
471 if((fp_ou=fopen(report,"w"))==NULL) {
472 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),report,strerror(errno));
473 exit(EXIT_FAILURE);
474 }
475
476 if ((line=longline_create())==NULL) {
477 debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),redirector_sorted);
478 exit(EXIT_FAILURE);
479 }
480
481 write_html_header(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 3 : 1,_("Redirector report"),HTML_JS_NONE);
482 fputs("<tr><td class=\"header_c\">",fp_ou);
483 fprintf(fp_ou,_("Period: %s"),period.html);
484 fputs("</td></tr>\n",fp_ou);
485 fprintf(fp_ou,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Redirector report"));
486 close_html_header(fp_ou);
487
488 fputs("<div class=\"report\"><table cellpadding=1 cellspacing=2>\n",fp_ou);
489 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"));
490
491 while((buf=longline_read(fp_in,line))!=NULL) {
492 getword_start(&gwarea,buf);
493 if (getword(user,sizeof(user),&gwarea,'\t')<0) {
494 debuga(__FILE__,__LINE__,_("Invalid user in file \"%s\"\n"),redirector_sorted);
495 exit(EXIT_FAILURE);
496 }
497 if (getword_atoll(&data2,&gwarea,'\t')<0) {
498 debuga(__FILE__,__LINE__,_("Invalid date in file \"%s\"\n"),redirector_sorted);
499 exit(EXIT_FAILURE);
500 }
501 if (getword(hora,sizeof(hora),&gwarea,'\t')<0) {
502 debuga(__FILE__,__LINE__,_("Invalid time in file \"%s\"\n"),redirector_sorted);
503 exit(EXIT_FAILURE);
504 }
505 if (getword(ip,sizeof(ip),&gwarea,'\t')<0) {
506 debuga(__FILE__,__LINE__,_("Invalid IP address in file \"%s\"\n"),redirector_sorted);
507 exit(EXIT_FAILURE);
508 }
509 if (getword_ptr(buf,&url,&gwarea,'\t')<0) {
510 debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),redirector_sorted);
511 exit(EXIT_FAILURE);
512 }
513 if (getword(rule,sizeof(rule),&gwarea,'\n')<0) {
514 debuga(__FILE__,__LINE__,_("Invalid rule in file \"%s\"\n"),redirector_sorted);
515 exit(EXIT_FAILURE);
516 }
517
518 uinfo=userinfo_find_from_id(user);
519 if (!uinfo) {
520 debuga(__FILE__,__LINE__,_("Unknown user ID %s in file \"%s\"\n"),user,redirector_sorted);
521 exit(EXIT_FAILURE);
522 }
523
524 computedate(data2/10000,(data2/100)%10,data2%100,&t);
525 strftime(data,sizeof(data),"%x",&t);
526
527 new_user=false;
528 if(!z) {
529 strcpy(ouser,user);
530 strcpy(oip,ip);
531 strcpy(oname,ip);
532 if (Ip2Name && !uinfo->id_is_ip) ip2name(oname,sizeof(oname));
533 z=true;
534 new_user=true;
535 } else {
536 if(strcmp(ouser,user) != 0) {
537 strcpy(ouser,user);
538 new_user=true;
539 }
540 if(strcmp(oip,ip) != 0) {
541 strcpy(oip,ip);
542 strcpy(oname,ip);
543 if (Ip2Name && !uinfo->id_is_ip) ip2name(oname,sizeof(oname));
544 new_user=true;
545 }
546 }
547
548 if(SquidGuardReportLimit) {
549 if(strcmp(ouser2,uinfo->label) == 0) {
550 count++;
551 } else {
552 if(count>SquidGuardReportLimit && SquidGuardReportLimit>0)
553 show_ignored_redirector(fp_ou,count-SquidGuardReportLimit);
554 count=1;
555 strcpy(ouser2,uinfo->label);
556 }
557 if(count > SquidGuardReportLimit)
558 continue;
559 }
560
561 if (new_user)
562 fprintf(fp_ou,"<tr><td class=\"data2\">%s</td><td class=\"data2\">%s</td>",uinfo->label,ip);
563 else
564 fputs("<tr><td class=\"data2\"></td><td class=\"data2\"></td>",fp_ou);
565 fprintf(fp_ou,"<td class=\"data2\">%s-%s</td><td class=\"data2\">",data,hora);
566 output_html_link(fp_ou,url,100);
567 fprintf(fp_ou,"</td><td class=\"data2\">%s</td></tr>\n",rule);
568 }
569 if (FileObject_Close(fp_in)) {
570 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),redirector_sorted,FileObject_GetLastCloseError());
571 exit(EXIT_FAILURE);
572 }
573 longline_destroy(&line);
574
575 if(count>SquidGuardReportLimit && SquidGuardReportLimit>0)
576 show_ignored_redirector(fp_ou,count-SquidGuardReportLimit);
577
578 fputs("</table>\n",fp_ou);
579
580 if (RedirectorErrors>0)
581 {
582 fputs("<div class=\"warn\"><span>",fp_ou);
583 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);
584 fputs("</span></div>\n",fp_ou);
585 }
586
587 fputs("</div>\n",fp_ou);
588 write_html_trailer(fp_ou);
589 if (fclose(fp_ou)==EOF) {
590 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),report,strerror(errno));
591 exit(EXIT_FAILURE);
592 }
593
594 if (!KeepTempLog && unlink(redirector_sorted)) {
595 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),redirector_sorted,strerror(errno));
596 exit(EXIT_FAILURE);
597 }
598
599 return;
600 }