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