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