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