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