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