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