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