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