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