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