]> git.ipfire.org Git - thirdparty/sarg.git/blob - util.c
Display some messages to understand why sarg isn't doing something
[thirdparty/sarg.git] / util.c
1 /*
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
3 * 1998, 2011
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 // #define LEGACY_MY_ATOLL
28 // #define LEGACY_TESTVALIDUSERCHAR
29
30 #include "include/conf.h"
31 #include "include/defs.h"
32
33 #if defined(HAVE_BACKTRACE)
34 #define USE_GETWORD_BACKTRACE 1
35 #else
36 #define USE_GETWORD_BACKTRACE 0
37 #endif
38
39 static char mtab1[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
40
41 //! The list of the HTTP codes to exclude from the report.
42 static char *excludecode=NULL;
43
44 #if USE_GETWORD_BACKTRACE
45 static void getword_backtrace(void)
46 {
47 void *buffer[5];
48 int i, n;
49 char **calls;
50
51 n=backtrace(buffer,sizeof(buffer)/sizeof(buffer[0]));
52 if (n<=0) return;
53 calls=backtrace_symbols(buffer,n);
54 if (calls) {
55 debuga(_("getword backtrace:\n"));
56 for (i=0 ; i<n ; i++) {
57 fprintf(stderr,"SARG: %d:%s\n",i+1,calls[i]);
58 }
59 free(calls);
60 }
61 }
62 #endif //USE_GETWORD_BACKTRACE
63
64 void getword_start(struct getwordstruct *gwarea, const char *line)
65 {
66 gwarea->beginning=line;
67 gwarea->current=line;
68 gwarea->modified=0;
69 }
70
71 void getword_restart(struct getwordstruct *gwarea)
72 {
73 if (gwarea->modified) {
74 debuga(_("Cannot parse again the line as it was modified\n"));
75 exit(EXIT_FAILURE);
76 }
77 gwarea->current=gwarea->beginning;
78 }
79
80 int getword(char *word, int limit, struct getwordstruct *gwarea, char stop)
81 {
82 int x;
83
84 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
85 if(x>=limit) {
86 printf("SARG: getword loop detected after %d bytes.\n",x);
87 printf("SARG: Line=\"%s\"\n",gwarea->beginning);
88 printf("SARG: Record=\"%s\"\n",gwarea->current);
89 printf("SARG: searching for \'x%x\'\n",stop);
90 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
91 word[(limit>0) ? limit-1 : 0]='\0';
92 #if USE_GETWORD_BACKTRACE
93 getword_backtrace();
94 #endif
95 return(-1);
96 }
97 word[x] = gwarea->current[x];
98 }
99
100 word[x] = '\0';
101 if (gwarea->current[x]) ++x;
102 gwarea->current+=x;
103 return(0);
104 }
105
106 int getword_limit(char *word, int limit, struct getwordstruct *gwarea, char stop)
107 {
108 int x;
109
110 limit--;
111 for(x=0; x<limit && gwarea->current[x] && gwarea->current[x] != stop ;x++) {
112 word[x] = gwarea->current[x];
113 }
114 word[x] = '\0';
115 gwarea->current+=x;
116 while (*gwarea->current && *gwarea->current != stop) gwarea->current++;
117 if (*gwarea->current) ++gwarea->current;
118 return(0);
119 }
120
121 int getword_multisep(char *word, int limit, struct getwordstruct *gwarea, char stop)
122 {
123 int x;
124
125 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++) {
126 if(x>=limit) {
127 printf("SARG: getword_multisep loop detected.\n");
128 printf("SARG: Line=\"%s\"\n",gwarea->beginning);
129 printf("SARG: Record=\"%s\"\n",gwarea->current);
130 printf("SARG: searching for \'x%x\'\n",stop);
131 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
132 if (limit>0) word[limit-1]='\0';
133 #if USE_GETWORD_BACKTRACE
134 getword_backtrace();
135 #endif
136 //exit(EXIT_FAILURE);
137 return(-1);
138 }
139 word[x] = gwarea->current[x];
140 }
141
142 word[x] = '\0';
143 while (gwarea->current[x] && gwarea->current[x]==stop) ++x;
144 gwarea->current+=x;
145 return(0);
146 }
147
148 int getword_skip(int limit, struct getwordstruct *gwarea, char stop)
149 {
150 int x;
151
152 for(x=0;(gwarea->current[x] && (gwarea->current[x] != stop ));x++) {
153 if(x>=limit) {
154 printf("SARG: getword_skip loop detected after %d bytes.\n",x);
155 printf("SARG: Line=\"%s\"\n",gwarea->beginning);
156 printf("SARG: Record=\"%s\"\n",gwarea->current);
157 printf("SARG: searching for \'x%x\'\n",stop);
158 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
159 #if USE_GETWORD_BACKTRACE
160 getword_backtrace();
161 #endif
162 return(-1);
163 }
164 }
165
166 if (gwarea->current[x]) ++x;
167 gwarea->current+=x;
168 return(0);
169 }
170
171 int getword_atoll(long long int *number, struct getwordstruct *gwarea, char stop)
172 {
173 int x;
174 int sign=+1;
175 int digit;
176
177 if (gwarea->current[0] == '-') {
178 gwarea->current++;
179 sign=-1;
180 } else if (gwarea->current[0] == '+') {
181 gwarea->current++;
182 }
183 *number=0LL;
184 for(x=0;isdigit(gwarea->current[x]);x++) {
185 digit=gwarea->current[x]-'0';
186 if (*number >= (LLONG_MAX-digit)/10) {
187 debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea->beginning);
188 return(-1);
189 }
190 *number=(*number * 10) + digit;
191 }
192 if(gwarea->current[x] && gwarea->current[x]!=stop) {
193 printf("SARG: getword_atoll loop detected after %d bytes.\n",x);
194 printf("SARG: Line=\"%s\"\n",gwarea->beginning);
195 printf("SARG: Record=\"%s\"\n",gwarea->current);
196 printf("SARG: searching for \'x%x\'\n",stop);
197 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
198 #if USE_GETWORD_BACKTRACE
199 getword_backtrace();
200 #endif
201 return(-1);
202 }
203 *number*=sign;
204
205 if (gwarea->current[x]) ++x;
206 gwarea->current+=x;
207 return(0);
208 }
209
210 int getword_atoi(int *number, struct getwordstruct *gwarea, char stop)
211 {
212 int x;
213 int sign=+1;
214 int digit;
215
216 if (gwarea->current[0] == '-') {
217 gwarea->current++;
218 sign=-1;
219 } else if (gwarea->current[0] == '+') {
220 gwarea->current++;
221 }
222 *number=0;
223 for(x=0;isdigit(gwarea->current[x]);x++) {
224 digit=gwarea->current[x]-'0';
225 if (*number > (INT_MAX-digit)/10) {
226 debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea->beginning);
227 return(-1);
228 }
229 *number=(*number * 10) + digit;
230 }
231 if(gwarea->current[x] && gwarea->current[x]!=stop) {
232 printf("SARG: getword_atoi loop detected after %d bytes.\n",x);
233 printf("SARG: Line=\"%s\"\n",gwarea->beginning);
234 printf("SARG: Record=\"%s\"\n",gwarea->current);
235 printf("SARG: searching for \'x%x\'\n",stop);
236 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
237 #if USE_GETWORD_BACKTRACE
238 getword_backtrace();
239 #endif
240 return(-1);
241 }
242 *number*=sign;
243
244 if (gwarea->current[x]) ++x;
245 gwarea->current+=x;
246 return(0);
247 }
248
249
250 int getword_ptr(char *orig_line,char **word, struct getwordstruct *gwarea, char stop)
251 {
252 /*!
253 \note Why pass the original buffer to the function ? Because we must modify it to
254 insert the terminating ASCII zero for the word we return and that's not compatible
255 with getword_restart(). Moreover, getword_start() sometime works on constant strings
256 so this function require the original buffer to detect any missuse.
257 */
258 int x;
259 int sep;
260 int start;
261
262 if (orig_line && orig_line!=gwarea->beginning) {
263 debuga(_("Invalid buffer passed to getword_ptr\n"));
264 return(-1);
265 }
266
267 start=(gwarea->current-gwarea->beginning);
268 if (word && orig_line) *word=orig_line+start;
269 for(x=0;((gwarea->current[x]) && (gwarea->current[x] != stop ));x++);
270 sep=(gwarea->current[x]!='\0');
271 if (word && orig_line) orig_line[start+x] = '\0';
272 if (sep) ++x;
273 gwarea->current+=x;
274 gwarea->modified=1;
275 return(0);
276 }
277
278 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
279 long long int my_atoll (const char *nptr)
280 {
281 long long int returnval=0LL;
282 int max_digits = MAXLLL ;
283
284 // Soak up all the white space
285 while (isspace( *nptr )) {
286 nptr++;
287 }
288
289 //For each character left to right
290 //change the character to a single digit
291 //multiply what we had before by 10 and add the new digit
292
293 while (--max_digits && isdigit( *nptr ))
294 {
295 returnval = ( returnval * 10 ) + ( *nptr++ - '0' ) ;
296 }
297
298 return returnval;
299 }
300
301 int is_absolute(const char *path)
302 {
303 if (*path=='/') return(1);
304 #ifdef WINDOWS
305 if (isalpha(path[0]) && path[1]==':') return(1);
306 #endif
307 return(0);
308 }
309
310 void my_mkdir(const char *name)
311 {
312 char w0[MAXLEN];
313 int i;
314 int chars;
315
316 if(!is_absolute(name)) {
317 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name);
318 debuga(_("process aborted.\n"));
319 exit(EXIT_FAILURE);
320 }
321
322 chars=0;
323 for (i=0 ; name[i] ; i++) {
324 if (i>=sizeof(w0)) {
325 debuga(_("directory name too long: %s\n"),name);
326 exit(EXIT_FAILURE);
327 }
328 if (chars>0 && name[i] == '/') {
329 w0[i] = '\0';
330 if (access(w0, R_OK) != 0) {
331 if (mkdir(w0,0755)) {
332 debuga(_("Cannot create directory %s - %s\n"),w0,strerror(errno));
333 debuga(_("process aborted.\n"));
334 exit(EXIT_FAILURE);
335 }
336 }
337 }
338 if (name[i] != '/') chars++;
339 w0[i] = name[i];
340 }
341
342 if (access(name, R_OK) != 0) {
343 if (mkdir(name,0755)) {
344 debuga(_("Cannot create directory %s - %s\n"),name,strerror(errno));
345 debuga(_("process aborted.\n"));
346 exit(EXIT_FAILURE);
347 }
348 }
349 }
350
351
352 void my_lltoa(unsigned long long int n, char *s, int ssize, int len)
353 {
354 int i;
355 int slen = 0;
356 int j;
357 char c;
358
359 ssize--;
360 if (len>ssize) {
361 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len,ssize);
362 abort();
363 }
364
365 do {
366 s[slen++] = (n % 10) + '0';
367 } while ((n /= 10) > 0 && slen<ssize);
368 s[slen] = '\0';
369
370 for (i = 0, j = slen-1; i<j; i++, j--) {
371 c = s[i];
372 s[i] = s[j];
373 s[j] = c;
374 }
375
376 if(len>slen) {
377 i=len-slen;
378 for(j=slen; j>=0; j--)
379 s[j+i]=s[j];
380 for(j=0 ; j<i ; j++)
381 s[j]='0';
382 }
383 }
384
385 int month2num(const char *month)
386 {
387 int m;
388
389 for(m=0 ; m<12 && strcmp(mtab1[m],month) != 0; m++);
390 return(m);
391 }
392
393 int builddia(int day, int month, int year)
394 {
395 return(year*10000+month*100+day);
396 }
397
398
399 void buildymd(const char *dia, const char *mes, const char *ano, char *wdata)
400 {
401 int nmes;
402
403 nmes=month2num(mes);
404 sprintf(wdata,"%04d%02d%02d",atoi(ano),nmes+1,atoi(dia));
405 }
406
407
408 int conv_month(const char *month)
409 {
410 int x;
411
412 for(x=0; x<12 && strncmp(mtab1[x],month,3)!=0; x++);
413 return(x+1);
414 }
415
416
417 const char *conv_month_name(int month)
418 {
419 static char str[4];
420
421 if (month<1 || month>12) {
422 snprintf(str,sizeof(str),"%03d",month);
423 return(str);
424 }
425 return(mtab1[month-1]);
426 }
427
428
429 void name_month(char *month,int month_len)
430 {
431 int x, z=atoi(month)-1;
432 char m[255];
433 char w[20];
434 struct getwordstruct gwarea;
435
436 strcpy(m,_("January,February,March,April,May,June,July,August,September,October,November,December"));
437 getword_start(&gwarea,m);
438
439 for(x=0; x<z; x++)
440 if (getword_multisep(w,sizeof(w),&gwarea,',')<0) {
441 printf("SARG: Maybe you have a broken record or garbage in the names of the months.\n");
442 exit(EXIT_FAILURE);
443 }
444 if (getword_multisep(month,month_len,&gwarea,',')<0) {
445 printf("SARG: Maybe you have a broken record or garbage in the name of the months.\n");
446 exit(EXIT_FAILURE);
447 }
448 }
449
450
451 /*!
452 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
453
454 \param msg The printf like message to format.
455 \param ... The arguments to format in the message.
456 */
457 void debuga(const char *msg,...)
458 {
459 va_list ap;
460
461 fputs(_("SARG: "),stderr);
462 va_start(ap,msg);
463 vfprintf(stderr,msg,ap);
464 va_end(ap);
465 }
466
467
468 /*!
469 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
470
471 \param msg The printf like message to format.
472 \param ... The arguments to format in the message.
473 */
474 void debugaz(const char *msg,...)
475 {
476 va_list ap;
477
478 fputs(_("SARG: (info) "),stderr);
479 va_start(ap,msg);
480 vfprintf(stderr,msg,ap);
481 va_end(ap);
482 }
483
484
485 char *fixnum(long long int value, int n)
486 {
487 #define MAXLEN_FIXNUM 256
488 char num[MAXLEN_FIXNUM]="";
489 char buf[MAXLEN_FIXNUM * 2];
490 char *pbuf;
491 static char ret[MAXLEN_FIXNUM * 2];
492 char *pret;
493 register int i, j, k;
494 int numlen;
495 static char abbrev[30];
496
497 my_lltoa(value, num, sizeof(num), 0);
498
499 if(DisplayedValues==DISPLAY_ABBREV) {
500 numlen = strlen(num);
501 if(numlen <= 3)
502 sprintf(abbrev,"%s",num);
503 if(numlen == 4 || numlen == 7 || numlen == 10 || numlen == 13) {
504 snprintf(abbrev,2,"%s",num);
505 strncat(abbrev,".",1);
506 strncat(abbrev,num+1,2);
507 if(!n) return(abbrev);
508 if(numlen == 4)
509 strncat(abbrev,"K",1);
510 else if(numlen == 7)
511 strncat(abbrev,"M",1);
512 else if(numlen == 10)
513 strncat(abbrev,"G",1);
514 else if(numlen == 13)
515 strncat(abbrev,"T",1);
516 }
517 if(numlen == 5 || numlen == 8 || numlen == 11 || numlen == 14) {
518 snprintf(abbrev,3,"%s",num);
519 strncat(abbrev,".",1);
520 strncat(abbrev,num+2,2);
521 if(!n) return(abbrev);
522 if(numlen == 5)
523 strncat(abbrev,"K",1);
524 else if(numlen == 8)
525 strncat(abbrev,"M",1);
526 else if(numlen == 11)
527 strncat(abbrev,"G",1);
528 else if(numlen == 14)
529 strncat(abbrev,"T",1);
530 }
531 if(numlen == 6 || numlen == 9 || numlen == 12 || numlen == 15) {
532 snprintf(abbrev,4,"%s",num);
533 strncat(abbrev,".",1);
534 strncat(abbrev,num+3,2);
535 if(!n) return(abbrev);
536 if(numlen == 6)
537 strncat(abbrev,"K",1);
538 else if(numlen == 9)
539 strncat(abbrev,"M",1);
540 else if(numlen == 12)
541 strncat(abbrev,"G",1);
542 else if(numlen == 15)
543 strncat(abbrev,"T",1);
544 }
545
546 return(abbrev);
547 }
548
549 bzero(buf, MAXLEN_FIXNUM*2);
550
551 pbuf = buf;
552 pret = ret;
553 k = 0;
554
555 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
556 if ( k == 2 && i != 0 ) {
557 k = 0;
558 pbuf[j++] = num[i];
559 pbuf[j++] = (UseComma) ? ',' : '.';
560 continue;
561 }
562 pbuf[j] = num[i];
563 j++;
564 k++;
565 }
566
567 pret[0]='\0';
568
569 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
570 pret[j] = pbuf[i];
571
572 pret[j] = '\0';
573
574 return pret;
575 }
576
577
578 char *fixnum2(long long int value, int n)
579 {
580 #define MAXLEN_FIXNUM2 1024
581 char num[MAXLEN_FIXNUM2];
582 char buf[MAXLEN_FIXNUM2 * 2];
583 char *pbuf;
584 static char ret[MAXLEN_FIXNUM2 * 2];
585 char *pret;
586 register int i, j, k;
587
588 my_lltoa(value, num, sizeof(num), 0);
589 bzero(buf, MAXLEN_FIXNUM2*2);
590
591 pbuf = buf;
592 pret = ret;
593 k = 0;
594
595 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
596 if ( k == 2 && i != 0 ) {
597 k = 0;
598 pbuf[j++] = num[i];
599 pbuf[j++] = (UseComma) ? ',' : '.';
600 continue;
601 }
602 pbuf[j] = num[i];
603 j++;
604 k++;
605 }
606
607 pret[0]='\0';
608
609 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
610 pret[j] = pbuf[i];
611
612 pret[j] = '\0';
613
614 return pret;
615 }
616
617
618 char *buildtime(long long int elap)
619 {
620 int num = elap / 1000;
621 int hor = 0;
622 int min = 0;
623 int sec = 0;
624 static char buf[12];
625
626 buf[0]='\0';
627
628 hor=num / 3600;
629 min=(num % 3600) / 60;
630 sec=num % 60;
631 sprintf(buf,"%02d:%02d:%02d",hor,min,sec);
632
633 return(buf);
634 }
635
636
637 /*!
638 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
639
640 \param dirname The directory to look for the connection directory.
641 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
642 \param data The buffer to store the content of the file. It must be more than 80
643 bytes long.
644
645 \retval 0 No error.
646 \retval -1 File not found.
647 */
648 int obtdate(const char *dirname, const char *name, char *data)
649 {
650 FILE *fp_in;
651 char wdir[MAXLEN];
652
653 sprintf(wdir,"%s%s/sarg-date",dirname,name);
654 if ((fp_in = fopen(wdir, "rt")) == 0) {
655 sprintf(wdir,"%s%s/date",dirname,name);
656 if ((fp_in = fopen(wdir, "rt")) == 0) {
657 data[0]='\0';
658 return(-1);
659 }
660 }
661
662 if (!fgets(data,80,fp_in)) {
663 debuga(_("Failed to read the date in %s\n"),wdir);
664 exit(EXIT_FAILURE);
665 }
666 fclose(fp_in);
667 fixendofline(data);
668
669 return(0);
670 }
671
672
673 void formatdate(char *date,int date_size,int year,int month,int day,int hour,int minute,int second,int dst)
674 {
675 struct tm ltm;
676 time_t unixtime;
677 struct tm *fulltm;
678
679 memset(&ltm,0,sizeof(ltm));
680 if (year>=1900) ltm.tm_year=year-1900;
681 if (month>=1 && month<=12) ltm.tm_mon=month-1;
682 if (day>=1 && day<=31) ltm.tm_mday=day;
683 if (hour>=0 && hour<24) ltm.tm_hour=hour;
684 if (minute>=0 && minute<60) ltm.tm_min=minute;
685 if (second>=0 && second<60) ltm.tm_sec=second;
686 ltm.tm_isdst=dst;
687 unixtime=mktime(&ltm); //fill the missing entries
688 fulltm=localtime(&unixtime);
689 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
690 strftime(date,date_size,"%c",fulltm);
691 }
692
693
694 void computedate(int year,int month,int day,struct tm *t)
695 {
696 memset(t,0,sizeof(*t));
697 t->tm_year=year-1900;
698 t->tm_mon=month-1;
699 t->tm_mday=day;
700 }
701
702
703 int obtuser(const char *dirname, const char *name)
704 {
705 FILE *fp_in;
706 char wdir[MAXLEN];
707 char tuser[20];
708 int nuser;
709
710 sprintf(wdir,"%s%s/sarg-users",dirname,name);
711 if((fp_in=fopen(wdir,"r"))==NULL) {
712 sprintf(wdir,"%s%s/users",dirname,name);
713 if((fp_in=fopen(wdir,"r"))==NULL) {
714 return(0);
715 }
716 }
717
718 if (!fgets(tuser,sizeof(tuser),fp_in)) {
719 debuga(_("Failed to read the number of users in %s\n"),wdir);
720 exit(EXIT_FAILURE);
721 }
722 fclose(fp_in);
723 nuser=atoi(tuser);
724
725 return(nuser);
726 }
727
728
729 void obttotal(const char *dirname, const char *name, int nuser, long long int *tbytes, long long int *media)
730 {
731 FILE *fp_in;
732 char *buf;
733 char wdir[MAXLEN];
734 char user[MAX_USER_LEN];
735 char sep;
736 struct getwordstruct gwarea;
737 longline line;
738
739 *tbytes=0;
740 *media=0;
741
742 sprintf(wdir,"%s%s/sarg-general",dirname,name);
743 if ((fp_in = fopen(wdir, "r")) == 0) {
744 sprintf(wdir,"%s%s/general",dirname,name);
745 if ((fp_in = fopen(wdir, "r")) == 0) {
746 return;
747 }
748 }
749
750 if ((line=longline_create())==NULL) {
751 debuga(_("Not enough memory to read the file %s\n"),wdir);
752 exit(EXIT_FAILURE);
753 }
754
755 while((buf=longline_read(fp_in,line))!=NULL) {
756 if (strncmp(buf,"TOTAL\t",6) == 0)
757 sep='\t'; //new file
758 else if (strncmp(buf,"TOTAL ",6) == 0)
759 sep=' '; //old file
760 else
761 continue;
762 getword_start(&gwarea,buf);
763 if (getword(user,sizeof(user),&gwarea,sep)<0) {
764 debuga(_("There is a invalid user in file %s\n"),wdir);
765 exit(EXIT_FAILURE);
766 }
767 if(strcmp(user,"TOTAL") != 0)
768 continue;
769 if (getword_skip(MAXLEN,&gwarea,sep)<0) {
770 debuga(_("There a broken total number of access in file %s\n"),wdir);
771 exit(EXIT_FAILURE);
772 }
773 if (getword_atoll(tbytes,&gwarea,sep)<0) {
774 debuga(_("There is a broken number of bytes in file %s\n"),wdir);
775 exit(EXIT_FAILURE);
776 }
777 break;
778 }
779 fclose(fp_in);
780 longline_destroy(&line);
781
782 if (nuser <= 0)
783 return;
784
785 *media=*tbytes / nuser;
786 return;
787 }
788
789 int getperiod_fromsarglog(const char *arqtt,struct periodstruct *period)
790 {
791 const char *str;
792 int day0, month0, year0, hour0, minute0;
793 int day1, month1, year1, hour1, minute1;
794 int i;
795
796 memset(period,0,sizeof(*period));
797
798 str=arqtt;
799 while((str=strstr(str,"sarg-"))!=NULL) {
800 str+=5;
801 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
802 day0=(str[0]-'0')*10+(str[1]-'0');
803 if (day0<1 || day0>31) continue;
804 str+=2;
805 month0=(str[0]-'0')*10+(str[1]-'0')-1;
806 if (month0<0 || month0>11) continue;
807 str+=2;
808 year0=0;
809 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year0=year0*10+(str[i]-'0');
810 if (i!=4) continue;
811 str+=4;
812 if (str[0]!='_') continue;
813 str++;
814
815 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
816 hour0=(str[0]-'0')*10+(str[1]-'0');
817 str+=2;
818 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
819 minute0=(str[0]-'0')*10+(str[1]-'0');
820 str+=2;
821
822 if (*str != '-') continue;
823 str++;
824
825 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
826 day1=(str[0]-'0')*10+(str[1]-'0');
827 if (day1<1 || day1>31) continue;
828 str+=2;
829 month1=(str[0]-'0')*10+(str[1]-'0')-1;
830 if (month1<0 || month1>11) continue;
831 str+=2;
832 year1=0;
833 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year1=year1*10+(str[i]-'0');
834 if (i!=4) continue;
835 str+=4;
836
837 if (str[0]!='_') continue;
838 str++;
839
840 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
841 hour1=(str[0]-'0')*10+(str[1]-'0');
842 str+=2;
843 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
844 minute1=(str[0]-'0')*10+(str[1]-'0');
845 str+=2;
846
847 period->start.tm_mday=day0;
848 period->start.tm_mon=month0;
849 period->start.tm_year=year0-1900;
850 period->start.tm_hour=hour0;
851 period->start.tm_min=minute0;
852 period->end.tm_mday=day1;
853 period->end.tm_mon=month1;
854 period->end.tm_year=year1-1900;
855 period->end.tm_hour=hour1;
856 period->end.tm_min=minute1;
857 return(0);
858 }
859 return(-1);
860 }
861
862 void getperiod_fromrange(struct periodstruct *period,int dfrom,int duntil)
863 {
864 memset(&period->start,0,sizeof(period->start));
865 period->start.tm_mday=dfrom%100;
866 period->start.tm_mon=(dfrom/100)%100-1;
867 period->start.tm_year=(dfrom/10000)-1900;
868
869 memset(&period->end,0,sizeof(period->end));
870 period->end.tm_mday=duntil%100;
871 period->end.tm_mon=(duntil/100)%100-1;
872 period->end.tm_year=(duntil/10000)-1900;
873 }
874
875 int getperiod_buildtext(struct periodstruct *period)
876 {
877 int i;
878 int range;
879 char text1[40], text2[40];
880
881 if(df[0]=='u') {
882 i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
883 }else if(df[0]=='e') {
884 i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
885 } else /*if(df[0]=='w')*/ {
886 IndexTree=INDEX_TREE_FILE;
887 i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
888 }
889 if (i == 0) return(-1);
890
891 range=(period->start.tm_year!=period->end.tm_year ||
892 period->start.tm_mon!=period->end.tm_mon ||
893 period->start.tm_mday!=period->end.tm_mday);
894 if (range) {
895 if(df[0]=='u') {
896 i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
897 } else if(df[0]=='e') {
898 i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
899 } else {
900 i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
901 }
902 if (i == 0) return(-1);
903 }
904
905 if (range) {
906 snprintf(period->text,sizeof(period->text),"%s-%s",text1,text2);
907 snprintf(period->html,sizeof(period->html),"%s&mdash;%s",text1,text2);
908 } else {
909 strncpy(period->text,text1,sizeof(period->text)-1);
910 period->text[sizeof(period->text)-1]='\0';
911 strncpy(period->html,text1,sizeof(period->html)-1);
912 period->html[sizeof(period->html)-1]='\0';
913 }
914 return(0);
915 }
916
917 static void copy_images(void)
918 {
919 FILE *img_in, *img_ou;
920 char images[512];
921 char imgdir[MAXLEN];
922 char srcfile[MAXLEN];
923 char dstfile[MAXLEN];
924 DIR *dirp;
925 struct dirent *direntp;
926 char buffer[MAXLEN];
927 size_t nread;
928 struct stat info;
929
930 if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
931 debuga(_("Cannot copy images to target directory %simages\n"),outdir);
932 exit(EXIT_FAILURE);
933 }
934 if (access(images,R_OK)!=0) {
935 if (mkdir(images,0755)) {
936 debuga(_("Cannot create directory %s - %s\n"),images,strerror(errno));
937 exit(EXIT_FAILURE);
938 }
939 }
940
941 strcpy(imgdir,IMAGEDIR);
942 dirp = opendir(imgdir);
943 if(dirp==NULL) {
944 debuga(_("(util) Can't open directory %s: %s\n"),imgdir,strerror(errno));
945 return;
946 }
947 while ((direntp = readdir( dirp )) != NULL ){
948 if(direntp->d_name[0]=='.')
949 continue;
950 sprintf(srcfile,"%s/%s",imgdir,direntp->d_name);
951 if (stat(srcfile,&info)) {
952 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile,strerror(errno));
953 continue;
954 }
955 if (S_ISREG(info.st_mode)) {
956 sprintf(dstfile,"%s/%s",images,direntp->d_name);
957 img_in = fopen(srcfile, "rb");
958 if(img_in!=NULL) {
959 img_ou = fopen(dstfile, "wb");
960 if(img_ou!=NULL) {
961 while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
962 if (fwrite(buffer,1,nread,img_ou)!=nread) {
963 debuga(_("Failed to copy image %s to %s\n"),srcfile,dstfile);
964 break;
965 }
966 }
967 fclose(img_ou);
968 } else
969 fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile, strerror(errno));
970 fclose(img_in);
971 } else
972 fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile, strerror(errno));
973 }
974 }
975 (void) closedir(dirp);
976
977 return;
978 }
979
980 int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form)
981 {
982 FILE *fp_ou;
983 int num=1, count=0;
984 char wdir[MAXLEN];
985 char dirname2[MAXLEN];
986 int y1, y2;
987 int m1, m2;
988 int d1, d2;
989 int wlen, wlen2;
990 time_t curtime;
991 struct tm *loctm;
992
993 strcpy(wdir,outdir);
994 wlen=strlen(wdir);
995 y1=per1->start.tm_year+1900;
996 y2=per1->end.tm_year+1900;
997 m1=per1->start.tm_mon+1;
998 m2=per1->end.tm_mon+1;
999 d1=per1->start.tm_mday;
1000 d2=per1->end.tm_mday;
1001 if(IndexTree == INDEX_TREE_DATE) {
1002 wlen+=sprintf(wdir+wlen,"%04d",y1);
1003 if(y1!=y2) wlen+=sprintf(wdir+wlen,"-%04d",y2);
1004 if(access(wdir, R_OK) != 0)
1005 my_mkdir(wdir);
1006
1007 wlen+=sprintf(wdir+wlen,"/%02d",m1);
1008 if(m1 != m2) wlen+=sprintf(wdir+wlen,"-%02d",m2);
1009 if(access(wdir, R_OK) != 0)
1010 my_mkdir(wdir);
1011
1012 wlen+=sprintf(wdir+wlen,"/%02d",d1);
1013 if(d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
1014 } else {
1015 if(df[0] == 'u') {
1016 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
1017 conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
1018 } else if(df[0] == 'e') {
1019 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
1020 conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
1021 } else if(df[0] == 'w') {
1022 wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
1023 if (wlen2==0) return(-1);
1024 wlen+=wlen2;
1025 }
1026 }
1027
1028 if(us[0] != '\0') {
1029 struct userinfostruct *uinfo=userinfo_find_from_id(us);
1030 if (uinfo) {
1031 strcat(wdir,"-");
1032 strcat(wdir,uinfo->filename);
1033 }
1034 }
1035 if(addr[0] != '\0') {
1036 strcat(wdir,"-");
1037 strcat(wdir,addr);
1038 }
1039 if(site[0] != '\0') {
1040 strcat(wdir,"-");
1041 strcat(wdir,site);
1042 }
1043
1044 strcpy(outdirname,wdir);
1045
1046 if(IndexTree != INDEX_TREE_DATE) {
1047 if(!OverwriteReport) {
1048 while(num) {
1049 if(access(wdir,R_OK) == 0) {
1050 sprintf(wdir,"%s.%d",outdirname,num);
1051 num++;
1052 count++;
1053 } else
1054 break;
1055 }
1056
1057 if(count > 0) {
1058 if(debug)
1059 debuga(_("File %s already exists, moved to %s\n"),outdirname,wdir);
1060 rename(outdirname,wdir);
1061 }
1062 } else {
1063 if(access(outdirname,R_OK) == 0) {
1064 unlinkdir(outdirname,1);
1065 }
1066 }
1067 my_mkdir(outdirname);
1068 } else {
1069 strcpy(dirname2,wdir);
1070 if(!OverwriteReport) {
1071 while(num) {
1072 if(access(wdir,R_OK) == 0) {
1073 sprintf(wdir,"%s.%d",dirname2,num);
1074 num++;
1075 count++;
1076 } else
1077 break;
1078 }
1079
1080 if(count > 0) {
1081 if(debug)
1082 debuga(_("File %s already exists, moved to %s\n"),dirname2,wdir);
1083 rename(dirname2,wdir);
1084 strcpy(dirname2,wdir);
1085 }
1086 } else {
1087 if(access(wdir,R_OK) == 0) {
1088 unlinkdir(wdir,1);
1089 }
1090 }
1091
1092 if(access(wdir, R_OK) != 0)
1093 my_mkdir(wdir);
1094 }
1095
1096 strcpy(dirname2,wdir);
1097
1098 sprintf(wdir,"%s/sarg-date",outdirname);
1099 if ((fp_ou = fopen(wdir, "wt")) == 0) {
1100 debuga(_("cannot open %s for writing\n"),wdir);
1101 perror("SARG:");
1102 exit(EXIT_FAILURE);
1103 }
1104 time(&curtime);
1105 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1106 loctm=localtime(&curtime);
1107 strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
1108 if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
1109 debuga(_("Failed to write the date in %s\n"),wdir);
1110 perror("SARG:");
1111 exit(EXIT_FAILURE);
1112 }
1113 if (fclose(fp_ou)==EOF) {
1114 debuga(_("Failed to write the date in %s\n"),wdir);
1115 perror("SARG:");
1116 exit(EXIT_FAILURE);
1117 }
1118
1119 copy_images();
1120 return(0);
1121 }
1122
1123 void strip_latin(char *line)
1124 {
1125 int i,j;
1126 int skip;
1127
1128 j=0;
1129 skip=0;
1130 for (i=0;line[i];i++){
1131 if (skip){
1132 if (line[i]==';') skip=0;
1133 } else {
1134 if (line[i]=='&')
1135 skip=1;
1136 else
1137 line[j++]=line[i];
1138 }
1139 }
1140 line[j]='\0';
1141 return;
1142 }
1143
1144 void zdate(char *ftime,int ftimesize, const char *DateFormat)
1145 {
1146 time_t t;
1147 struct tm *local;
1148
1149 t = time(NULL);
1150 local = localtime(&t);
1151 if(strcmp(DateFormat,"u") == 0)
1152 strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
1153 if(strcmp(DateFormat,"e") == 0)
1154 strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
1155 if(strcmp(DateFormat,"w") == 0)
1156 strftime(ftime, ftimesize, "%W-%H-%M", local);
1157 return;
1158 }
1159
1160
1161 char *fixtime(long long int elap)
1162 {
1163 int num = elap / 1000;
1164 int hor = 0;
1165 int min = 0;
1166 int sec = 0;
1167 static char buf[12];
1168
1169 hor=num / 3600;
1170 min=(num % 3600) / 60;
1171 sec=num % 60;
1172
1173 if(hor==0 && min==0 && sec==0)
1174 strcpy(buf,"0");
1175 else
1176 sprintf(buf,"%d:%02d:%02d",hor,min,sec);
1177
1178 return buf;
1179 }
1180
1181
1182 void date_from(char *date, int *dfrom, int *duntil)
1183 {
1184 int d0=0;
1185 int m0=0;
1186 int y0=0;
1187 int d1=0;
1188 int m1=0;
1189 int y1=0;
1190
1191 if (isdigit(date[0])) {
1192 int next=-1;
1193
1194 if (sscanf(date,"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
1195 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1196 exit(EXIT_FAILURE);
1197 }
1198 if (date[next]=='-') {
1199 if (sscanf(date+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
1200 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1201 exit(EXIT_FAILURE);
1202 }
1203 } else if (date[next]!='\0') {
1204 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1205 exit(EXIT_FAILURE);
1206 } else {
1207 d1=d0;
1208 m1=m0;
1209 y1=y0;
1210 }
1211 } else {
1212 int i;
1213 time_t Today,t1;
1214 struct tm *Date0,Date1;
1215
1216 if (time(&Today)==(time_t)-1) {
1217 debuga(_("Failed to get the current time\n"));
1218 exit(EXIT_FAILURE);
1219 }
1220 if (sscanf(date,"day-%d",&i)==1) {
1221 if (i<0) {
1222 debuga(_("Invalid number of days in -d parameter\n"));
1223 exit(EXIT_FAILURE);
1224 }
1225 Today-=i*24*60*60;
1226 Date0=localtime(&Today);
1227 if (Date0==NULL) {
1228 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1229 exit(EXIT_FAILURE);
1230 }
1231 y0=y1=Date0->tm_year+1900;
1232 m0=m1=Date0->tm_mon+1;
1233 d0=d1=Date0->tm_mday;
1234 } else if (sscanf(date,"week-%d",&i)==1) {
1235 /*
1236 There is no portable way to find the first day of the week even though the
1237 information is available in the locale. nl_langinfo has the unofficial
1238 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1239 undocumented as is their return value and it is discouraged to use them.
1240 Beside, nl_langinfo isn't available on windows and the first day of the
1241 week isn't available at all on that system.
1242 */
1243 const int FirstWeekDay=1;
1244 time_t WeekBegin;
1245
1246 if (i<0) {
1247 debuga(_("Invalid number of weeks in -d parameter\n"));
1248 exit(EXIT_FAILURE);
1249 }
1250 Date0=localtime(&Today);
1251 if (Date0==NULL) {
1252 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1253 exit(EXIT_FAILURE);
1254 }
1255 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1256 WeekBegin-=i*7*24*60*60;
1257 Date0=localtime(&WeekBegin);
1258 if (Date0==NULL) {
1259 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1260 exit(EXIT_FAILURE);
1261 }
1262 y0=Date0->tm_year+1900;
1263 m0=Date0->tm_mon+1;
1264 d0=Date0->tm_mday;
1265 WeekBegin+=6*24*60*60;
1266 Date0=localtime(&WeekBegin);
1267 if (Date0==NULL) {
1268 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1269 exit(EXIT_FAILURE);
1270 }
1271 y1=Date0->tm_year+1900;
1272 m1=Date0->tm_mon+1;
1273 d1=Date0->tm_mday;
1274 } else if (sscanf(date,"month-%d",&i)==1) {
1275 if (i<0) {
1276 debuga(_("Invalid number of months in -d parameter\n"));
1277 exit(EXIT_FAILURE);
1278 }
1279 Date0=localtime(&Today);
1280 if (Date0==NULL) {
1281 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1282 exit(EXIT_FAILURE);
1283 }
1284 if (Date0->tm_mon<i%12) {
1285 y0=Date0->tm_year+1900-i/12-1;
1286 m0=(Date0->tm_mon+12-i%12)%12+1;
1287 d0=1;
1288 } else {
1289 y0=Date0->tm_year+1900-i/12;
1290 m0=Date0->tm_mon-i%12+1;
1291 d0=1;
1292 }
1293 memcpy(&Date1,Date0,sizeof(struct tm));
1294 Date1.tm_isdst=-1;
1295 Date1.tm_mday=1;
1296 if (m0<12) {
1297 Date1.tm_mon=m0;
1298 Date1.tm_year=y0-1900;
1299 } else {
1300 Date1.tm_mon=0;
1301 Date1.tm_year=y0-1900+1;
1302 }
1303 t1=mktime(&Date1);
1304 t1-=24*60*60;
1305 Date0=localtime(&t1);
1306 y1=Date0->tm_year+1900;
1307 m1=Date0->tm_mon+1;
1308 d1=Date0->tm_mday;
1309 } else {
1310 debuga(_("Invalid date range passed on command line\n"));
1311 exit(EXIT_FAILURE);
1312 }
1313 }
1314
1315 *dfrom=y0*10000+m0*100+d0;
1316 *duntil=y1*10000+m1*100+d1;
1317 sprintf(date,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
1318 return;
1319 }
1320
1321
1322 char *strlow(char *string)
1323 {
1324 char *s;
1325
1326 if (string)
1327 {
1328 for (s = string; *s; ++s)
1329 *s = tolower(*s);
1330 }
1331
1332 return string;
1333 }
1334
1335
1336
1337
1338 char *strup(char *string)
1339 {
1340 char *s;
1341
1342 if (string)
1343 {
1344 for (s = string; *s; ++s)
1345 *s = toupper(*s);
1346 }
1347
1348 return string;
1349 }
1350
1351
1352 void removetmp(const char *outdir)
1353 {
1354 FILE *fp_gen;
1355 char filename[256];
1356
1357 if(!RemoveTempFiles)
1358 return;
1359
1360 if(debug) {
1361 debuga(_("Purging temporary file sarg-general\n"));
1362 }
1363 if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
1364 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir);
1365 exit(EXIT_FAILURE);
1366 }
1367 if((fp_gen=fopen(filename,"w"))==NULL){
1368 debuga(_("(removetmp) Cannot open file %s\n"),filename);
1369 exit(EXIT_FAILURE);
1370 }
1371 totalger(fp_gen,filename);
1372 if (fclose(fp_gen)==EOF) {
1373 debuga(_("Failed to close %s after writing the total line - %s\n"),filename,strerror(errno));
1374 exit(EXIT_FAILURE);
1375 }
1376 }
1377
1378 void load_excludecodes(const char *ExcludeCodes)
1379 {
1380 FILE *fp_in;
1381 char data[80];
1382 int i;
1383 int Stored;
1384 long int MemSize;
1385
1386 if(ExcludeCodes[0] == '\0')
1387 return;
1388
1389 if((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
1390 debuga(_("(util) Cannot open file %s (exclude_codes)\n"),ExcludeCodes);
1391 exit(EXIT_FAILURE);
1392 }
1393
1394 if (fseek(fp_in, 0, SEEK_END)==-1) {
1395 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1396 exit(EXIT_FAILURE);
1397 }
1398 MemSize = ftell(fp_in);
1399 if (MemSize<0) {
1400 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes);
1401 exit(EXIT_FAILURE);
1402 }
1403 if (fseek(fp_in, 0, SEEK_SET)==-1) {
1404 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1405 exit(EXIT_FAILURE);
1406 }
1407
1408 MemSize+=1;
1409 if((excludecode=(char *) malloc(MemSize))==NULL) {
1410 debuga(_("malloc error (%ld)\n"),MemSize);
1411 exit(EXIT_FAILURE);
1412 }
1413 memset(excludecode,0,MemSize);
1414
1415 Stored=0;
1416 while(fgets(data,sizeof(data),fp_in)!=NULL) {
1417 if (data[0]=='#') continue;
1418 for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
1419 if (i<0) continue;
1420 if (Stored+i+2>=MemSize) {
1421 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes);
1422 break;
1423 }
1424 strcat(excludecode,data);
1425 strcat(excludecode,";");
1426 Stored+=i+1;
1427 }
1428
1429 fclose(fp_in);
1430 return;
1431 }
1432
1433 void free_excludecodes(void)
1434 {
1435 if (excludecode) {
1436 free(excludecode);
1437 excludecode=NULL;
1438 }
1439 }
1440
1441 int vercode(const char *code)
1442 {
1443 char *cod;
1444 int clen;
1445
1446 if (excludecode && excludecode[0]!='\0') {
1447 clen=strlen(code);
1448 cod=excludecode;
1449 while (cod) {
1450 if (strncmp(code,cod,clen)==0 && cod[clen]==';')
1451 return 1;
1452 cod=strchr(cod,';');
1453 if (cod) cod++;
1454 }
1455 }
1456 return 0;
1457 }
1458
1459 void fixnone(char *str)
1460 {
1461 int i;
1462
1463 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--);
1464 if(i==3 && strncmp(str,"none",4) == 0)
1465 str[0]='\0';
1466
1467 return;
1468 }
1469
1470 void fixendofline(char *str)
1471 {
1472 int i;
1473
1474 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--) str[i]=0;
1475 }
1476
1477 #ifdef LEGACY_TESTVALIDUSERCHAR
1478 int testvaliduserchar(const char *user)
1479 {
1480 int x=0;
1481 int y=0;
1482
1483 for (y=0; y<strlen(UserInvalidChar); y++) {
1484 for (x=0; x<strlen(user); x++) {
1485 if(user[x] == UserInvalidChar[y])
1486 return 1;
1487 }
1488 }
1489 return 0;
1490 }
1491 #else
1492 int testvaliduserchar(const char *user)
1493 {
1494 char * p_UserInvalidChar = UserInvalidChar ;
1495 const char * p_user ;
1496
1497 while( *p_UserInvalidChar ) {
1498 p_user = user ;
1499 while ( *p_user ) {
1500 if( *p_UserInvalidChar == *p_user )
1501 return 1;
1502 p_user++ ;
1503 }
1504 p_UserInvalidChar++ ;
1505 }
1506 return 0;
1507 }
1508 #endif
1509
1510 int compar( const void *a, const void *b )
1511 {
1512 if( *(int *)a > *(int *)b ) return 1;
1513 if( *(int *)a < *(int *)b ) return -1;
1514 return 0;
1515 }
1516
1517 int getnumlist( char *buf, numlist *list, const int len, const int maxvalue )
1518 {
1519 int i, j, d, flag, r1, r2;
1520 char *pbuf, **bp, *strbufs[ 24 ];
1521
1522 bp = strbufs;
1523 strtok( buf, " \t" );
1524 for( *bp = strtok( NULL, "," ), list->len = 0; *bp; *bp = strtok( NULL, "," ) ) {
1525 if( ++bp >= &strbufs[ 24 ] )
1526 break;
1527 list->len++;
1528 }
1529 if( ! list->len )
1530 return -1;
1531 d = 0;
1532 for( i = 0; i < list->len; i++ ) {
1533 if( strchr( strbufs[ i ], '-' ) != 0 ) {
1534 pbuf = strbufs[ i ];
1535 strtok( pbuf, "-" );
1536 pbuf = strtok( NULL, "\0" );
1537 r1 = atoi( strbufs[ i ] );
1538 if( ( r2 = atoi( pbuf ) ) >= maxvalue || r1 >= r2 )
1539 return -1;
1540 if( i + d + ( r2 - r1 ) + 1 <= len ) {
1541 for( j = r1; j <= r2; j++ )
1542 list->list[ i + d++ ] = j;
1543 d--;
1544 }
1545 }
1546 else
1547 if( ( list->list[ i + d ] = atoi( strbufs[ i ] ) ) >= maxvalue )
1548 return 1;
1549 }
1550 list->len += d;
1551 qsort( list->list, list->len, sizeof( int ), compar );
1552 do {
1553 flag = 0;
1554 for( i = 0; i < list->len - 1; i++ )
1555 if( list->list[ i ] == list->list[ i + 1 ] ) {
1556 for( j = i + 1; j < list->len; j++ )
1557 list->list[ j - 1 ] = list->list[ j ];
1558 list->len--;
1559 flag = 1;
1560 break;
1561 }
1562 } while( flag );
1563 return 0;
1564 }
1565
1566
1567 char *get_size(const char *path, const char *file)
1568 {
1569 FILE *fp;
1570 static char response[255];
1571 char cmd[255];
1572 char *ptr;
1573
1574 if (snprintf(cmd,sizeof(cmd),"du -skh %s%s",path,file)>=sizeof(cmd)) {
1575 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path,file);
1576 exit(EXIT_FAILURE);
1577 }
1578 if ((fp = popen(cmd, "r")) == NULL) {
1579 debuga(_("Cannot get disk space with command %s\n"),cmd);
1580 exit(EXIT_FAILURE);
1581 }
1582 if (!fgets(response, sizeof(response), fp)) {
1583 debuga(_("Cannot get disk size with command %s\n"),cmd);
1584 exit(EXIT_FAILURE);
1585 }
1586 ptr=strchr(response,'\t');
1587 if (ptr==NULL) {
1588 debuga(_("The command %s failed\n"),cmd);
1589 exit(EXIT_FAILURE);
1590 }
1591 pclose(fp);
1592 *ptr='\0';
1593
1594 return (response);
1595 }
1596
1597 void show_info(FILE *fp_ou)
1598 {
1599 char ftime[127];
1600
1601 if(!ShowSargInfo) return;
1602 zdate(ftime, sizeof(ftime), DateFormat);
1603 fprintf(fp_ou,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL,PGM,VERSION,_("on"),ftime);
1604 }
1605
1606 void show_sarg(FILE *fp_ou, int depth)
1607 {
1608 int i;
1609
1610 if(!ShowSargLogo) return;
1611 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
1612 for (i=0 ; i<depth ; i++)
1613 fputs("../",fp_ou);
1614 fputs("images/sarg.png\" title=\"SARG, Squid Analysis Report Generator. Logo by Osamu Matsuzaki\" alt=\"Sarg\"></a>&nbsp;Squid Analysis Report Generator</div>\n",fp_ou);
1615 }
1616
1617 void write_logo_image(FILE *fp_ou)
1618 {
1619 if(LogoImage[0]!='\0')
1620 fprintf(fp_ou, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\">&nbsp;%s</div>\n",LogoImage,Width,Height,LogoText);
1621 }
1622
1623 void write_html_head(FILE *fp_ou, int depth, const char *page_title,int javascript)
1624 {
1625 int i;
1626
1627 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
1628 fprintf(fp_ou, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
1629 if (page_title) fprintf(fp_ou,"<title>%s</title>\n",page_title);
1630 css(fp_ou);
1631 if ((javascript & HTML_JS_SORTTABLE)!=0 && SortTableJs[0]) {
1632 fputs("<script type=\"text/javascript\" src=\"",fp_ou);
1633 if (strncmp(SortTableJs,"../",3)==0) {
1634 for (i=0 ; i<depth ; i++) fputs("../",fp_ou);
1635 }
1636 fputs(SortTableJs,fp_ou);
1637 fputs("\"></script>\n",fp_ou);
1638 }
1639 fputs("</head>\n<body>\n",fp_ou);
1640 }
1641
1642 void write_html_header(FILE *fp_ou, int depth, const char *page_title,int javascript)
1643 {
1644 write_html_head(fp_ou,depth,page_title,javascript);
1645 write_logo_image(fp_ou);
1646 show_sarg(fp_ou, depth);
1647 fprintf(fp_ou,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title);
1648 }
1649
1650 void close_html_header(FILE *fp_ou)
1651 {
1652 fputs("</table></div>\n",fp_ou);
1653 }
1654
1655 int write_html_trailer(FILE *fp_ou)
1656 {
1657 show_info(fp_ou);
1658 if (fputs("</body>\n</html>\n",fp_ou)==EOF) return(-1);
1659 return(0);
1660 }
1661
1662 void output_html_string(FILE *fp_ou,const char *str,int maxlen)
1663 {
1664 int i=0;
1665
1666 while (*str && (maxlen<=0 || i<maxlen)) {
1667 switch (*str) {
1668 case '&':
1669 fputs("&amp;",fp_ou);
1670 break;
1671 case '<':
1672 fputs("&lt;",fp_ou);
1673 break;
1674 case '>':
1675 fputs("&gt;",fp_ou);
1676 break;
1677 case '"':
1678 fputs("&quot;",fp_ou);
1679 break;
1680 case '\'':
1681 fputs("&#39;",fp_ou);
1682 break;
1683 default:
1684 fputc(*str,fp_ou);
1685 }
1686 str++;
1687 i++;
1688 }
1689 if (maxlen>0 && i>=maxlen)
1690 fputs("&hellip;",fp_ou);
1691 }
1692
1693 void output_html_url(FILE *fp_ou,const char *url)
1694 {
1695 while (*url) {
1696 if (*url=='&')
1697 fputs("&amp;",fp_ou);
1698 else
1699 fputc(*url,fp_ou);
1700 url++;
1701 }
1702 }
1703
1704 /*!
1705 Write a host name inside an A tag of a HTML file. If the host name starts
1706 with a star, it is assumed to be an alias that cannot be put inside a link
1707 so the A tag is not written around the host name.
1708
1709 \param fp_ou The handle of the HTML file.
1710 \param url The host to display in the HTML file.
1711 \param maxlen The maximum number of characters to print into the host name.
1712 */
1713 void output_html_link(FILE *fp_ou,const char *url,int maxlen)
1714 {
1715 if (url[0]==ALIAS_PREFIX) {
1716 // this is an alias, no need for a A tag
1717 output_html_string(fp_ou,url+1,100);
1718 } else {
1719 fputs("<a href=\"http://",fp_ou);
1720 output_html_url(fp_ou,url);
1721 fputs("\">",fp_ou);
1722 output_html_string(fp_ou,url,100);
1723 fputs("</a>",fp_ou);
1724 }
1725 }
1726
1727 void url_module(const char *url, char *w2)
1728 {
1729 int x, y;
1730 char w[255];
1731
1732 y=0;
1733 for(x=strlen(url)-1; x>=0; x--) {
1734 if(url[x] == '/' || y>=sizeof(w)-1) break;
1735 w[y++]=url[x];
1736 }
1737 if (x<0) {
1738 w2[0]='\0';
1739 return;
1740 }
1741
1742 x=0;
1743 for(y=y-1; y>=0; y--) {
1744 w2[x++]=w[y];
1745 }
1746 w2[x]='\0';
1747 }
1748
1749 void url_to_file(const char *url,char *file,int filesize)
1750 {
1751 int i,skip;
1752
1753 filesize--;
1754 skip=0;
1755 for(i=0; i<filesize && *url; url++) {
1756 if(isalnum(*url) || *url=='-' || *url=='_' || *url=='.' || *url=='%') {
1757 file[i++]=*url;
1758 skip=0;
1759 } else {
1760 if (!skip) file[i++]='_';
1761 skip=1;
1762 }
1763 }
1764 file[i]='\0';
1765 }
1766
1767 void version(void)
1768 {
1769 printf(_("SARG Version: %s\n"),VERSION);
1770 exit(EXIT_SUCCESS);
1771 }
1772
1773 char *get_param_value(const char *param,char *line)
1774 {
1775 int plen;
1776
1777 while (*line==' ' || *line=='\t') line++;
1778 plen=strlen(param);
1779 if (strncasecmp(line,param,plen)) return(NULL);
1780 if (line[plen]!=' ' && line[plen]!='\t') return(NULL);
1781 line+=plen;
1782 while (*line==' ' || *line=='\t') line++;
1783 return(line);
1784 }
1785
1786 void unlinkdir(const char *dir,int contentonly)
1787 {
1788 struct stat st;
1789 DIR *dirp;
1790 struct dirent *direntp;
1791 char dname[MAXLEN];
1792 int err;
1793
1794 dirp=opendir(dir);
1795 if (!dirp) return;
1796 while ((direntp = readdir(dirp)) != NULL) {
1797 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
1798 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
1799 continue;
1800 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
1801 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
1802 exit(EXIT_FAILURE);
1803 }
1804 #ifdef HAVE_LSTAT
1805 err=lstat(dname,&st);
1806 #else
1807 err=stat(dname,&st);
1808 #endif
1809 if (err) {
1810 debuga(_("cannot stat %s\n"),dname);
1811 exit(EXIT_FAILURE);
1812 }
1813 if (S_ISREG(st.st_mode)) {
1814 if (unlink(dname)) {
1815 debuga(_("cannot delete %s - %s\n"),dname,strerror(errno));
1816 exit(EXIT_FAILURE);
1817 }
1818 } else if (S_ISDIR(st.st_mode)) {
1819 unlinkdir(dname,0);
1820 } else {
1821 debuga(_("unknown path type %s\n"),dname);
1822 }
1823 }
1824 closedir(dirp);
1825
1826 if (!contentonly) {
1827 if (rmdir(dir)) {
1828 debuga(_("cannot delete %s - %s\n"),dir,strerror(errno));
1829 exit(EXIT_FAILURE);
1830 }
1831 }
1832 }
1833
1834 /*!
1835 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
1836 prefix size.
1837
1838 \param buf The buffer to parse.
1839 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
1840 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
1841 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
1842 \param nbits The number of prefix bits for an IP address.
1843 \param next The content of the line after the extracted address.
1844
1845 \retval 3 The pattern is a IPv6 address.
1846 \retval 2 The pattern is a IPv4 address.
1847 \retval 1 The patter is a string.
1848 \retval 0 Empty pattern.
1849 */
1850 int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next)
1851 {
1852 int i;
1853 int j;
1854 int ip_size;
1855 unsigned int value4, value6;
1856 unsigned short int addr[8];
1857 int addr_len;
1858 int nibble6_len;
1859 int mask, max_mask;
1860 int pad_pos;
1861 int pad_len;
1862 int bracket=false;
1863
1864 // skip leading spaces and tabs
1865 while (*buf && (*buf==' ' || *buf=='\t')) buf++;
1866
1867 // find out the nature of the pattern
1868 ip_size=0x60 | 0x04;
1869 if (*buf=='[') {
1870 bracket=true;
1871 ip_size=0x60;
1872 buf++;
1873 }
1874 value4=0U;
1875 value6=0U;
1876 addr_len=0;
1877 nibble6_len=0;
1878 pad_pos=-1;
1879 for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
1880 if (ip_size & 0x04) {
1881 if (isdigit(buf[i])) {
1882 value4=value4*10+(buf[i]-'0');
1883 if (value4>0xFFU) ip_size&=~0x04;
1884 } else if (buf[i]=='.' && addr_len<4) {
1885 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
1886 value4=0U;
1887 } else {
1888 ip_size&=~0x04;
1889 }
1890 }
1891 if (ip_size & 0x60) {
1892 if (isdigit(buf[i])) {
1893 value6=(value6<<4)+(buf[i]-'0');
1894 nibble6_len++;
1895 if (value6>0xFFFFU) ip_size&=~0x60;
1896 } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') {
1897 value6=(value6<<4)+(toupper(buf[i])-'A'+10);
1898 nibble6_len++;
1899 if (value6>0xFFFFU) ip_size&=~0x60;
1900 } else if (buf[i]==':' && addr_len<8) {
1901 if (nibble6_len>0) {
1902 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
1903 nibble6_len=0;
1904 }
1905 value6=0U;
1906 if (buf[i+1]==':') {
1907 pad_pos=addr_len;
1908 i++;
1909 }
1910 } else {
1911 ip_size&=~0x60;
1912 }
1913 }
1914 }
1915 if (i==0) return(0);
1916 if (ip_size & 0x04) {
1917 if (addr_len!=3)
1918 ip_size&=~0x04;
1919 else
1920 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
1921 }
1922 if (ip_size & 0x60) {
1923 if (pad_pos<0 && addr_len!=7) {
1924 ip_size&=~0x60;
1925 } else if (pad_pos>=0 && addr_len>=7)
1926 ip_size&=~0x60;
1927 else if (nibble6_len>0)
1928 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
1929 }
1930 if (!ip_size) {
1931 *text=buf;
1932 if (bracket) (*text)--;
1933 while ((unsigned char)buf[i]>' ') i++;
1934 if (next) *next=buf+i;
1935 return(1);
1936 }
1937 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
1938 if (buf[i]=='/') {
1939 i++;
1940 mask=atoi(buf+i);
1941 while (isdigit(buf[i])) i++;
1942 if (mask<0 || mask>max_mask) mask=max_mask;
1943 } else
1944 mask=max_mask;
1945 if (ip_size & 0x60 && bracket && buf[i]==']') i++;
1946 if (next) *next=buf+i;
1947 if (ip_size & 0x04) {
1948 if (nbits) *nbits=mask;
1949 for (i=0 ; i<addr_len ; i++)
1950 ipv4[i]=(unsigned char)addr[i];
1951 return(2);
1952 }
1953
1954 // IPv6 address
1955 if (nbits) *nbits=mask;
1956 i=0;
1957 j=0;
1958 if (pad_pos>=0) {
1959 while (i<pad_pos)
1960 ipv6[j++]=(unsigned short int)addr[i++];
1961 pad_len=8-addr_len;
1962 while (j<pad_pos+pad_len)
1963 ipv6[j++]=0;
1964 }
1965 while (i<addr_len)
1966 ipv6[j++]=(unsigned short int)addr[i++];
1967 return(3);
1968 }