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