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