]> git.ipfire.org Git - thirdparty/sarg.git/blob - util.c
Explain the reason when a file cannot be opened
[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 /*!
952 Update the \a main period to encompass the period in \a candidate.
953 */
954 void getperiod_merge(struct periodstruct *main,struct periodstruct *candidate)
955 {
956 int cdate;
957 int mdate;
958
959 mdate=(main->start.tm_year)*10000+(main->start.tm_mon)*100+main->start.tm_mday;
960 cdate=(candidate->start.tm_year)*10000+(candidate->start.tm_mon)*100+candidate->start.tm_mday;
961 if (cdate<mdate) memcpy(&main->start,&candidate->start,sizeof(struct tm));
962
963 mdate=(main->end.tm_year)*10000+(main->end.tm_mon)*100+main->end.tm_mday;
964 cdate=(candidate->end.tm_year)*10000+(candidate->end.tm_mon)*100+candidate->end.tm_mday;
965 if (cdate>mdate) memcpy(&main->end,&candidate->end,sizeof(struct tm));
966 }
967
968 int getperiod_buildtext(struct periodstruct *period)
969 {
970 int i;
971 int range;
972 char text1[40], text2[40];
973
974 if (df=='u') {
975 i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
976 } else if(df=='e') {
977 i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
978 } else /*if (df=='w')*/ {
979 IndexTree=INDEX_TREE_FILE;
980 i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
981 }
982 if (i == 0) return(-1);
983
984 range=(period->start.tm_year!=period->end.tm_year ||
985 period->start.tm_mon!=period->end.tm_mon ||
986 period->start.tm_mday!=period->end.tm_mday);
987 if (range) {
988 if (df=='u') {
989 i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
990 } else if (df=='e') {
991 i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
992 } else {
993 i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
994 }
995 if (i == 0) return(-1);
996 }
997
998 if (range) {
999 snprintf(period->text,sizeof(period->text),"%s-%s",text1,text2);
1000 snprintf(period->html,sizeof(period->html),"%s&mdash;%s",text1,text2);
1001 } else {
1002 safe_strcpy(period->text,text1,sizeof(period->text));
1003 safe_strcpy(period->html,text1,sizeof(period->html));
1004 }
1005 return(0);
1006 }
1007
1008 static void copy_images(void)
1009 {
1010 FILE *img_in, *img_ou;
1011 char images[512];
1012 char imgdir[MAXLEN];
1013 char srcfile[MAXLEN];
1014 char dstfile[MAXLEN];
1015 DIR *dirp;
1016 struct dirent *direntp;
1017 char buffer[MAXLEN];
1018 size_t nread;
1019 struct stat info;
1020
1021 if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
1022 debuga(_("Cannot copy images to target directory %simages\n"),outdir);
1023 exit(EXIT_FAILURE);
1024 }
1025 if (access(images,R_OK)!=0) {
1026 if (mkdir(images,0755)) {
1027 debuga(_("Cannot create directory %s - %s\n"),images,strerror(errno));
1028 exit(EXIT_FAILURE);
1029 }
1030 }
1031
1032 strcpy(imgdir,IMAGEDIR);
1033 dirp = opendir(imgdir);
1034 if(dirp==NULL) {
1035 debuga(_("(util) Can't open directory %s: %s\n"),imgdir,strerror(errno));
1036 return;
1037 }
1038 while ((direntp = readdir( dirp )) != NULL ){
1039 if(direntp->d_name[0]=='.')
1040 continue;
1041 sprintf(srcfile,"%s/%s",imgdir,direntp->d_name);
1042 if (stat(srcfile,&info)) {
1043 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile,strerror(errno));
1044 continue;
1045 }
1046 if (S_ISREG(info.st_mode)) {
1047 sprintf(dstfile,"%s/%s",images,direntp->d_name);
1048 img_in = fopen(srcfile, "rb");
1049 if(img_in!=NULL) {
1050 img_ou = fopen(dstfile, "wb");
1051 if(img_ou!=NULL) {
1052 while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
1053 if (fwrite(buffer,1,nread,img_ou)!=nread) {
1054 debuga(_("Failed to copy image %s to %s\n"),srcfile,dstfile);
1055 break;
1056 }
1057 }
1058 fclose(img_ou);
1059 } else
1060 fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile, strerror(errno));
1061 fclose(img_in);
1062 } else
1063 fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile, strerror(errno));
1064 }
1065 }
1066 (void) closedir(dirp);
1067
1068 return;
1069 }
1070
1071 int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form)
1072 {
1073 FILE *fp_ou;
1074 int num=1, count=0;
1075 char wdir[MAXLEN];
1076 char dirname2[MAXLEN];
1077 int y1, y2;
1078 int m1, m2;
1079 int d1, d2;
1080 int wlen, wlen2;
1081 time_t curtime;
1082 struct tm *loctm;
1083
1084 strcpy(wdir,outdir);
1085 wlen=strlen(wdir);
1086 y1=per1->start.tm_year+1900;
1087 y2=per1->end.tm_year+1900;
1088 m1=per1->start.tm_mon+1;
1089 m2=per1->end.tm_mon+1;
1090 d1=per1->start.tm_mday;
1091 d2=per1->end.tm_mday;
1092 if(IndexTree == INDEX_TREE_DATE) {
1093 wlen+=sprintf(wdir+wlen,"%04d",y1);
1094 if(y1!=y2) wlen+=sprintf(wdir+wlen,"-%04d",y2);
1095 if(access(wdir, R_OK) != 0)
1096 my_mkdir(wdir);
1097
1098 wlen+=sprintf(wdir+wlen,"/%02d",m1);
1099 if(m1 != m2) wlen+=sprintf(wdir+wlen,"-%02d",m2);
1100 if(access(wdir, R_OK) != 0)
1101 my_mkdir(wdir);
1102
1103 wlen+=sprintf(wdir+wlen,"/%02d",d1);
1104 if(d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
1105 } else {
1106 if (df == 'u') {
1107 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
1108 conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
1109 } else if (df == 'e') {
1110 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
1111 conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
1112 } else if (df == 'w') {
1113 wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
1114 if (wlen2==0) return(-1);
1115 wlen+=wlen2;
1116 }
1117 }
1118
1119 if(us[0] != '\0') {
1120 struct userinfostruct *uinfo=userinfo_find_from_id(us);
1121 if (uinfo) {
1122 strcat(wdir,"-");
1123 strcat(wdir,uinfo->filename);
1124 }
1125 }
1126 if(addr[0] != '\0') {
1127 strcat(wdir,"-");
1128 strcat(wdir,addr);
1129 }
1130 if(site[0] != '\0') {
1131 strcat(wdir,"-");
1132 strcat(wdir,site);
1133 }
1134
1135 strcpy(outdirname,wdir);
1136
1137 if(IndexTree != INDEX_TREE_DATE) {
1138 if(!OverwriteReport) {
1139 while(num) {
1140 if(access(wdir,R_OK) == 0) {
1141 sprintf(wdir,"%s.%d",outdirname,num);
1142 num++;
1143 count++;
1144 } else
1145 break;
1146 }
1147
1148 if(count > 0) {
1149 if(debug)
1150 debuga(_("File %s already exists, moved to %s\n"),outdirname,wdir);
1151 rename(outdirname,wdir);
1152 }
1153 } else {
1154 if(access(outdirname,R_OK) == 0) {
1155 unlinkdir(outdirname,1);
1156 }
1157 }
1158 my_mkdir(outdirname);
1159 } else {
1160 strcpy(dirname2,wdir);
1161 if(!OverwriteReport) {
1162 while(num) {
1163 if(access(wdir,R_OK) == 0) {
1164 sprintf(wdir,"%s.%d",dirname2,num);
1165 num++;
1166 count++;
1167 } else
1168 break;
1169 }
1170
1171 if(count > 0) {
1172 if(debug)
1173 debuga(_("File %s already exists, moved to %s\n"),dirname2,wdir);
1174 rename(dirname2,wdir);
1175 strcpy(dirname2,wdir);
1176 }
1177 } else {
1178 if(access(wdir,R_OK) == 0) {
1179 unlinkdir(wdir,1);
1180 }
1181 }
1182
1183 if(access(wdir, R_OK) != 0)
1184 my_mkdir(wdir);
1185 }
1186
1187 strcpy(dirname2,wdir);
1188
1189 sprintf(wdir,"%s/sarg-date",outdirname);
1190 if ((fp_ou = fopen(wdir, "wt")) == 0) {
1191 debuga(_("cannot open %s for writing: %s\n"),wdir,strerror(errno));
1192 perror("SARG:");
1193 exit(EXIT_FAILURE);
1194 }
1195 time(&curtime);
1196 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1197 loctm=localtime(&curtime);
1198 strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
1199 if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
1200 debuga(_("Failed to write the date in %s\n"),wdir);
1201 perror("SARG:");
1202 exit(EXIT_FAILURE);
1203 }
1204 if (fclose(fp_ou)==EOF) {
1205 debuga(_("Failed to write the date in %s\n"),wdir);
1206 perror("SARG:");
1207 exit(EXIT_FAILURE);
1208 }
1209
1210 copy_images();
1211 return(0);
1212 }
1213
1214 /*!
1215 Copy a string without overflowing the buffer. The copied string
1216 is properly terminated by an ASCII zero.
1217
1218 \param dest The destination buffer.
1219 \param src The source buffer.
1220 \param length The size of the destination buffer. The program is aborted
1221 if the length is negative or zero.
1222 */
1223 void safe_strcpy(char *dest,const char *src,int length)
1224 {
1225 if (length<=0) {
1226 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1227 exit(EXIT_FAILURE);
1228 }
1229 strncpy(dest,src,length-1);
1230 dest[length-1]='\0';
1231 }
1232
1233 void strip_latin(char *line)
1234 {
1235 int i,j;
1236 int skip;
1237
1238 j=0;
1239 skip=0;
1240 for (i=0;line[i];i++){
1241 if (skip){
1242 if (line[i]==';') skip=0;
1243 } else {
1244 if (line[i]=='&')
1245 skip=1;
1246 else
1247 line[j++]=line[i];
1248 }
1249 }
1250 line[j]='\0';
1251 return;
1252 }
1253
1254 void zdate(char *ftime,int ftimesize, char DateFormat)
1255 {
1256 time_t t;
1257 struct tm *local;
1258
1259 t = time(NULL);
1260 local = localtime(&t);
1261 if (DateFormat=='u')
1262 strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
1263 else if (DateFormat=='e')
1264 strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
1265 else if (DateFormat=='w')
1266 strftime(ftime, ftimesize, "%W-%H-%M", local);
1267 return;
1268 }
1269
1270
1271 char *fixtime(long long int elap)
1272 {
1273 int num = elap / 1000;
1274 int hor = 0;
1275 int min = 0;
1276 int sec = 0;
1277 static char buf[12];
1278
1279 hor=num / 3600;
1280 min=(num % 3600) / 60;
1281 sec=num % 60;
1282
1283 if(hor==0 && min==0 && sec==0)
1284 strcpy(buf,"0");
1285 else
1286 sprintf(buf,"%d:%02d:%02d",hor,min,sec);
1287
1288 return buf;
1289 }
1290
1291
1292 void date_from(char *date, int *dfrom, int *duntil)
1293 {
1294 int d0=0;
1295 int m0=0;
1296 int y0=0;
1297 int d1=0;
1298 int m1=0;
1299 int y1=0;
1300
1301 if (isdigit(date[0])) {
1302 int next=-1;
1303
1304 if (sscanf(date,"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
1305 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1306 exit(EXIT_FAILURE);
1307 }
1308 if (date[next]=='-') {
1309 if (sscanf(date+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
1310 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1311 exit(EXIT_FAILURE);
1312 }
1313 } else if (date[next]!='\0') {
1314 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1315 exit(EXIT_FAILURE);
1316 } else {
1317 d1=d0;
1318 m1=m0;
1319 y1=y0;
1320 }
1321 } else {
1322 int i;
1323 time_t Today,t1;
1324 struct tm *Date0,Date1;
1325
1326 if (time(&Today)==(time_t)-1) {
1327 debuga(_("Failed to get the current time\n"));
1328 exit(EXIT_FAILURE);
1329 }
1330 if (sscanf(date,"day-%d",&i)==1) {
1331 if (i<0) {
1332 debuga(_("Invalid number of days in -d parameter\n"));
1333 exit(EXIT_FAILURE);
1334 }
1335 Today-=i*24*60*60;
1336 Date0=localtime(&Today);
1337 if (Date0==NULL) {
1338 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1339 exit(EXIT_FAILURE);
1340 }
1341 y0=y1=Date0->tm_year+1900;
1342 m0=m1=Date0->tm_mon+1;
1343 d0=d1=Date0->tm_mday;
1344 } else if (sscanf(date,"week-%d",&i)==1) {
1345 /*
1346 There is no portable way to find the first day of the week even though the
1347 information is available in the locale. nl_langinfo has the unofficial
1348 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1349 undocumented as is their return value and it is discouraged to use them.
1350 Beside, nl_langinfo isn't available on windows and the first day of the
1351 week isn't available at all on that system.
1352 */
1353 const int FirstWeekDay=1;
1354 time_t WeekBegin;
1355
1356 if (i<0) {
1357 debuga(_("Invalid number of weeks in -d parameter\n"));
1358 exit(EXIT_FAILURE);
1359 }
1360 Date0=localtime(&Today);
1361 if (Date0==NULL) {
1362 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1363 exit(EXIT_FAILURE);
1364 }
1365 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1366 WeekBegin-=i*7*24*60*60;
1367 Date0=localtime(&WeekBegin);
1368 if (Date0==NULL) {
1369 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1370 exit(EXIT_FAILURE);
1371 }
1372 y0=Date0->tm_year+1900;
1373 m0=Date0->tm_mon+1;
1374 d0=Date0->tm_mday;
1375 WeekBegin+=6*24*60*60;
1376 Date0=localtime(&WeekBegin);
1377 if (Date0==NULL) {
1378 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1379 exit(EXIT_FAILURE);
1380 }
1381 y1=Date0->tm_year+1900;
1382 m1=Date0->tm_mon+1;
1383 d1=Date0->tm_mday;
1384 } else if (sscanf(date,"month-%d",&i)==1) {
1385 if (i<0) {
1386 debuga(_("Invalid number of months in -d parameter\n"));
1387 exit(EXIT_FAILURE);
1388 }
1389 Date0=localtime(&Today);
1390 if (Date0==NULL) {
1391 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1392 exit(EXIT_FAILURE);
1393 }
1394 if (Date0->tm_mon<i%12) {
1395 y0=Date0->tm_year+1900-i/12-1;
1396 m0=(Date0->tm_mon+12-i%12)%12+1;
1397 d0=1;
1398 } else {
1399 y0=Date0->tm_year+1900-i/12;
1400 m0=Date0->tm_mon-i%12+1;
1401 d0=1;
1402 }
1403 memcpy(&Date1,Date0,sizeof(struct tm));
1404 Date1.tm_isdst=-1;
1405 Date1.tm_mday=1;
1406 if (m0<12) {
1407 Date1.tm_mon=m0;
1408 Date1.tm_year=y0-1900;
1409 } else {
1410 Date1.tm_mon=0;
1411 Date1.tm_year=y0-1900+1;
1412 }
1413 t1=mktime(&Date1);
1414 t1-=24*60*60;
1415 Date0=localtime(&t1);
1416 y1=Date0->tm_year+1900;
1417 m1=Date0->tm_mon+1;
1418 d1=Date0->tm_mday;
1419 } else {
1420 debuga(_("Invalid date range passed on command line\n"));
1421 exit(EXIT_FAILURE);
1422 }
1423 }
1424
1425 *dfrom=y0*10000+m0*100+d0;
1426 *duntil=y1*10000+m1*100+d1;
1427 sprintf(date,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
1428 return;
1429 }
1430
1431
1432 char *strlow(char *string)
1433 {
1434 char *s;
1435
1436 if (string)
1437 {
1438 for (s = string; *s; ++s)
1439 *s = tolower(*s);
1440 }
1441
1442 return string;
1443 }
1444
1445
1446
1447
1448 char *strup(char *string)
1449 {
1450 char *s;
1451
1452 if (string)
1453 {
1454 for (s = string; *s; ++s)
1455 *s = toupper(*s);
1456 }
1457
1458 return string;
1459 }
1460
1461
1462 void removetmp(const char *outdir)
1463 {
1464 FILE *fp_gen;
1465 char filename[256];
1466
1467 if(!RemoveTempFiles)
1468 return;
1469
1470 if(debug) {
1471 debuga(_("Purging temporary file sarg-general\n"));
1472 }
1473 if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
1474 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir);
1475 exit(EXIT_FAILURE);
1476 }
1477 if((fp_gen=fopen(filename,"w"))==NULL){
1478 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename,strerror(errno));
1479 exit(EXIT_FAILURE);
1480 }
1481 totalger(fp_gen,filename);
1482 if (fclose(fp_gen)==EOF) {
1483 debuga(_("Failed to close %s after writing the total line - %s\n"),filename,strerror(errno));
1484 exit(EXIT_FAILURE);
1485 }
1486 }
1487
1488 void load_excludecodes(const char *ExcludeCodes)
1489 {
1490 FILE *fp_in;
1491 char data[80];
1492 int i;
1493 int Stored;
1494 long int MemSize;
1495
1496 if(ExcludeCodes[0] == '\0')
1497 return;
1498
1499 if((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
1500 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes,strerror(errno));
1501 exit(EXIT_FAILURE);
1502 }
1503
1504 if (fseek(fp_in, 0, SEEK_END)==-1) {
1505 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1506 exit(EXIT_FAILURE);
1507 }
1508 MemSize = ftell(fp_in);
1509 if (MemSize<0) {
1510 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes);
1511 exit(EXIT_FAILURE);
1512 }
1513 if (fseek(fp_in, 0, SEEK_SET)==-1) {
1514 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1515 exit(EXIT_FAILURE);
1516 }
1517
1518 MemSize+=1;
1519 if((excludecode=(char *) malloc(MemSize))==NULL) {
1520 debuga(_("malloc error (%ld)\n"),MemSize);
1521 exit(EXIT_FAILURE);
1522 }
1523 memset(excludecode,0,MemSize);
1524
1525 Stored=0;
1526 while(fgets(data,sizeof(data),fp_in)!=NULL) {
1527 if (data[0]=='#') continue;
1528 for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
1529 if (i<0) continue;
1530 if (Stored+i+2>=MemSize) {
1531 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes);
1532 break;
1533 }
1534 strcat(excludecode,data);
1535 strcat(excludecode,";");
1536 Stored+=i+1;
1537 }
1538
1539 fclose(fp_in);
1540 return;
1541 }
1542
1543 void free_excludecodes(void)
1544 {
1545 if (excludecode) {
1546 free(excludecode);
1547 excludecode=NULL;
1548 }
1549 }
1550
1551 int vercode(const char *code)
1552 {
1553 char *cod;
1554 int clen;
1555
1556 if (excludecode && excludecode[0]!='\0') {
1557 clen=strlen(code);
1558 cod=excludecode;
1559 while (cod) {
1560 if (strncmp(code,cod,clen)==0 && cod[clen]==';')
1561 return 1;
1562 cod=strchr(cod,';');
1563 if (cod) cod++;
1564 }
1565 }
1566 return 0;
1567 }
1568
1569 void fixnone(char *str)
1570 {
1571 int i;
1572
1573 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--);
1574 if(i==3 && strncmp(str,"none",4) == 0)
1575 str[0]='\0';
1576
1577 return;
1578 }
1579
1580 void fixendofline(char *str)
1581 {
1582 int i;
1583
1584 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--) str[i]=0;
1585 }
1586
1587 #ifdef LEGACY_TESTVALIDUSERCHAR
1588 int testvaliduserchar(const char *user)
1589 {
1590 int x=0;
1591 int y=0;
1592
1593 for (y=0; y<strlen(UserInvalidChar); y++) {
1594 for (x=0; x<strlen(user); x++) {
1595 if(user[x] == UserInvalidChar[y])
1596 return 1;
1597 }
1598 }
1599 return 0;
1600 }
1601 #else
1602 int testvaliduserchar(const char *user)
1603 {
1604 char * p_UserInvalidChar = UserInvalidChar ;
1605 const char * p_user ;
1606
1607 while( *p_UserInvalidChar ) {
1608 p_user = user ;
1609 while ( *p_user ) {
1610 if( *p_UserInvalidChar == *p_user )
1611 return 1;
1612 p_user++ ;
1613 }
1614 p_UserInvalidChar++ ;
1615 }
1616 return 0;
1617 }
1618 #endif
1619
1620 int compar( const void *a, const void *b )
1621 {
1622 if( *(int *)a > *(int *)b ) return 1;
1623 if( *(int *)a < *(int *)b ) return -1;
1624 return 0;
1625 }
1626
1627 int getnumlist( char *buf, numlist *list, const int len, const int maxvalue )
1628 {
1629 int i, j, d, flag, r1, r2;
1630 char *pbuf, **bp, *strbufs[ 24 ];
1631
1632 bp = strbufs;
1633 strtok( buf, " \t" );
1634 for( *bp = strtok( NULL, "," ), list->len = 0; *bp; *bp = strtok( NULL, "," ) ) {
1635 if( ++bp >= &strbufs[ 24 ] )
1636 break;
1637 list->len++;
1638 }
1639 if( ! list->len )
1640 return -1;
1641 d = 0;
1642 for( i = 0; i < list->len; i++ ) {
1643 if( strchr( strbufs[ i ], '-' ) != 0 ) {
1644 pbuf = strbufs[ i ];
1645 strtok( pbuf, "-" );
1646 pbuf = strtok( NULL, "\0" );
1647 r1 = atoi( strbufs[ i ] );
1648 if( ( r2 = atoi( pbuf ) ) >= maxvalue || r1 >= r2 )
1649 return -1;
1650 if( i + d + ( r2 - r1 ) + 1 <= len ) {
1651 for( j = r1; j <= r2; j++ )
1652 list->list[ i + d++ ] = j;
1653 d--;
1654 }
1655 }
1656 else
1657 if( ( list->list[ i + d ] = atoi( strbufs[ i ] ) ) >= maxvalue )
1658 return 1;
1659 }
1660 list->len += d;
1661 qsort( list->list, list->len, sizeof( int ), compar );
1662 do {
1663 flag = 0;
1664 for( i = 0; i < list->len - 1; i++ )
1665 if( list->list[ i ] == list->list[ i + 1 ] ) {
1666 for( j = i + 1; j < list->len; j++ )
1667 list->list[ j - 1 ] = list->list[ j ];
1668 list->len--;
1669 flag = 1;
1670 break;
1671 }
1672 } while( flag );
1673 return 0;
1674 }
1675
1676
1677 char *get_size(const char *path, const char *file)
1678 {
1679 FILE *fp;
1680 static char response[255];
1681 char cmd[255];
1682 char *ptr;
1683
1684 if (snprintf(cmd,sizeof(cmd),"du -skh %s%s",path,file)>=sizeof(cmd)) {
1685 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path,file);
1686 exit(EXIT_FAILURE);
1687 }
1688 if ((fp = popen(cmd, "r")) == NULL) {
1689 debuga(_("Cannot get disk space with command %s\n"),cmd);
1690 exit(EXIT_FAILURE);
1691 }
1692 if (!fgets(response, sizeof(response), fp)) {
1693 debuga(_("Cannot get disk size with command %s\n"),cmd);
1694 exit(EXIT_FAILURE);
1695 }
1696 ptr=strchr(response,'\t');
1697 if (ptr==NULL) {
1698 debuga(_("The command %s failed\n"),cmd);
1699 exit(EXIT_FAILURE);
1700 }
1701 pclose(fp);
1702 *ptr='\0';
1703
1704 return (response);
1705 }
1706
1707 void show_info(FILE *fp_ou)
1708 {
1709 char ftime[127];
1710
1711 if(!ShowSargInfo) return;
1712 zdate(ftime, sizeof(ftime), df);
1713 fprintf(fp_ou,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL,PGM,VERSION,_("on"),ftime);
1714 }
1715
1716 void show_sarg(FILE *fp_ou, int depth)
1717 {
1718 int i;
1719
1720 if(!ShowSargLogo) return;
1721 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
1722 for (i=0 ; i<depth ; i++)
1723 fputs("../",fp_ou);
1724 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);
1725 }
1726
1727 void write_logo_image(FILE *fp_ou)
1728 {
1729 if(LogoImage[0]!='\0')
1730 fprintf(fp_ou, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\">&nbsp;%s</div>\n",LogoImage,Width,Height,LogoText);
1731 }
1732
1733 void write_html_head(FILE *fp_ou, int depth, const char *page_title,int javascript)
1734 {
1735 int i;
1736
1737 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
1738 fprintf(fp_ou, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
1739 if (page_title) fprintf(fp_ou,"<title>%s</title>\n",page_title);
1740 css(fp_ou);
1741 if ((javascript & HTML_JS_SORTTABLE)!=0 && SortTableJs[0]) {
1742 fputs("<script type=\"text/javascript\" src=\"",fp_ou);
1743 if (strncmp(SortTableJs,"../",3)==0) {
1744 for (i=0 ; i<depth ; i++) fputs("../",fp_ou);
1745 }
1746 fputs(SortTableJs,fp_ou);
1747 fputs("\"></script>\n",fp_ou);
1748 }
1749 fputs("</head>\n<body>\n",fp_ou);
1750 }
1751
1752 void write_html_header(FILE *fp_ou, int depth, const char *page_title,int javascript)
1753 {
1754 write_html_head(fp_ou,depth,page_title,javascript);
1755 write_logo_image(fp_ou);
1756 show_sarg(fp_ou, depth);
1757 fprintf(fp_ou,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title);
1758 }
1759
1760 void close_html_header(FILE *fp_ou)
1761 {
1762 fputs("</table></div>\n",fp_ou);
1763 }
1764
1765 int write_html_trailer(FILE *fp_ou)
1766 {
1767 show_info(fp_ou);
1768 if (fputs("</body>\n</html>\n",fp_ou)==EOF) return(-1);
1769 return(0);
1770 }
1771
1772 void output_html_string(FILE *fp_ou,const char *str,int maxlen)
1773 {
1774 int i=0;
1775
1776 while (*str && (maxlen<=0 || i<maxlen)) {
1777 switch (*str) {
1778 case '&':
1779 fputs("&amp;",fp_ou);
1780 break;
1781 case '<':
1782 fputs("&lt;",fp_ou);
1783 break;
1784 case '>':
1785 fputs("&gt;",fp_ou);
1786 break;
1787 case '"':
1788 fputs("&quot;",fp_ou);
1789 break;
1790 case '\'':
1791 fputs("&#39;",fp_ou);
1792 break;
1793 default:
1794 fputc(*str,fp_ou);
1795 }
1796 str++;
1797 i++;
1798 }
1799 if (maxlen>0 && i>=maxlen)
1800 fputs("&hellip;",fp_ou);
1801 }
1802
1803 void output_html_url(FILE *fp_ou,const char *url)
1804 {
1805 while (*url) {
1806 if (*url=='&')
1807 fputs("&amp;",fp_ou);
1808 else
1809 fputc(*url,fp_ou);
1810 url++;
1811 }
1812 }
1813
1814 /*!
1815 Write a host name inside an A tag of a HTML file. If the host name starts
1816 with a star, it is assumed to be an alias that cannot be put inside a link
1817 so the A tag is not written around the host name.
1818
1819 \param fp_ou The handle of the HTML file.
1820 \param url The host to display in the HTML file.
1821 \param maxlen The maximum number of characters to print into the host name.
1822 */
1823 void output_html_link(FILE *fp_ou,const char *url,int maxlen)
1824 {
1825 if (url[0]==ALIAS_PREFIX) {
1826 // this is an alias, no need for a A tag
1827 output_html_string(fp_ou,url+1,100);
1828 } else {
1829 if (skip_scheme(url)==url)
1830 fputs("<a href=\"http://",fp_ou);//no scheme in the url, assume http:// to make the link clickable
1831 else
1832 fputs("<a href=\"",fp_ou);//the scheme is in the url, no need to add one
1833 output_html_url(fp_ou,url);
1834 fputs("\">",fp_ou);
1835 output_html_string(fp_ou,url,100);
1836 fputs("</a>",fp_ou);
1837 }
1838 }
1839
1840 void url_module(const char *url, char *w2)
1841 {
1842 int x, y;
1843 char w[255];
1844
1845 y=0;
1846 for(x=strlen(url)-1; x>=0; x--) {
1847 if(url[x] == '/' || y>=sizeof(w)-1) break;
1848 w[y++]=url[x];
1849 }
1850 if (x<0) {
1851 w2[0]='\0';
1852 return;
1853 }
1854
1855 x=0;
1856 for(y=y-1; y>=0; y--) {
1857 w2[x++]=w[y];
1858 }
1859 w2[x]='\0';
1860 }
1861
1862 void url_to_file(const char *url,char *file,int filesize)
1863 {
1864 int i,skip;
1865
1866 filesize--;
1867 skip=0;
1868 for(i=0; i<filesize && *url; url++) {
1869 if(isalnum(*url) || *url=='-' || *url=='_' || *url=='.') {
1870 file[i++]=*url;
1871 skip=0;
1872 } else {
1873 if (!skip) file[i++]='_';
1874 skip=1;
1875 }
1876 }
1877 file[i]='\0';
1878 }
1879
1880 void version(void)
1881 {
1882 printf(_("SARG Version: %s\n"),VERSION);
1883 exit(EXIT_SUCCESS);
1884 }
1885
1886 char *get_param_value(const char *param,char *line)
1887 {
1888 int plen;
1889
1890 while (*line==' ' || *line=='\t') line++;
1891 plen=strlen(param);
1892 if (strncasecmp(line,param,plen)) return(NULL);
1893 if (line[plen]!=' ' && line[plen]!='\t') return(NULL);
1894 line+=plen;
1895 while (*line==' ' || *line=='\t') line++;
1896 return(line);
1897 }
1898
1899 void unlinkdir(const char *dir,bool contentonly)
1900 {
1901 struct stat st;
1902 DIR *dirp;
1903 struct dirent *direntp;
1904 char dname[MAXLEN];
1905 int err;
1906
1907 dirp=opendir(dir);
1908 if (!dirp) return;
1909 while ((direntp = readdir(dirp)) != NULL) {
1910 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
1911 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
1912 continue;
1913 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
1914 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
1915 exit(EXIT_FAILURE);
1916 }
1917 #ifdef HAVE_LSTAT
1918 err=lstat(dname,&st);
1919 #else
1920 err=stat(dname,&st);
1921 #endif
1922 if (err) {
1923 debuga(_("cannot stat %s\n"),dname);
1924 exit(EXIT_FAILURE);
1925 }
1926 if (S_ISREG(st.st_mode)) {
1927 if (unlink(dname)) {
1928 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
1929 exit(EXIT_FAILURE);
1930 }
1931 } else if (S_ISDIR(st.st_mode)) {
1932 unlinkdir(dname,0);
1933 } else {
1934 debuga(_("unknown path type %s\n"),dname);
1935 }
1936 }
1937 closedir(dirp);
1938
1939 if (!contentonly) {
1940 if (rmdir(dir)) {
1941 debuga(_("Cannot delete \"%s\": %s\n"),dir,strerror(errno));
1942 exit(EXIT_FAILURE);
1943 }
1944 }
1945 }
1946
1947 /*!
1948 Delete every file from the temporary directory where sarg is told to store its
1949 temporary files.
1950
1951 As any stray file left over by a previous run would be included in the report, we
1952 must delete every file from the temporary directory before we start processing the logs.
1953
1954 But the temporary directory is given by the user either in the configuration file or
1955 on the command line. We check that the user didn't give a wrong directory by looking
1956 at the files stored in the directory. If a single file is not one of ours, we abort.
1957
1958 \param dir The temporary directory to purge.
1959 */
1960 void emptytmpdir(const char *dir)
1961 {
1962 struct stat st;
1963 DIR *dirp;
1964 struct dirent *direntp;
1965 int dlen;
1966 int elen;
1967 char dname[MAXLEN];
1968 int err;
1969 int i;
1970 static const char *TmpExt[]=
1971 {
1972 ".int_unsort",
1973 ".int_log",
1974 ".day",
1975 "htmlrel.txt",
1976 ".user_unsort",
1977 ".user_log",
1978 ".utmp",
1979 ".ip"
1980 };
1981
1982 dirp=opendir(dir);
1983 if (!dirp) return;
1984
1985 // make sure the temporary directory contains only our files
1986 while ((direntp = readdir(dirp)) != NULL) {
1987 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
1988 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
1989 continue;
1990
1991 // is it one of our files
1992 dlen=strlen(direntp->d_name);
1993 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
1994 elen=strlen(TmpExt[i]);
1995 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
1996 }
1997 if (i<0) {
1998 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
1999 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2000 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2001 exit(EXIT_FAILURE);
2002 }
2003
2004 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2005 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
2006 exit(EXIT_FAILURE);
2007 }
2008
2009 #ifdef HAVE_LSTAT
2010 err=lstat(dname,&st);
2011 #else
2012 err=stat(dname,&st);
2013 #endif
2014 if (err) {
2015 debuga(_("cannot stat \"%s\"\n"),dname);
2016 exit(EXIT_FAILURE);
2017 }
2018 if (S_ISDIR(st.st_mode)) {
2019 unlinkdir(dname,0);
2020 } else if (!S_ISREG(st.st_mode)) {
2021 debuga(_("Unknown path type \"%s\". Check your temporary directory\n"),dname);
2022 exit(EXIT_FAILURE);
2023 }
2024 }
2025 rewinddir(dirp);
2026
2027 // now delete our files
2028 while ((direntp = readdir(dirp)) != NULL) {
2029 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2030 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2031 continue;
2032
2033 // is it one of our files
2034 dlen=strlen(direntp->d_name);
2035 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2036 elen=strlen(TmpExt[i]);
2037 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2038 }
2039 if (i<0) {
2040 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2041 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2042 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2043 exit(EXIT_FAILURE);
2044 }
2045
2046 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2047 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
2048 exit(EXIT_FAILURE);
2049 }
2050 #ifdef HAVE_LSTAT
2051 err=lstat(dname,&st);
2052 #else
2053 err=stat(dname,&st);
2054 #endif
2055 if (err) {
2056 debuga(_("cannot stat \"%s\"\n"),dname);
2057 exit(EXIT_FAILURE);
2058 }
2059 if (S_ISREG(st.st_mode)) {
2060 if (unlink(dname)) {
2061 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2062 exit(EXIT_FAILURE);
2063 }
2064 } else {
2065 debuga(_("unknown path type %s\n"),dname);
2066 }
2067 }
2068 closedir(dirp);
2069 }
2070
2071 /*!
2072 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2073 prefix size.
2074
2075 \param buf The buffer to parse.
2076 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2077 The pointer may be NULL.
2078 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2079 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2080 \param nbits The number of prefix bits for an IP address.
2081 \param next The content of the line after the extracted address.
2082
2083 \retval 3 The pattern is a IPv6 address.
2084 \retval 2 The pattern is a IPv4 address.
2085 \retval 1 The patter is a string.
2086 \retval 0 Empty pattern.
2087 */
2088 int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next)
2089 {
2090 int i;
2091 int j;
2092 int ip_size;
2093 unsigned int value4, value6;
2094 unsigned short int addr[8];
2095 int addr_len;
2096 int nibble6_len;
2097 int mask, max_mask;
2098 int pad_pos;
2099 int pad_len;
2100 bool bracket=false;
2101 bool port=false;
2102 bool port_num=0;
2103
2104 // skip leading spaces and tabs
2105 while (*buf && (*buf==' ' || *buf=='\t')) buf++;
2106
2107 // find out the nature of the pattern
2108 ip_size=0x60 | 0x04;
2109 if (*buf=='[') {
2110 bracket=true;
2111 ip_size=0x60;
2112 buf++;
2113 }
2114 value4=0U;
2115 value6=0U;
2116 addr_len=0;
2117 nibble6_len=0;
2118 pad_pos=-1;
2119 for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
2120 if (ip_size & 0x04) {
2121 if (isdigit(buf[i])) {
2122 if (port) {
2123 port_num=port_num*10+(buf[i]-'0');
2124 if (port_num>65535) ip_size&=~0x04;
2125 } else {
2126 value4=value4*10+(buf[i]-'0');
2127 if (value4>0xFFU) ip_size&=~0x04;
2128 }
2129 } else if (buf[i]=='.' && addr_len<4) {
2130 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2131 value4=0U;
2132 } else if (!port && buf[i]==':') {
2133 port=true;
2134 } else {
2135 ip_size&=~0x04;
2136 }
2137 }
2138 if (ip_size & 0x60) {
2139 if (isdigit(buf[i])) {
2140 value6=(value6<<4)+(buf[i]-'0');
2141 nibble6_len++;
2142 if (value6>0xFFFFU) ip_size&=~0x60;
2143 } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') {
2144 value6=(value6<<4)+(toupper(buf[i])-'A'+10);
2145 nibble6_len++;
2146 if (value6>0xFFFFU) ip_size&=~0x60;
2147 } else if (buf[i]==':' && addr_len<8) {
2148 if (nibble6_len>0) {
2149 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2150 nibble6_len=0;
2151 }
2152 value6=0U;
2153 if (buf[i+1]==':') {
2154 pad_pos=addr_len;
2155 i++;
2156 }
2157 } else {
2158 ip_size&=~0x60;
2159 }
2160 }
2161 }
2162 if (i==0) return(0);
2163 if (ip_size & 0x04) {
2164 if (addr_len!=3)
2165 ip_size&=~0x04;
2166 else
2167 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2168 }
2169 if (ip_size & 0x60) {
2170 if (pad_pos<0 && addr_len!=7) {
2171 ip_size&=~0x60;
2172 } else if (pad_pos>=0 && addr_len>=7)
2173 ip_size&=~0x60;
2174 else if (nibble6_len>0)
2175 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2176 }
2177 if (!ip_size) {
2178 if (text) {
2179 *text=buf;
2180 if (bracket) (*text)--;
2181 }
2182 while ((unsigned char)buf[i]>' ') i++;
2183 if (next) *next=buf+i;
2184 return(1);
2185 }
2186 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
2187 if (buf[i]=='/') {
2188 i++;
2189 mask=atoi(buf+i);
2190 while (isdigit(buf[i])) i++;
2191 if (mask<0 || mask>max_mask) mask=max_mask;
2192 } else
2193 mask=max_mask;
2194 if (ip_size & 0x60 && bracket && buf[i]==']') i++;
2195 if (next) *next=buf+i;
2196 if (ip_size & 0x04) {
2197 if (nbits) *nbits=mask;
2198 for (i=0 ; i<addr_len ; i++)
2199 ipv4[i]=(unsigned char)addr[i];
2200 return(2);
2201 }
2202
2203 // IPv6 address
2204 if (nbits) *nbits=mask;
2205 i=0;
2206 j=0;
2207 if (pad_pos>=0) {
2208 while (i<pad_pos)
2209 ipv6[j++]=(unsigned short int)addr[i++];
2210 pad_len=8-addr_len;
2211 while (j<pad_pos+pad_len)
2212 ipv6[j++]=0;
2213 }
2214 while (i<addr_len)
2215 ipv6[j++]=(unsigned short int)addr[i++];
2216 return(3);
2217 }