]> git.ipfire.org Git - thirdparty/sarg.git/blame - useragent.c
Create a user agent report if the input log provides the information
[thirdparty/sarg.git] / useragent.c
CommitLineData
25697a35 1/*
94ff9470 2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
110ce984 3 * 1998, 2015
25697a35
GS
4 *
5 * SARG donations:
6 * please look at http://sarg.sourceforge.net/donations.php
1164c474
FM
7 * Support:
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
25697a35
GS
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"
5f3cfd1d 28#include "include/defs.h"
137eb63d
FM
29#include "include/filelist.h"
30
31FileListObject UserAgentLog=NULL;
25697a35 32
f009b9ad
FM
33//! Log file where the user agent data are written.
34static char UserAgentTempLog[MAXLEN]="";
35
36static struct tm UserAgentStartDate;
37static struct tm UserAgentEndDate;
38
39/*!
40 * Open the temporary file to store the useragent entries to be
41 * reported.
42 *
43 * \return The file handle. It must be closed when the data have
44 * been written.
45 */
46FILE *UserAgent_Open(void)
47{
34ad8e64 48 FILE *fp_ou=NULL;
f009b9ad
FM
49
50 if (UserAgentTempLog[0]) {
51 debuga(__FILE__,__LINE__,_("Useragent log already opened\n"));
52 exit(EXIT_FAILURE);
53 }
34ad8e64
FM
54 if ((ReportType & REPORT_TYPE_USERAGENT)!=0) {
55 snprintf(UserAgentTempLog,sizeof(UserAgentTempLog),"%s/squagent.int_unsort",tmp);
56 if ((fp_ou=fopen(UserAgentTempLog,"w"))==NULL) {
57 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),UserAgentTempLog,strerror(errno));
58 exit(EXIT_FAILURE);
59 }
60 memset(&UserAgentStartDate,0,sizeof(UserAgentStartDate));
61 memset(&UserAgentEndDate,0,sizeof(UserAgentEndDate));
f009b9ad 62 }
f009b9ad
FM
63 return(fp_ou);
64}
65
66/*!
67 * Write a user agent entry into the temporary log.
68 *
69 * \param fp The file opened by UserAgent_Open().
70 * \param Ip The IP address using this agent.
71 * \param User The user name.
72 * \param Agent The user agent string.
73 */
74void UserAgent_Write(FILE *fp,const char *Ip,const char *User,const char *Agent)
75{
34ad8e64
FM
76 if (fp) {
77 fprintf(fp,"%s\t%s\t%s\n",Ip,Agent,User);
78 useragent_count++;
79 }
f009b9ad
FM
80}
81
82/*!
83 * Read the user provided useragent file and create
84 * a temporary file with the data to report.
85 */
86void UserAgent_Readlog(void)
25697a35 87{
976c5bb7 88 FileObject *fp_log;
f009b9ad 89 FILE *fp_ou = NULL;
976c5bb7 90 char *ptr;
f009b9ad
FM
91 char ip[80], data[50], agent[MAXLEN], user[MAXLEN];
92 int day,month,year;
93 char monthname[5];
137eb63d 94 const char *FileName;
9bd92830 95 unsigned long totregsl=0;
9bd92830 96 int ndate;
9bd92830 97 struct getwordstruct gwarea, gwarea1;
976c5bb7 98 longline line;
137eb63d 99 FileListIterator FIter;
f009b9ad 100 struct tm logtime;
02d231f3
FM
101 int dfrom;
102 int duntil;
9bd92830 103
f009b9ad 104 fp_ou=UserAgent_Open();
9bd92830 105
976c5bb7
FM
106 if ((line=longline_create())==NULL) {
107 debuga(__FILE__,__LINE__,_("Not enough memory to read useragent log\n"));
108 exit(EXIT_FAILURE);
109 }
f009b9ad 110 memset(&logtime,0,sizeof(logtime));
02d231f3 111 getperiod_torange(&period,&dfrom,&duntil);
976c5bb7 112
137eb63d
FM
113 FIter=FileListIter_Open(UserAgentLog);
114 while ((FileName=FileListIter_Next(FIter))!=NULL)
115 {
976c5bb7 116 longline_reset(line);
f009b9ad 117 if ((fp_log=decomp(FileName))==NULL) {
976c5bb7 118 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),FileName,FileObject_GetLastOpenError());
9bd92830
FM
119 exit(EXIT_FAILURE);
120 }
137eb63d
FM
121
122 if(debug) {
123 debuga(__FILE__,__LINE__,_("Reading useragent log \"%s\"\n"),FileName);
9bd92830
FM
124 }
125
f009b9ad 126 while ((ptr=longline_read(fp_log,line))!=NULL) {
137eb63d 127 totregsl++;
976c5bb7 128 getword_start(&gwarea,ptr);
f009b9ad 129 if (getword(ip,sizeof(ip),&gwarea,' ')<0 || getword_skip(10,&gwarea,'[')<0 ||
137eb63d
FM
130 getword(data,sizeof(data),&gwarea,' ')<0) {
131 debuga(__FILE__,__LINE__,_("Invalid record in file \"%s\"\n"),FileName);
9bd92830
FM
132 exit(EXIT_FAILURE);
133 }
137eb63d 134 getword_start(&gwarea1,data);
f009b9ad
FM
135 if (getword_atoi(&day,&gwarea1,'/')<0 || getword(monthname,sizeof(monthname),&gwarea1,'/')<0 ||
136 getword_atoi(&year,&gwarea1,':')<0) {
137eb63d
FM
137 debuga(__FILE__,__LINE__,_("Invalid date in file \"%s\"\n"),FileName);
138 exit(EXIT_FAILURE);
139 }
f009b9ad
FM
140 month=month2num(monthname)+1;
141 if (month>12) {
142 debuga(__FILE__,__LINE__,_("Invalid month name \"%s\" found in user agent file \"%s\""),monthname,FileName);
143 exit(EXIT_FAILURE);
144 }
137eb63d 145 if (dfrom!=0 || duntil!=0){
f009b9ad 146 ndate=year*10000+month*100+day;
137eb63d
FM
147 if (ndate<dfrom) continue;
148 if (ndate>duntil) break;
149 }
f009b9ad
FM
150 logtime.tm_year=year-1900;
151 logtime.tm_mon=month-1;
152 logtime.tm_mday=day;
153 if (totregsl==1 || compare_date(&UserAgentStartDate,&logtime)>0)
154 memcpy(&UserAgentStartDate,&logtime,sizeof(logtime));
155 if (compare_date(&UserAgentEndDate,&logtime)<0)
156 memcpy(&UserAgentEndDate,&logtime,sizeof(logtime));
137eb63d
FM
157 if (getword_skip(MAXLEN,&gwarea,'"')<0 || getword(agent,sizeof(agent),&gwarea,'"')<0) {
158 debuga(__FILE__,__LINE__,_("Invalid useragent in file \"%s\"\n"),FileName);
159 exit(EXIT_FAILURE);
160 }
161
f009b9ad 162 if (gwarea.current[0]!='\0') {
137eb63d
FM
163 if (getword_skip(MAXLEN,&gwarea,' ')<0 || getword(user,sizeof(user),&gwarea,'\n')<0) {
164 debuga(__FILE__,__LINE__,_("Invalid record in file \"%s\"\n"),FileName);
165 exit(EXIT_FAILURE);
166 }
f009b9ad 167 if (user[0] == '-')
137eb63d 168 strcpy(user,ip);
f009b9ad 169 if (user[0] == '\0')
137eb63d
FM
170 strcpy(user,ip);
171 } else {
9bd92830 172 strcpy(user,ip);
137eb63d
FM
173 }
174
f009b9ad 175 UserAgent_Write(fp_ou,ip,user,agent);
9bd92830
FM
176 }
177
976c5bb7
FM
178 if (FileObject_Close(fp_log)==EOF) {
179 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),FileName,FileObject_GetLastCloseError());
137eb63d
FM
180 exit(EXIT_FAILURE);
181 }
9bd92830 182 }
137eb63d 183 FileListIter_Close(FIter);
976c5bb7 184 longline_destroy(&line);
9bd92830
FM
185
186 if(debug) {
af961877 187 debuga(__FILE__,__LINE__,_(" Records read: %ld\n"),totregsl);
9bd92830
FM
188 }
189
9bd92830 190 if (fclose(fp_ou)==EOF) {
f009b9ad 191 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),UserAgentTempLog,strerror(errno));
9bd92830
FM
192 exit(EXIT_FAILURE);
193 }
f009b9ad
FM
194}
195
196void UserAgent(void)
197{
198 FILE *fp_in = NULL, *fp_ou = NULL, *fp_ht = NULL;
199 char buf[MAXLEN];
200 char ip[80], agent[MAXLEN], user[MAXLEN];
201 char ipbefore[MAXLEN]="";
202 char namebefore[MAXLEN]="";
203 char tagent[MAXLEN];
204 char user_old[MAXLEN]="";
205 char agent_old[MAXLEN]="";
206 char hfile[MAXLEN];
207 char idate[100], fdate[100];
208 char tmp2[MAXLEN];
209 char tmp3[MAXLEN];
210 char csort[MAXLEN];
211 int agentot=0, agentot2=0, agentdif=0, cont=0, nagent;
212 int cstatus;
213 double perc;
214 struct getwordstruct gwarea;
215
34ad8e64 216 if (!UserAgentTempLog[0] || useragent_count==0) return;
f009b9ad
FM
217
218 snprintf(tmp2,sizeof(tmp2),"%s/squagent.int_log",tmp);
219 if (debug) {
af961877 220 debuga(__FILE__,__LINE__,_("Sorting file \"%s\"\n"),tmp2);
9bd92830
FM
221 }
222
f009b9ad
FM
223 if (snprintf(csort,sizeof(csort),"sort -n -t \"\t\" -k 3,3 -k 2,2 -k 1,1 -o \"%s\" \"%s\"",tmp2,UserAgentTempLog)>=sizeof(csort)) {
224 debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),tmp2,UserAgentTempLog);
78eeb33f
FM
225 exit(EXIT_FAILURE);
226 }
9bd92830
FM
227 cstatus=system(csort);
228 if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
af961877
FM
229 debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
230 debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
9bd92830
FM
231 exit(EXIT_FAILURE);
232 }
f009b9ad 233 if ((fp_in=fopen(tmp2,"r"))==NULL) {
af961877
FM
234 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),tmp2,strerror(errno));
235 debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
9bd92830
FM
236 exit(EXIT_FAILURE);
237 }
238
f009b9ad
FM
239 if (!KeepTempLog && unlink(UserAgentTempLog)) {
240 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),UserAgentTempLog,strerror(errno));
08f9b029
FM
241 exit(EXIT_FAILURE);
242 }
9bd92830
FM
243
244 snprintf(hfile,sizeof(hfile),"%s/useragent.html", outdirname);
f009b9ad 245 if ((fp_ht=fopen(hfile,"w"))==NULL) {
af961877 246 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),hfile,strerror(errno));
9bd92830
FM
247 exit(EXIT_FAILURE);
248 }
249
f009b9ad 250 if (debug)
af961877 251 debuga(__FILE__,__LINE__,_("Making Useragent report\n"));
9bd92830
FM
252
253 write_html_header(fp_ht,(IndexTree == INDEX_TREE_DATE) ? 3 : 1,_("Squid Useragent's Report"),HTML_JS_NONE);
254 fprintf(fp_ht,"<tr><th class=\"header_c\">%s</th></tr>\n",_("Squid Useragent's Report"));
f009b9ad
FM
255 strftime(idate,sizeof(idate),"%x",&UserAgentStartDate);
256 strftime(fdate,sizeof(fdate),"%x",&UserAgentEndDate);
9bd92830
FM
257 fprintf(fp_ht,"<tr><td class=\"header_c\">%s: %s - %s</td></tr>\n",_("Period"),idate,fdate);
258 close_html_header(fp_ht);
259
260 fputs("<br><br>\n",fp_ht);
261
262 fputs("<div class=\"report\"><table cellpadding=\"0\" cellspacing=\"0\">\n",fp_ht);
263 fputs("<tr><td>&nbsp;</td><td>&nbsp;</td></tr>",fp_ht);
264
265 fprintf(fp_ht,"<tr><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th></tr>\n",_("USERID"),_("AGENT"));
266
f009b9ad 267 while (fgets(buf,sizeof(buf),fp_in)!=NULL) {
9bd92830
FM
268 getword_start(&gwarea,buf);
269 if (getword(ip,sizeof(ip),&gwarea,'\t')<0) {
af961877 270 debuga(__FILE__,__LINE__,_("Invalid IP address in file \"%s\"\n"),tmp2);
9bd92830
FM
271 exit(EXIT_FAILURE);
272 }
273
f009b9ad
FM
274 if (Ip2Name) {
275 if (strcmp(ip,ipbefore) != 0) {
9bd92830
FM
276 strcpy(ipbefore,ip);
277 ip2name(ip,sizeof(ip));
278 strcpy(namebefore,ip);
279 } else strcpy(ip,namebefore);
280 }
281
282 if (getword(agent,sizeof(agent),&gwarea,'\t')<0) {
af961877 283 debuga(__FILE__,__LINE__,_("Invalid useragent in file \"%s\"\n"),tmp2);
9bd92830
FM
284 exit(EXIT_FAILURE);
285 }
286 if (getword(user,sizeof(user),&gwarea,'\t')<0) {
af961877 287 debuga(__FILE__,__LINE__,_("Invalid user ID in file \"%s\"\n"),tmp2);
9bd92830
FM
288 exit(EXIT_FAILURE);
289 }
290
f009b9ad 291 if (strcmp(user,user_old) != 0) {
9bd92830
FM
292 fprintf(fp_ht,"<tr><td class=\"data2\">%s</td><td class=\"data2\">",user);
293 output_html_string(fp_ht,agent,250);
294 fputs("</td></tr>\n",fp_ht);
295 strcpy(user_old,user);
296 strcpy(agent_old,agent);
f009b9ad 297 } else if (strcmp(agent,agent_old) != 0) {
9bd92830
FM
298 fputs("<tr><td></td><td class=\"data2\">",fp_ht);
299 output_html_string(fp_ht,agent,250);
300 fputs("</td></tr>\n",fp_ht);
301 strcpy(agent_old,agent);
302 }
303 }
304
305 fputs("</table>\n",fp_ht);
204781f4 306 if (fclose(fp_in)==EOF) {
af961877 307 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),tmp2,strerror(errno));
204781f4
FM
308 exit(EXIT_FAILURE);
309 }
9bd92830 310
f009b9ad 311 snprintf(tmp3,sizeof(tmp3),"%s/squagent2.int_log",tmp);
78eeb33f 312 if (snprintf(csort,sizeof(csort),"sort -t \"\t\" -k 2,2 -o \"%s\" \"%s\"",tmp3,tmp2)>=sizeof(csort)) {
af961877 313 debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),tmp2,tmp3);
78eeb33f
FM
314 exit(EXIT_FAILURE);
315 }
9bd92830
FM
316 cstatus=system(csort);
317 if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
af961877
FM
318 debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
319 debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
9bd92830
FM
320 exit(EXIT_FAILURE);
321 }
f009b9ad 322 if ((fp_in=fopen(tmp3,"r"))==NULL) {
af961877
FM
323 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),tmp3,strerror(errno));
324 debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
9bd92830
FM
325 exit(EXIT_FAILURE);
326 }
327
11767c6a 328 if (!KeepTempLog && unlink(tmp2)) {
af961877 329 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),tmp2,strerror(errno));
08f9b029
FM
330 exit(EXIT_FAILURE);
331 }
9bd92830 332
f009b9ad 333 if ((fp_ou=fopen(tmp2,"w"))==NULL) {
af961877 334 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),tmp2,strerror(errno));
9bd92830
FM
335 exit(EXIT_FAILURE);
336 }
337
338 agent_old[0]='\0';
339 cont=0;
340
f009b9ad 341 while (fgets(buf,sizeof(buf),fp_in)!=NULL) {
9bd92830
FM
342 getword_start(&gwarea,buf);
343 if (getword(ip,sizeof(ip),&gwarea,'\t')<0) {
af961877 344 debuga(__FILE__,__LINE__,_("Invalid IP address in file \"%s\"\n"),tmp3);
9bd92830
FM
345 exit(EXIT_FAILURE);
346 }
347 if (getword(agent,sizeof(agent),&gwarea,'\t')<0) {
af961877 348 debuga(__FILE__,__LINE__,_("Invalid useragent in file \"%s\"\n"),tmp3);
9bd92830
FM
349 exit(EXIT_FAILURE);
350 }
351
f009b9ad 352 if (!cont) {
9bd92830
FM
353 cont++;
354 strcpy(agent_old,agent);
355 }
356
f009b9ad 357 if (strcmp(agent,agent_old) != 0) {
9bd92830
FM
358 agentdif++;
359 fprintf(fp_ou,"%06d %s\n",agentot,agent_old);
360 strcpy(agent_old,agent);
361 agentot2+=agentot;
362 agentot=0;
363 }
364 agentot++;
365 }
366 agentdif++;
367 fprintf(fp_ou,"%06d %s\n",agentot,agent);
368 agentot2+=agentot;
369
9bd92830 370 if (fclose(fp_ou)==EOF) {
af961877 371 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),tmp2,strerror(errno));
9bd92830
FM
372 exit(EXIT_FAILURE);
373 }
204781f4 374 if (fclose(fp_in)==EOF) {
af961877 375 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),tmp3,strerror(errno));
204781f4
FM
376 exit(EXIT_FAILURE);
377 }
9bd92830 378
11767c6a 379 if (!KeepTempLog && unlink(tmp3)) {
af961877 380 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),tmp3,strerror(errno));
08f9b029
FM
381 exit(EXIT_FAILURE);
382 }
9bd92830 383
78eeb33f 384 if (snprintf(csort,sizeof(csort),"sort -n -r -k 1,1 -o \"%s\" \"%s\"",tmp3,tmp2)>=sizeof(csort)) {
af961877 385 debuga(__FILE__,__LINE__,_("Sort command too long when sorting file \"%s\" to \"%s\"\n"),tmp2,tmp3);
78eeb33f
FM
386 exit(EXIT_FAILURE);
387 }
9bd92830
FM
388 cstatus=system(csort);
389 if (!WIFEXITED(cstatus) || WEXITSTATUS(cstatus)) {
af961877
FM
390 debuga(__FILE__,__LINE__,_("sort command return status %d\n"),WEXITSTATUS(cstatus));
391 debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
9bd92830
FM
392 exit(EXIT_FAILURE);
393 }
394 if((fp_in=fopen(tmp3,"r"))==NULL) {
af961877
FM
395 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),tmp3,strerror(errno));
396 debuga(__FILE__,__LINE__,_("sort command: %s\n"),csort);
9bd92830
FM
397 exit(EXIT_FAILURE);
398 }
399
11767c6a 400 if (!KeepTempLog && unlink(tmp2)) {
af961877 401 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),tmp2,strerror(errno));
08f9b029
FM
402 exit(EXIT_FAILURE);
403 }
9bd92830
FM
404
405 fputs("<br><br>\n",fp_ht);
406
407 fputs("<table cellpadding=\"0\" cellspacing=\"0\">\n",fp_ht);
408 fprintf(fp_ht,"<tr><th class=\"header_l\">%s</th><th class=\"header_l\">%s</th><th class=\"header_c\">%%</th></tr>\n",_("AGENT"),_("TOTAL"));
409
410 perc=0.;
411 while(fgets(buf,sizeof(buf),fp_in)!=NULL) {
412 fixendofline(buf);
413 getword_start(&gwarea,buf);
414 if (getword(tagent,sizeof(tagent),&gwarea,' ')<0) {
af961877 415 debuga(__FILE__,__LINE__,_("Invalid useragent in file \"%s\"\n"),tmp3);
9bd92830
FM
416 exit(EXIT_FAILURE);
417 }
418 nagent=atoi(tagent);
419 perc=(agentot2>0) ? nagent * 100. / agentot2 : 0.;
420
421 fputs("<tr><td class=\"data2\">",fp_ht);
422 output_html_string(fp_ht,gwarea.current,250);
423 fprintf(fp_ht,"</td><td class=\"data\">%d</td><td class=\"data\">%3.2lf</td></tr>\n",nagent,perc);
424 }
204781f4 425 if (fclose(fp_in)==EOF) {
af961877 426 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),tmp3,strerror(errno));
204781f4
FM
427 exit(EXIT_FAILURE);
428 }
9bd92830
FM
429
430 fputs("</table></div>\n",fp_ht);
342bd723 431 write_html_trailer(fp_ht);
507460ae 432 if (fclose(fp_ht)==EOF) {
af961877 433 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),hfile,strerror(errno));
507460ae
FM
434 exit(EXIT_FAILURE);
435 }
9bd92830 436
11767c6a 437 if (!KeepTempLog && unlink(tmp3)) {
af961877 438 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),tmp3,strerror(errno));
08f9b029
FM
439 exit(EXIT_FAILURE);
440 }
9bd92830
FM
441
442 return;
25697a35 443}