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 //! Number of limits.
31 int PerUserLimitsNumber=0;
32 //! Log user's who downloaded more than the limit.
33 struct PerUserLimitStruct PerUserLimits[MAX_USER_LIMITS];
34 //! How to create a per user file.
35 enum PerUserFileCreationEnum PerUserFileCreation=PUFC_Always;
36 
37 extern struct globalstatstruct globstat;
38 
htmlrel(void)39 void htmlrel(void)
40 {
41 	FileObject *fp_in;
42 	FileObject *fp_ip;
43 	FILE *fp_ou;
44 	FILE *fp_ip2;
45 
46 	long long int nnbytes=0, unbytes=0, tnbytes=0, totbytes=0, totbytes2=0;
47 	long long int totelap=0, totelap2=0, nnelap=0, unelap=0, tnelap=0;
48 	long long int incache=0, oucache=0, tnincache=0, tnoucache=0, twork=0;
49 	long long int ltemp;
50 	long long int ntotuser;
51 	long long int userbytes, userelap;
52 	char *buf;
53 	char arqin[MAXLEN], arqou[MAXLEN], arqip[MAXLEN];
54 	char *url, tmsg[50], csort[MAXLEN];
55 	char duser[MAXLEN];
56 	char user_ip[MAXLEN], olduserip[MAXLEN], tmp2[MAXLEN], tmp3[MAXLEN];
57 	char warea[MAXLEN];
58 	char tmp6[MAXLEN];
59 	char *user_url;
60 	long long int tnacc=0, ttnacc=0;
61 	double perc=0, perc2=0, ouperc=0, inperc=0;
62 	int count;
63 	int cstatus;
64 	int i;
65 	unsigned int user_limit[(MAX_USER_LIMITS+sizeof(unsigned int)-1)/sizeof(unsigned int)];
66 	bool have_denied_report;
67 	const char *sort_field;
68 	const char *sort_order;
69 	char siteind[MAX_TRUNCATED_URL];
70 	struct getwordstruct gwarea;
71 	longline line,line1;
72 	const struct userinfostruct *uinfo;
73 	userscan uscan;
74 
75 	if (snprintf(tmp2,sizeof(tmp2),"%s/sargtmp.int_unsort",tmp)>=sizeof(tmp2)) {
76 		debuga(__FILE__,__LINE__,_("Path too long: "));
77 		debuga_more("%s/sargtmp.int_unsort\n",tmp);
78 		exit(EXIT_FAILURE);
79 	}
80 
81 	if (snprintf(tmp3,sizeof(tmp3),"%s/sargtmp.int_log",tmp)>=sizeof(tmp3)) {
82 		debuga(__FILE__,__LINE__,_("Path too long: "));
83 		debuga_more("%s/sargtmp.int_log\n",tmp);
84 		exit(EXIT_FAILURE);
85 	}
86 
87 	tnacc=globstat.nacc;
88 	totbytes=globstat.nbytes;
89 	totelap=globstat.elap;
90 	ntotuser=globstat.totuser;
91 
92 	sort_labels(&sort_field,&sort_order);
93 
94 	switch (PerUserFileCreation)
95 	{
96 		case PUFC_Always:
97 			for (i=0 ; i<PerUserLimitsNumber ; i++) {
98 				FILE *fp_usr=fopen(PerUserLimits[i].File,"wt");
99 				if (fp_usr==NULL) {
100 					debuga(__FILE__,__LINE__,_("Cannot create empty per_user_limit file \"%s\": %s\n"),PerUserLimits[i].File,
101 						   strerror(errno));
102 					exit(EXIT_FAILURE);
103 				}
104 				if (fclose(fp_usr)==EOF) {
105 					debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),PerUserLimits[i].File,strerror(errno));
106 					exit(EXIT_FAILURE);
107 				}
108 			}
109 			break;
110 
111 		case PUFC_AsRequired:
112 			for (i=0 ; i<PerUserLimitsNumber ; i++) {
113 				if (access(PerUserLimits[i].File,R_OK)==0 && unlink(PerUserLimits[i].File)==-1) {
114 					debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),PerUserLimits[i].File,
115 						   strerror(errno));
116 					exit(EXIT_FAILURE);
117 				}
118 			}
119 			break;
120 	}
121 
122 	uscan=userinfo_startscan();
123 	if (uscan == NULL) {
124 		debuga(__FILE__,__LINE__,_("Cannot enumerate the user list\n"));
125 		exit(EXIT_FAILURE);
126 	}
127 	while ( (uinfo = userinfo_advancescan(uscan)) != NULL ) {
128 		if (snprintf(warea,sizeof(warea),"%s/%s",outdirname,uinfo->filename)>=sizeof(warea)) {
129 			debuga(__FILE__,__LINE__,_("Path too long: "));
130 			debuga_more("%s/%s\n",outdirname,uinfo->filename);
131 			exit(EXIT_FAILURE);
132 		}
133 		if (!uinfo->topuser) {
134 			//! \todo Instead of deleting the supernumerary directories, don't create them in the first place.
135 			unlinkdir(warea,0);
136 			continue;
137 		}
138 
139 		if (access(warea, R_OK) != 0) {
140 			if (PortableMkDir(warea,0755)) {
141 				debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),warea,strerror(errno));
142 				exit(EXIT_FAILURE);
143 			}
144 		}
145 		tmpsort(uinfo);
146 
147 		if (snprintf(arqin,sizeof(arqin),"%s/htmlrel.txt",tmp)>=sizeof(arqin)) {
148 			debuga(__FILE__,__LINE__,_("Input file name too long: %s/htmlrel.txt\n"),tmp);
149 			exit(EXIT_FAILURE);
150 		}
151 		if ((fp_in = FileObject_Open(arqin)) == 0){
152 			if (uinfo->no_report) continue;
153 			debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),arqin,FileObject_GetLastOpenError());
154 			exit(EXIT_FAILURE);
155 		}
156 
157 		if (snprintf(arqou,sizeof(arqou),"%s/%s/%s.html",outdirname,uinfo->filename,uinfo->filename)>=sizeof(arqou)) {
158 			debuga(__FILE__,__LINE__,_("Path too long: "));
159 			debuga_more("%s/%s/%s.html\n",outdirname,uinfo->filename,uinfo->filename);
160 			exit(EXIT_FAILURE);
161 		}
162 		if (snprintf(duser,sizeof(duser),"%s/denied_%s.html",outdirname,uinfo->filename)>=sizeof(duser)) {
163 			debuga(__FILE__,__LINE__,_("Path too long: "));
164 			debuga_more("%s/denied_%s.html\n",outdirname,uinfo->filename);
165 			exit(EXIT_FAILURE);
166 		}
167 		if (access(duser, R_OK) != 0)
168 			have_denied_report=false;
169 		else
170 			have_denied_report=true;
171 
172 		if ((line=longline_create())==NULL) {
173 			debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),arqin);
174 			exit(EXIT_FAILURE);
175 		}
176 
177 		for (i=0 ; i<sizeof(user_limit)/sizeof(user_limit[0]) ; i++)
178 			user_limit[i]=0;
179 
180 		tnacc=0;
181 		tnbytes=0;
182 		tnelap=0;
183 		tnincache=0;
184 		tnoucache=0;
185 		while((buf=longline_read(fp_in,line))!=NULL) {
186 			getword_start(&gwarea,buf);
187 			if (getword_atoll(&ltemp,&gwarea,'\t')<0) {
188 				debuga(__FILE__,__LINE__,_("Invalid number of accesses in file \"%s\"\n"),arqin);
189 				exit(EXIT_FAILURE);
190 			}
191 			tnacc+=ltemp;
192 			if (getword_atoll(&ltemp,&gwarea,'\t')<0) {
193 				debuga(__FILE__,__LINE__,_("Invalid downloaded size in file \"%s\"\n"),arqin);
194 				exit(EXIT_FAILURE);
195 			}
196 			tnbytes+=ltemp;
197 			if (getword_ptr(NULL,NULL,&gwarea,'\t')<0) {
198 				debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),arqin);
199 				exit(EXIT_FAILURE);
200 			}
201 			if (getword_skip(MAXLEN,&gwarea,'\t')<0) {
202 				debuga(__FILE__,__LINE__,_("Invalid access code in file \"%s\"\n"),arqin);
203 				exit(EXIT_FAILURE);
204 			}
205 			if (getword_atoll(&ltemp,&gwarea,'\t')<0) {
206 				debuga(__FILE__,__LINE__,_("Invalid elapsed time in file \"%s\"\n"),arqin);
207 				exit(EXIT_FAILURE);
208 			}
209 			tnelap+=ltemp;
210 			if (getword_atoll(&ltemp,&gwarea,'\t')<0) {
211 				debuga(__FILE__,__LINE__,_("Invalid in-cache size in file \"%s\"\n"),arqin);
212 				exit(EXIT_FAILURE);
213 			}
214 			tnincache+=ltemp;
215 			if (getword_atoll(&ltemp,&gwarea,'\n')<0) {
216 				debuga(__FILE__,__LINE__,_("Invalid out-of-cache size in file \"%s\"\n"),arqin);
217 				exit(EXIT_FAILURE);
218 			}
219 			tnoucache+=ltemp;
220 		}
221 
222 		FileObject_Rewind(fp_in);
223 
224 		if ((fp_ou = fopen(arqou, "w")) == 0){
225 			debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),arqou,strerror(errno));
226 			exit(EXIT_FAILURE);
227 		}
228 
229 		write_html_header(fp_ou,(IndexTree == INDEX_TREE_DATE) ? 4 : 2,_("User report"),HTML_JS_SORTTABLE);
230 		fprintf(fp_ou,"<tr><td class=\"header_c\">%s:&nbsp;%s</td></tr>\n",_("Period"),period.html);
231 		fprintf(fp_ou,"<tr><td class=\"header_c\">%s:&nbsp;%s</td></tr>\n",_("User"),uinfo->label);
232 		fputs("<tr><td class=\"header_c\">",fp_ou);
233 		fprintf(fp_ou,_("Sort:&nbsp;%s, %s"),sort_field,sort_order);
234 		fputs("</td></tr>\n",fp_ou);
235 		fprintf(fp_ou,"<tr><th class=\"header_c\">%s</th></tr>\n",_("User report"));
236 		close_html_header(fp_ou);
237 
238 		if (have_denied_report) {
239 			fputs("<div class=\"report\"><table cellpadding=\"1\" cellspacing=\"2\">\n",fp_ou);
240 			fprintf(fp_ou,"<tr><td class=\"header_l\" colspan=\"11\"><a href=\"denied_%s.html\">%s</a></td></tr>\n",uinfo->filename,_("SmartFilter report"));
241 			fputs("<tr><td></td></tr>\n</table></div>\n",fp_ou);
242 		}
243 
244 		fputs("<div class=\"report\"><table cellpadding=\"2\" cellspacing=\"1\"",fp_ou);
245 		if (SortTableJs[0]) fputs(" class=\"sortable\"",fp_ou);
246 		fputs(">\n",fp_ou);
247 
248 		fputs("<thead><tr><th class=\"sorttable_nosort\"></th><th class=\"header_l",fp_ou);
249 		if (SortTableJs[0]) fputs(" sorttable_alpha",fp_ou);
250 		fprintf(fp_ou,"\">%s</th>",_("ACCESSED SITE"));
251 
252 		if ((UserReportFields & USERREPORTFIELDS_CONNECT) != 0)
253 			fprintf(fp_ou,"<th class=\"header_l\">%s</th>",_("CONNECT"));
254 		if ((UserReportFields & USERREPORTFIELDS_BYTES) != 0)
255 			fprintf(fp_ou,"<th class=\"header_l\">%s</th>",_("BYTES"));
256 		if ((UserReportFields & USERREPORTFIELDS_SETYB) != 0)
257 			fprintf(fp_ou,"<th class=\"header_l\">%s</th>",_("%BYTES"));
258 		if ((UserReportFields & USERREPORTFIELDS_IN_CACHE_OUT) != 0)
259 			fprintf(fp_ou,"<th class=\"header_c\" colspan=\"2\">%s</th><th style=\"display:none;\"></th>",_("IN-CACHE-OUT"));
260 		if ((UserReportFields & USERREPORTFIELDS_USED_TIME) != 0)
261 			fprintf(fp_ou,"<th class=\"header_l\">%s</th>",_("ELAPSED TIME"));
262 		if ((UserReportFields & USERREPORTFIELDS_MILISEC) != 0)
263 			fprintf(fp_ou,"<th class=\"header_l\">%s</th>",_("MILLISEC"));
264 		if ((UserReportFields & USERREPORTFIELDS_PTIME) != 0)
265 			fprintf(fp_ou,"<th class=\"header_l\">%s</th>",pgettext("duration","%TIME"));
266 
267 		fputs("</tr></thead>\n",fp_ou);
268 
269 		if (debug) {
270 			debuga(__FILE__,__LINE__,_("Making report %s\n"),uinfo->id);
271 		}
272 		count=0;
273 		arqip[0]='\0';
274 
275 		while((buf=longline_read(fp_in,line))!=NULL) {
276 			getword_start(&gwarea,buf);
277 			if (getword_atoll(&twork,&gwarea,'\t')<0) {
278 				debuga(__FILE__,__LINE__,_("Invalid number of accesses in file \"%s\"\n"),arqin);
279 				exit(EXIT_FAILURE);
280 			}
281 			if (getword_atoll(&nnbytes,&gwarea,'\t')<0) {
282 				debuga(__FILE__,__LINE__,_("Invalid number of bytes in file \"%s\"\n"),arqin);
283 				exit(EXIT_FAILURE);
284 			}
285 			if (getword_ptr(buf,&url,&gwarea,'\t')<0) {
286 				debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),arqin);
287 				exit(EXIT_FAILURE);
288 			}
289 			if (getword(tmsg,sizeof(tmsg),&gwarea,'\t')<0) {
290 				debuga(__FILE__,__LINE__,_("Invalid access code in file \"%s\"\n"),arqin);
291 				exit(EXIT_FAILURE);
292 			}
293 			if (getword_atoll(&nnelap,&gwarea,'\t')<0) {
294 				debuga(__FILE__,__LINE__,_("Invalid elapsed time in file \"%s\"\n"),arqin);
295 				exit(EXIT_FAILURE);
296 			}
297 			if (getword_atoll(&incache,&gwarea,'\t')<0) {
298 				debuga(__FILE__,__LINE__,_("Invalid in-cache size in file \"%s\"\n"),arqin);
299 				exit(EXIT_FAILURE);
300 			}
301 			if (getword_atoll(&oucache,&gwarea,'\n')<0) {
302 				debuga(__FILE__,__LINE__,_("Invalid out-of-cache size in file \"%s\"\n"),arqin);
303 				exit(EXIT_FAILURE);
304 			}
305 
306 			if (UserReportLimit<=0 || count<=UserReportLimit) {
307 				fputs("<tr>",fp_ou);
308 
309 				if (IndexTree == INDEX_TREE_DATE)
310 					sprintf(tmp6,"../%s",ImageFile);
311 				else
312 					strcpy(tmp6,"../../images");
313 
314 				if ((ReportType & REPORT_TYPE_SITE_USER_TIME_DATE) != 0) {
315 					url_to_anchor(url,siteind,sizeof(siteind));
316 					fprintf(fp_ou,"<td class=\"data\"><a href=\"tt.html#%s\"><img src=\"%s/datetime.png\" title=\"%s\" alt=\"T\"></a></td>",siteind,tmp6,_("date/time report"));
317 				} else {
318 					fprintf(fp_ou,"<td class=\"data\"></td>");
319 				}
320 
321 				if (Privacy)
322 					fprintf(fp_ou,"<td class=\"data2\"><span style=\"color:%s;\">%s</span></td>",PrivacyStringColor,PrivacyString);
323 				else {
324 					fputs("<td class=\"data2\">",fp_ou);
325 					if (BlockIt[0]!='\0' && url[0]!=ALIAS_PREFIX) {
326 						fprintf(fp_ou,"<a href=\"%s%s?url=",wwwDocumentRoot,BlockIt);
327 						output_html_url(fp_ou,url);
328 						fprintf(fp_ou,"\"><img src=\"%s/sarg-squidguard-block.png\"></a>&nbsp;",tmp6);
329 					}
330 					output_html_link(fp_ou,url,100);
331 					fputs("</td>",fp_ou);
332 				}
333 
334 				if ((UserReportFields & USERREPORTFIELDS_CONNECT) != 0) {
335 					fputs("<td class=\"data\"",fp_ou);
336 					if (SortTableJs[0]) fprintf(fp_ou," sorttable_customkey=\"%"PRId64"\"",(int64_t)twork);
337 					fprintf(fp_ou,">%s</td>",fixnum(twork,1));
338 				}
339 				if ((UserReportFields & USERREPORTFIELDS_BYTES) != 0) {
340 					fputs("<td class=\"data\"",fp_ou);
341 					if (SortTableJs[0]) fprintf(fp_ou," sorttable_customkey=\"%"PRId64"\"",(int64_t)nnbytes);
342 					fprintf(fp_ou,">%s</td>",fixnum(nnbytes,1));
343 				}
344 				if ((UserReportFields & USERREPORTFIELDS_SETYB) != 0) {
345 					perc=(tnbytes) ? nnbytes * 100. / tnbytes : 0.;
346 					fprintf(fp_ou,"<td class=\"data\">%3.2lf%%</td>",perc);
347 				}
348 				if ((UserReportFields & USERREPORTFIELDS_IN_CACHE_OUT) != 0) {
349 					inperc=(nnbytes) ? incache * 100. / nnbytes : 0.;
350 					ouperc=(nnbytes) ? oucache * 100. / nnbytes : 0.;
351 					fprintf(fp_ou,"<td class=\"data\">%3.2lf%%</td><td class=\"data\">%3.2lf%%</td>",inperc,ouperc);
352 				}
353 				if ((UserReportFields & USERREPORTFIELDS_USED_TIME) != 0) {
354 					fputs("<td class=\"data\"",fp_ou);
355 					if (SortTableJs[0]) fprintf(fp_ou," sorttable_customkey=\"%"PRId64"\"",(int64_t)nnelap);
356 					fprintf(fp_ou,">%s</td>",buildtime(nnelap));
357 				}
358 				if ((UserReportFields & USERREPORTFIELDS_MILISEC) != 0) {
359 					fputs("<td class=\"data\"",fp_ou);
360 					if (SortTableJs[0]) fprintf(fp_ou," sorttable_customkey=\"%"PRId64"\"",(int64_t)nnelap);
361 					fprintf(fp_ou,">%s</td>",fixnum2(nnelap,1));
362 				}
363 				if ((UserReportFields & USERREPORTFIELDS_PTIME) != 0) {
364 					perc2=(tnelap) ? nnelap * 100. / tnelap : 0.;
365 					fprintf(fp_ou,"<td class=\"data\">%3.2lf%%</td>",perc2);
366 				}
367 
368 				if (strncmp(tmsg,"OK",2) != 0)
369 					fprintf(fp_ou,"<td class=\"data\">%s</td>",_("DENIED"));
370 
371 				fputs("</tr>\n",fp_ou);
372 				count++;
373 			} else if ((ReportType & REPORT_TYPE_SITE_USER_TIME_DATE) != 0) {
374 				format_path(__FILE__, __LINE__, warea,sizeof(warea), "%s/%s/tt.html", outdirname, uinfo->filename);
375 				if (unlink(warea)!=0) {
376 					debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),warea,strerror(errno));
377 				}
378 			}
379 
380 			if (iprel) {
381 				if (snprintf(arqip,sizeof(arqip),"%s/%s.ip",tmp,uinfo->filename)>=sizeof(arqip)) {
382 					debuga(__FILE__,__LINE__,_("Path too long: "));
383 					debuga_more("%s/%s.ip\n",tmp,uinfo->filename);
384 					exit(EXIT_FAILURE);
385 				}
386 
387 				if ((fp_ip = FileObject_Open(arqip)) == 0){
388 					debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),arqip,FileObject_GetLastOpenError());
389 					exit(EXIT_FAILURE);
390 				}
391 
392 				if ((fp_ip2 = MY_FOPEN(tmp2, "a")) == 0){
393 					debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),tmp2,strerror(errno));
394 					exit(EXIT_FAILURE);
395 				}
396 
397 				if ((line1=longline_create())==NULL) {
398 					debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),arqip);
399 					exit(EXIT_FAILURE);
400 				}
401 				while((buf=longline_read(fp_ip,line1))!=NULL) {
402 					getword_start(&gwarea,buf);
403 					if (getword(user_ip,sizeof(user_ip),&gwarea,'\t')<0) {
404 						debuga(__FILE__,__LINE__,_("Invalid user IP in file \"%s\"\n"),tmp3);
405 						exit(EXIT_FAILURE);
406 					}
407 					if (getword_ptr(buf,&user_url,&gwarea,'\t')<0) {
408 						debuga(__FILE__,__LINE__,_("Invalid url in file \"%s\"\n"),tmp3);
409 						exit(EXIT_FAILURE);
410 					}
411 					if (strncmp(user_url,url,strlen(url))!=0) continue;
412 					if (getword_skip(15,&gwarea,'\t')<0) {
413 						debuga(__FILE__,__LINE__,_("Invalid day in file \"%s\"\n"),tmp3);
414 						exit(EXIT_FAILURE);
415 					}
416 					if (getword_skip(15,&gwarea,'\t')<0) {
417 						debuga(__FILE__,__LINE__,_("Invalid time in file \"%s\"\n"),tmp3);
418 						exit(EXIT_FAILURE);
419 					}
420 					if (getword_atoll(&userbytes,&gwarea,'\t')<0) {
421 						debuga(__FILE__,__LINE__,_("Invalid size in file \"%s\"\n"),tmp3);
422 						exit(EXIT_FAILURE);
423 					}
424 					if (getword_atoll(&userelap,&gwarea,'\0')<0) {
425 						debuga(__FILE__,__LINE__,_("Invalid elapsed time in file \"%s\"\n"),tmp3);
426 						exit(EXIT_FAILURE);
427 					}
428 					fprintf(fp_ip2,"%s\t%"PRIu64"\t%"PRIu64"\n",user_ip,(uint64_t)userbytes,(uint64_t)userelap);
429 				}
430 				longline_destroy(&line1);
431 
432 				if (fclose(fp_ip2)==EOF) {
433 					debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),tmp2,strerror(errno));
434 					exit(EXIT_FAILURE);
435 				}
436 				if (FileObject_Close(fp_ip)) {
437 					debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),arqip,FileObject_GetLastCloseError());
438 					exit(EXIT_FAILURE);
439 				}
440 
441 				if (snprintf(csort,sizeof(csort),"sort -n -t \"\t\" -T \"%s\" -k 1,1 -k 2,2 -o \"%s\" \"%s\"",tmp,tmp3,tmp2)>=sizeof(csort)) {
442 					debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),tmp2,tmp3);
443 					exit(EXIT_FAILURE);
444 				}
445 				cstatus=system(csort);
446 				if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
447 					debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
448 					debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
449 					exit(EXIT_FAILURE);
450 				}
451 
452 				if ((fp_ip = FileObject_Open(tmp3)) == 0) {
453 					debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),tmp3,FileObject_GetLastOpenError());
454 					exit(EXIT_FAILURE);
455 				}
456 
457 				if (unlink(tmp2)) {
458 					debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),tmp2,strerror(errno));
459 					exit(EXIT_FAILURE);
460 				}
461 
462 				olduserip[0]='\0';
463 
464 				if ((line1=longline_create())==NULL) {
465 					debuga(__FILE__,__LINE__,_("Not enough memory to read file \"%s\"\n"),arqip);
466 					exit(EXIT_FAILURE);
467 				}
468 				while((buf=longline_read(fp_ip,line1))!=NULL) {
469 					getword_start(&gwarea,buf);
470 					if (getword(user_ip,sizeof(user_ip),&gwarea,'\t')<0) {
471 						debuga(__FILE__,__LINE__,_("Invalid user IP in file \"%s\"\n"),tmp3);
472 						exit(EXIT_FAILURE);
473 					}
474 					if (getword_atoll(&userbytes,&gwarea,'\t')<0) {
475 						debuga(__FILE__,__LINE__,_("Invalid size in file \"%s\"\n"),tmp3);
476 						exit(EXIT_FAILURE);
477 					}
478 					if (getword_atoll(&userelap,&gwarea,'\0')<0) {
479 						debuga(__FILE__,__LINE__,_("Invalid elapsed time in file \"%s\"\n"),tmp3);
480 						exit(EXIT_FAILURE);
481 					}
482 					if (strcmp(user_ip,olduserip) != 0) {
483 						if (olduserip[0]!='\0') {
484 							fprintf(fp_ou,"<tr><td></td><td class=\"data\">%s</td>",olduserip);
485 							if ((UserReportFields & USERREPORTFIELDS_CONNECT) != 0)
486 								fputs("<td></td>",fp_ou);
487 							if ((UserReportFields & USERREPORTFIELDS_BYTES) != 0)
488 								fprintf(fp_ou,"<td class=\"data\">%s</td>",fixnum(unbytes,1));
489 							if ((UserReportFields & USERREPORTFIELDS_SETYB) != 0)
490 								fputs("<td></td>",fp_ou);
491 							if ((UserReportFields & USERREPORTFIELDS_IN_CACHE_OUT) != 0)
492 								fputs("</td><td></td><td></td>",fp_ou);
493 							if ((UserReportFields & USERREPORTFIELDS_USED_TIME) != 0)
494 								fprintf(fp_ou,"<td class=\"data\">%s</td>",buildtime(unelap));
495 							if ((UserReportFields & USERREPORTFIELDS_MILISEC) != 0)
496 								fprintf(fp_ou,"<td class=\"data\">%s</td>",fixnum2(unelap,1));
497 							fputs("</tr>\n",fp_ou);
498 						}
499 
500 						strcpy(olduserip,user_ip);
501 						unbytes=0;
502 						unelap=0;
503 					}
504 
505 					unbytes+=userbytes;
506 					unelap+=userelap;
507 				}
508 
509 				if (FileObject_Close(fp_ip)) {
510 					debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),tmp3,FileObject_GetLastCloseError());
511 					exit(EXIT_FAILURE);
512 				}
513 				longline_destroy(&line1);
514 
515 				if (unlink(tmp3)) {
516 					debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),tmp3,strerror(errno));
517 					exit(EXIT_FAILURE);
518 				}
519 
520 				if (olduserip[0]!='\0') {
521 					fprintf(fp_ou,"<tr><td></td><td class=\"data\">%s</td>",olduserip);
522 					if ((UserReportFields & USERREPORTFIELDS_CONNECT) != 0)
523 						fputs("<td></td>",fp_ou);
524 					if ((UserReportFields & USERREPORTFIELDS_BYTES) != 0)
525 						fprintf(fp_ou,"<td class=\"data\">%s</td>",fixnum(unbytes,1));
526 					if ((UserReportFields & USERREPORTFIELDS_SETYB) != 0)
527 						fputs("<td></td>",fp_ou);
528 					if ((UserReportFields & USERREPORTFIELDS_IN_CACHE_OUT) != 0)
529 						fputs("</td><td></td><td></td>",fp_ou);
530 					if ((UserReportFields & USERREPORTFIELDS_USED_TIME) != 0)
531 						fprintf(fp_ou,"<td class=\"data\">%s</td>",buildtime(unelap));
532 					if ((UserReportFields & USERREPORTFIELDS_MILISEC) != 0)
533 						fprintf(fp_ou,"<td class=\"data\">%s</td>",fixnum2(unelap,1));
534 					fputs("</tr>\n",fp_ou);
535 				}
536 			}
537 
538 			unbytes=0;
539 			unelap=0;
540 		}
541 
542 		if (FileObject_Close(fp_in)) {
543 			debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),arqin,FileObject_GetLastCloseError());
544 			exit(EXIT_FAILURE);
545 		}
546 		longline_destroy(&line);
547 
548 		if (iprel && arqip[0]) {
549 			if (!KeepTempLog && unlink(arqip)) {
550 				debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),arqip,strerror(errno));
551 				exit(EXIT_FAILURE);
552 			}
553 		}
554 		if (!KeepTempLog && unlink(arqin)) {
555 			debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),arqin,strerror(errno));
556 			exit(EXIT_FAILURE);
557 		}
558 
559 		if ((UserReportFields & (USERREPORTFIELDS_TOTAL | USERREPORTFIELDS_AVERAGE)) != 0)
560 			fputs("<tfoot>",fp_ou);
561 
562 		if ((UserReportFields & USERREPORTFIELDS_TOTAL) != 0) {
563 			fprintf(fp_ou,"<tr><th></th><th class=\"header_l\">%s</th>",_("TOTAL"));
564 			if ((UserReportFields & USERREPORTFIELDS_CONNECT) != 0)
565 				fprintf(fp_ou,"<th class=\"header_r\">%s</th>",fixnum(tnacc,1));
566 			if ((UserReportFields & USERREPORTFIELDS_BYTES) != 0)
567 				fprintf(fp_ou,"<th class=\"header_r\">%s</th>",fixnum(tnbytes,1));
568 			if ((UserReportFields & USERREPORTFIELDS_SETYB) != 0) {
569 				perc=(totbytes) ? tnbytes *100. / totbytes :0.;
570 				fprintf(fp_ou,"<th class=\"header_r\">%3.2lf%%</th>",perc);
571 			}
572 			if ((UserReportFields & USERREPORTFIELDS_IN_CACHE_OUT) != 0) {
573 				inperc=(tnbytes) ? tnincache * 100. / tnbytes : 0.;
574 				ouperc=(tnbytes) ? tnoucache * 100. / tnbytes : 0.;
575 				fprintf(fp_ou,"<th class=\"header_r\">%3.2lf%%</th><th class=\"header_r\">%3.2lf%%</th>",inperc,ouperc);
576 			}
577 			if ((UserReportFields & USERREPORTFIELDS_USED_TIME) != 0)
578 				fprintf(fp_ou,"<th class=\"header_r\">%s</th>",buildtime(tnelap));
579 			if ((UserReportFields & USERREPORTFIELDS_MILISEC) != 0)
580 				fprintf(fp_ou,"<th class=\"header_r\">%s</th>",fixnum2(tnelap,1));
581 			if ((UserReportFields & USERREPORTFIELDS_PTIME) != 0) {
582 				perc2=(totelap) ? tnelap * 100. / totelap : 0.;
583 				fprintf(fp_ou,"<th class=\"header_r\">%3.2lf%%</th>",perc2);
584 			}
585 			fputs("</tr>\n",fp_ou);
586 		}
587 
588 		if (PerUserLimitsNumber>0) {
589 			int limit=(int)(tnbytes/1000000LLU);
590 			int maskid;
591 			int mask;
592 			for (i=0 ; i<PerUserLimitsNumber ; i++) {
593 				maskid=i/sizeof(unsigned int);
594 				mask=0x1U << (i % sizeof(unsigned int));
595 				if (limit>PerUserLimits[i].Limit && (user_limit[maskid] & mask)==0) {
596 					FILE *fp_usr;
597 
598 					if ((fp_usr = fopen(PerUserLimits[i].File, "at")) == 0) {
599 						debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),PerUserLimits[i].File,strerror(errno));
600 						exit(EXIT_FAILURE);
601 					}
602 					switch (PerUserLimits[i].Output)
603 					{
604 						case PUOE_UserId:
605 							fprintf(fp_usr,"%s\n",uinfo->label);
606 							break;
607 						case PUOE_UserIp:
608 							fprintf(fp_usr,"%s\n",uinfo->ip);
609 							break;
610 					}
611 					if (fclose(fp_usr)==EOF) {
612 						debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),PerUserLimits[i].File,strerror(errno));
613 						exit(EXIT_FAILURE);
614 					}
615 					user_limit[maskid]|=mask;
616 
617 					if (debug)
618 						debuga(__FILE__,__LINE__,_("Limit exceeded for user %s (%d MB). Added to file \"%s\"\n"),uinfo->label,
619 							   PerUserLimits[i].Limit,PerUserLimits[i].File);
620 				}
621 			}
622 		}
623 
624 		if ((ReportType & REPORT_TYPE_TOPUSERS) != 0 && (UserReportFields & USERREPORTFIELDS_AVERAGE) != 0) {
625 			totbytes2=totbytes/ntotuser;
626 			totelap2=totelap/ntotuser;
627 
628 			fprintf(fp_ou,"<tr><th></th><th class=\"header_l\">%s</th>",_("AVERAGE"));
629 			if ((UserReportFields & USERREPORTFIELDS_CONNECT) != 0)
630 				fprintf(fp_ou,"<th class=\"header_r\">%s</th>",fixnum(ttnacc/ntotuser,1));
631 			if ((UserReportFields & USERREPORTFIELDS_BYTES) != 0)
632 				fprintf(fp_ou,"<th class=\"header_r\">%s</th>",fixnum(totbytes2,1));
633 			fprintf(fp_ou,"<th></th><th></th><th></th>");
634 			if ((UserReportFields & USERREPORTFIELDS_USED_TIME) != 0)
635 				fprintf(fp_ou,"<th class=\"header_r\">%s</th>",buildtime(totelap2));
636 			if ((UserReportFields & USERREPORTFIELDS_MILISEC) != 0)
637 				fprintf(fp_ou,"<th class=\"header_r\">%s</th>",fixnum2(totelap2,1));
638 			if ((UserReportFields & USERREPORTFIELDS_PTIME) != 0) {
639 				perc2 = (totelap) ? totelap2 * 100. / totelap : 0.;
640 				fprintf(fp_ou,"<th class=\"header_r\">%3.2lf%%</th>",perc2);
641 			}
642 			fputs("</tr>\n",fp_ou);
643 		}
644 
645 		if ((UserReportFields & (USERREPORTFIELDS_TOTAL | USERREPORTFIELDS_AVERAGE)) != 0)
646 			fputs("</tfoot>",fp_ou);
647 
648 		fputs("</table></div>\n",fp_ou);
649 		write_html_trailer(fp_ou);
650 		if (fclose(fp_ou)==EOF) {
651 			debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),arqou,strerror(errno));
652 			exit(EXIT_FAILURE);
653 		}
654 
655 		htaccess(uinfo);
656 	}
657 
658 	userinfo_stopscan(uscan);
659 
660 	return;
661 }
662