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