]> git.ipfire.org Git - thirdparty/sarg.git/blob - util.c
Use the function name in a message to reduce the number of messages.
[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 fclose(fp_in);
797 fixendofline(data);
798
799 return(0);
800 }
801
802
803 void formatdate(char *date,int date_size,int year,int month,int day,int hour,int minute,int second,int dst)
804 {
805 struct tm ltm;
806 time_t unixtime;
807 struct tm *fulltm;
808
809 memset(&ltm,0,sizeof(ltm));
810 if (year>=1900) ltm.tm_year=year-1900;
811 if (month>=1 && month<=12) ltm.tm_mon=month-1;
812 if (day>=1 && day<=31) ltm.tm_mday=day;
813 if (hour>=0 && hour<24) ltm.tm_hour=hour;
814 if (minute>=0 && minute<60) ltm.tm_min=minute;
815 if (second>=0 && second<60) ltm.tm_sec=second;
816 ltm.tm_isdst=dst;
817 unixtime=mktime(&ltm); //fill the missing entries
818 fulltm=localtime(&unixtime);
819 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
820 strftime(date,date_size,"%c",fulltm);
821 }
822
823
824 void computedate(int year,int month,int day,struct tm *t)
825 {
826 memset(t,0,sizeof(*t));
827 t->tm_year=year-1900;
828 t->tm_mon=month-1;
829 t->tm_mday=day;
830 }
831
832
833 int obtuser(const char *dirname, const char *name)
834 {
835 FILE *fp_in;
836 char wdir[MAXLEN];
837 char tuser[20];
838 int nuser;
839
840 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-users",dirname,name)>=sizeof(wdir)) {
841 debuga(_("Buffer too small to store "));
842 debuga_more("%s%s/sarg-users",dirname,name);
843 exit(EXIT_FAILURE);
844 }
845 if((fp_in=fopen(wdir,"r"))==NULL) {
846 if (snprintf(wdir,sizeof(wdir),"%s%s/users",dirname,name)>=sizeof(wdir)) {
847 debuga(_("Buffer too small to store "));
848 debuga_more("%s%s/users",dirname,name);
849 exit(EXIT_FAILURE);
850 }
851 if((fp_in=fopen(wdir,"r"))==NULL) {
852 return(0);
853 }
854 }
855
856 if (!fgets(tuser,sizeof(tuser),fp_in)) {
857 debuga(_("Failed to read the number of users in %s\n"),wdir);
858 exit(EXIT_FAILURE);
859 }
860 fclose(fp_in);
861 nuser=atoi(tuser);
862
863 return(nuser);
864 }
865
866
867 void obttotal(const char *dirname, const char *name, int nuser, long long int *tbytes, long long int *media)
868 {
869 FILE *fp_in;
870 char *buf;
871 char wdir[MAXLEN];
872 char user[MAX_USER_LEN];
873 char sep;
874 struct getwordstruct gwarea;
875 longline line;
876
877 *tbytes=0;
878 *media=0;
879
880 if (snprintf(wdir,sizeof(wdir),"%s%s/sarg-general",dirname,name)>=sizeof(wdir)) {
881 debuga(_("Buffer too small to store "));
882 debuga_more("%s%s/sarg-general",dirname,name);
883 exit(EXIT_FAILURE);
884 }
885 if ((fp_in = fopen(wdir, "r")) == 0) {
886 if (snprintf(wdir,sizeof(wdir),"%s%s/general",dirname,name)>=sizeof(wdir)) {
887 debuga(_("Buffer too small to store "));
888 debuga_more("%s%s/general",dirname,name);
889 exit(EXIT_FAILURE);
890 }
891 if ((fp_in = fopen(wdir, "r")) == 0) {
892 return;
893 }
894 }
895
896 if ((line=longline_create())==NULL) {
897 debuga(_("Not enough memory to read the file %s\n"),wdir);
898 exit(EXIT_FAILURE);
899 }
900
901 while((buf=longline_read(fp_in,line))!=NULL) {
902 if (strncmp(buf,"TOTAL\t",6) == 0)
903 sep='\t'; //new file
904 else if (strncmp(buf,"TOTAL ",6) == 0)
905 sep=' '; //old file
906 else
907 continue;
908 getword_start(&gwarea,buf);
909 if (getword(user,sizeof(user),&gwarea,sep)<0) {
910 debuga(_("There is a invalid user in file %s\n"),wdir);
911 exit(EXIT_FAILURE);
912 }
913 if(strcmp(user,"TOTAL") != 0)
914 continue;
915 if (getword_skip(MAXLEN,&gwarea,sep)<0) {
916 debuga(_("There a broken total number of access in file %s\n"),wdir);
917 exit(EXIT_FAILURE);
918 }
919 if (getword_atoll(tbytes,&gwarea,sep)<0) {
920 debuga(_("There is a broken number of bytes in file %s\n"),wdir);
921 exit(EXIT_FAILURE);
922 }
923 break;
924 }
925 fclose(fp_in);
926 longline_destroy(&line);
927
928 if (nuser <= 0)
929 return;
930
931 *media=*tbytes / nuser;
932 return;
933 }
934
935 int getperiod_fromsarglog(const char *arqtt,struct periodstruct *period)
936 {
937 const char *str;
938 int day0, month0, year0, hour0, minute0;
939 int day1, month1, year1, hour1, minute1;
940 int i;
941
942 memset(period,0,sizeof(*period));
943
944 str=arqtt;
945 while((str=strstr(str,"sarg-"))!=NULL) {
946 str+=5;
947 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
948 day0=(str[0]-'0')*10+(str[1]-'0');
949 if (day0<1 || day0>31) continue;
950 str+=2;
951 month0=(str[0]-'0')*10+(str[1]-'0')-1;
952 if (month0<0 || month0>11) continue;
953 str+=2;
954 year0=0;
955 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year0=year0*10+(str[i]-'0');
956 if (i!=4) continue;
957 str+=4;
958 if (str[0]!='_') continue;
959 str++;
960
961 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
962 hour0=(str[0]-'0')*10+(str[1]-'0');
963 str+=2;
964 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
965 minute0=(str[0]-'0')*10+(str[1]-'0');
966 str+=2;
967
968 if (*str != '-') continue;
969 str++;
970
971 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
972 day1=(str[0]-'0')*10+(str[1]-'0');
973 if (day1<1 || day1>31) continue;
974 str+=2;
975 month1=(str[0]-'0')*10+(str[1]-'0')-1;
976 if (month1<0 || month1>11) continue;
977 str+=2;
978 year1=0;
979 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year1=year1*10+(str[i]-'0');
980 if (i!=4) continue;
981 str+=4;
982
983 if (str[0]!='_') continue;
984 str++;
985
986 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
987 hour1=(str[0]-'0')*10+(str[1]-'0');
988 str+=2;
989 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
990 minute1=(str[0]-'0')*10+(str[1]-'0');
991 str+=2;
992
993 period->start.tm_mday=day0;
994 period->start.tm_mon=month0;
995 period->start.tm_year=year0-1900;
996 period->start.tm_hour=hour0;
997 period->start.tm_min=minute0;
998 period->end.tm_mday=day1;
999 period->end.tm_mon=month1;
1000 period->end.tm_year=year1-1900;
1001 period->end.tm_hour=hour1;
1002 period->end.tm_min=minute1;
1003 return(0);
1004 }
1005 return(-1);
1006 }
1007
1008 void getperiod_fromrange(struct periodstruct *period,int dfrom,int duntil)
1009 {
1010 memset(&period->start,0,sizeof(period->start));
1011 period->start.tm_mday=dfrom%100;
1012 period->start.tm_mon=(dfrom/100)%100-1;
1013 period->start.tm_year=(dfrom/10000)-1900;
1014
1015 memset(&period->end,0,sizeof(period->end));
1016 period->end.tm_mday=duntil%100;
1017 period->end.tm_mon=(duntil/100)%100-1;
1018 period->end.tm_year=(duntil/10000)-1900;
1019 }
1020
1021 /*!
1022 Update the \a main period to encompass the period in \a candidate.
1023 */
1024 void getperiod_merge(struct periodstruct *main,struct periodstruct *candidate)
1025 {
1026 int cdate;
1027 int mdate;
1028
1029 mdate=(main->start.tm_year)*10000+(main->start.tm_mon)*100+main->start.tm_mday;
1030 cdate=(candidate->start.tm_year)*10000+(candidate->start.tm_mon)*100+candidate->start.tm_mday;
1031 if (cdate<mdate) memcpy(&main->start,&candidate->start,sizeof(struct tm));
1032
1033 mdate=(main->end.tm_year)*10000+(main->end.tm_mon)*100+main->end.tm_mday;
1034 cdate=(candidate->end.tm_year)*10000+(candidate->end.tm_mon)*100+candidate->end.tm_mday;
1035 if (cdate>mdate) memcpy(&main->end,&candidate->end,sizeof(struct tm));
1036 }
1037
1038 int getperiod_buildtext(struct periodstruct *period)
1039 {
1040 int i;
1041 int range;
1042 char text1[40], text2[40];
1043
1044 if (df=='u') {
1045 i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
1046 } else if(df=='e') {
1047 i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
1048 } else /*if (df=='w')*/ {
1049 IndexTree=INDEX_TREE_FILE;
1050 i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
1051 }
1052 if (i == 0) return(-1);
1053
1054 range=(period->start.tm_year!=period->end.tm_year ||
1055 period->start.tm_mon!=period->end.tm_mon ||
1056 period->start.tm_mday!=period->end.tm_mday);
1057 if (range) {
1058 if (df=='u') {
1059 i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
1060 } else if (df=='e') {
1061 i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
1062 } else {
1063 i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
1064 }
1065 if (i == 0) return(-1);
1066 }
1067
1068 if (range) {
1069 snprintf(period->text,sizeof(period->text),"%s-%s",text1,text2);
1070 snprintf(period->html,sizeof(period->html),"%s&mdash;%s",text1,text2);
1071 } else {
1072 safe_strcpy(period->text,text1,sizeof(period->text));
1073 safe_strcpy(period->html,text1,sizeof(period->html));
1074 }
1075 return(0);
1076 }
1077
1078 static void copy_images(void)
1079 {
1080 FILE *img_in, *img_ou;
1081 char images[512];
1082 char srcfile[MAXLEN];
1083 char dstfile[MAXLEN];
1084 DIR *dirp;
1085 struct dirent *direntp;
1086 char buffer[MAXLEN];
1087 size_t nread;
1088 struct stat info;
1089
1090 if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
1091 debuga(_("Cannot copy images to target directory %simages\n"),outdir);
1092 exit(EXIT_FAILURE);
1093 }
1094 if (access(images,R_OK)!=0) {
1095 if (PortableMkDir(images,0755)) {
1096 debuga(_("Cannot create directory \"%s\": %s\n"),images,strerror(errno));
1097 exit(EXIT_FAILURE);
1098 }
1099 }
1100
1101 dirp = opendir(ImageDir);
1102 if(dirp==NULL) {
1103 debuga(_("Cannot open directory \"%s\": %s\n"),ImageDir,strerror(errno));
1104 return;
1105 }
1106 while ((direntp = readdir( dirp )) != NULL ){
1107 if(direntp->d_name[0]=='.')
1108 continue;
1109 if (snprintf(srcfile,sizeof(srcfile),"%s/%s",ImageDir,direntp->d_name)>=sizeof(srcfile)) {
1110 debuga(_("Buffer too small to store "));
1111 debuga_more("%s/%s",ImageDir,direntp->d_name);
1112 exit(EXIT_FAILURE);
1113 }
1114 if (stat(srcfile,&info)) {
1115 debuga(_("Cannot stat \"%s\": %s\n"),srcfile,strerror(errno));
1116 continue;
1117 }
1118 if (S_ISREG(info.st_mode)) {
1119 if (snprintf(dstfile,sizeof(dstfile),"%s/%s",images,direntp->d_name)>=sizeof(dstfile)) {
1120 debuga(_("Buffer too small to store "));
1121 debuga_more("%s/%s",images,direntp->d_name);
1122 exit(EXIT_FAILURE);
1123 }
1124 img_in = fopen(srcfile, "rb");
1125 if(img_in!=NULL) {
1126 img_ou = fopen(dstfile, "wb");
1127 if(img_ou!=NULL) {
1128 while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
1129 if (fwrite(buffer,1,nread,img_ou)!=nread) {
1130 debuga(_("Failed to copy image %s to %s\n"),srcfile,dstfile);
1131 break;
1132 }
1133 }
1134 if (fclose(img_ou)==EOF) {
1135 debuga(_("Error while copying image %s: %s\n"),dstfile,strerror(errno));
1136 exit(EXIT_FAILURE);
1137 }
1138 } else
1139 debuga(_("Cannot open file \"%s\": %s\n"), dstfile, strerror(errno));
1140 fclose(img_in);
1141 } else
1142 debuga(_("Cannot open file \"%s\": %s\n"), srcfile, strerror(errno));
1143 }
1144 }
1145 (void) closedir(dirp);
1146
1147 return;
1148 }
1149
1150 /*!
1151 * Check if the proposed file name conforms to the directory structure layed out
1152 * as a file tree. It is used to check if the file name enumerated while scanning
1153 * a directory content may have been created by sarg running with IndexTree set to
1154 * INDEX_TREE_FILE.
1155 */
1156 bool IsTreeFileDirName(const char *Name)
1157 {
1158 char DateFormat;
1159 int i;
1160
1161 // start year (date format u) or start day (date format e)
1162 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1163
1164 if (isdigit(Name[2]) && isdigit(Name[3]))
1165 {
1166 // date format is either u or w
1167 if (Name[4]=='.')
1168 {
1169 // date format is w
1170 if (!isdigit(Name[5]) || !isdigit(Name[6])) return(false);
1171 return(true);//date format w is confirmed
1172 }
1173
1174 // date format is u
1175 Name+=4;
1176
1177 // start month
1178 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1179 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1180 if (i<0) return(false);
1181 Name+=3;
1182
1183 // start day
1184 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1185 Name+=2;
1186
1187 DateFormat='u';
1188 }
1189 else if (isalpha(Name[2]) && isalpha(Name[3]) && isalpha(Name[4]))
1190 {
1191 // date format is e
1192 Name+=2;
1193
1194 // start month
1195 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1196 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1197 if (i<0) return(false);
1198 Name+=3;
1199
1200 // start day
1201 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1202 Name+=4;
1203
1204 DateFormat='e';
1205 }
1206 else
1207 return(false);
1208
1209 if (Name[0]!='-') return(false);
1210 Name++;
1211
1212 if (DateFormat=='u')
1213 {
1214 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1215 Name+=4;
1216
1217 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1218 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1219 if (i<0) return(false);
1220 Name+=3;
1221
1222 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1223 Name+=2;
1224 }
1225 else //DateFormat=='e'
1226 {
1227 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1228 Name+=2;
1229
1230 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1231 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1232 if (i<0) return(false);
1233 Name+=3;
1234
1235 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1236 Name+=4;
1237 }
1238 /*
1239 * The directory name may contains additional characters such as a counter if
1240 * a previous report is never overwritten.
1241 */
1242 return(true);
1243 }
1244
1245 /*!
1246 * Check if the proposed file name can be the year part of a report tree build with
1247 * IndexTree set to INDEX_TREE_DATE.
1248 */
1249 bool IsTreeYearFileName(const char *Name)
1250 {
1251 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1252 Name+=4;
1253 if (Name[0]=='-')
1254 {
1255 Name++;
1256 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1257 Name+=4;
1258 }
1259 if (Name[0]) return(false);
1260 return(true);
1261 }
1262
1263 /*!
1264 * Check if the proposed file name can be the month part of a report tree build with
1265 * IndexTree set to INDEX_TREE_DATE.
1266 */
1267 bool IsTreeMonthFileName(const char *Name)
1268 {
1269 int m;
1270
1271 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1272 m=(Name[0]-'0')*10+(Name[1]-'0');
1273 if (m<1 || m>12) return(false);
1274 Name+=2;
1275 if (Name[0]=='-')
1276 {
1277 Name++;
1278 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1279 m=(Name[0]-'0')*10+(Name[1]-'0');
1280 if (m<1 || m>12) return(false);
1281 Name+=2;
1282 }
1283 if (Name[0]) return(false);
1284 return(true);
1285 }
1286
1287 /*!
1288 * Check if the proposed file name can be the day part of a report tree build with
1289 * IndexTree set to INDEX_TREE_DATE.
1290 */
1291 bool IsTreeDayFileName(const char *Name)
1292 {
1293 int d;
1294
1295 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1296 d=(Name[0]-'0')*10+(Name[1]-'0');
1297 if (d<1 || d>31) return(false);
1298 if (Name[2]=='-')
1299 {
1300 Name+=3;
1301 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1302 d=(Name[0]-'0')*10+(Name[1]-'0');
1303 if (d<1 || d>31) return(false);
1304 }
1305 /*
1306 * The directory name may contains additional characters such as a counter if
1307 * a previous report is never overwritten.
1308 */
1309 return(true);
1310 }
1311
1312 int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form)
1313 {
1314 FILE *fp_ou;
1315 int num=1, count=0;
1316 char wdir[MAXLEN];
1317 char dirname2[MAXLEN];
1318 int y1, y2;
1319 int m1, m2;
1320 int d1, d2;
1321 int wlen, wlen2;
1322 time_t curtime;
1323 struct tm *loctm;
1324
1325 strcpy(wdir,outdir);
1326 wlen=strlen(wdir);
1327 y1=per1->start.tm_year+1900;
1328 y2=per1->end.tm_year+1900;
1329 m1=per1->start.tm_mon+1;
1330 m2=per1->end.tm_mon+1;
1331 d1=per1->start.tm_mday;
1332 d2=per1->end.tm_mday;
1333 if(IndexTree == INDEX_TREE_DATE) {
1334 wlen+=sprintf(wdir+wlen,"%04d",y1);
1335 if(y1!=y2) wlen+=sprintf(wdir+wlen,"-%04d",y2);
1336 if(access(wdir, R_OK) != 0)
1337 my_mkdir(wdir);
1338
1339 wlen+=sprintf(wdir+wlen,"/%02d",m1);
1340 if(m1 != m2) wlen+=sprintf(wdir+wlen,"-%02d",m2);
1341 if(access(wdir, R_OK) != 0)
1342 my_mkdir(wdir);
1343
1344 wlen+=sprintf(wdir+wlen,"/%02d",d1);
1345 if(d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
1346 } else {
1347 if (df == 'u') {
1348 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
1349 conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
1350 } else if (df == 'e') {
1351 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
1352 conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
1353 } else if (df == 'w') {
1354 wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
1355 if (wlen2==0) return(-1);
1356 wlen+=wlen2;
1357 }
1358 }
1359
1360 if(us[0] != '\0') {
1361 struct userinfostruct *uinfo=userinfo_find_from_id(us);
1362 if (uinfo) {
1363 strcat(wdir,"-");
1364 strcat(wdir,uinfo->filename);
1365 }
1366 }
1367 if(addr[0] != '\0') {
1368 strcat(wdir,"-");
1369 strcat(wdir,addr);
1370 }
1371 if(site[0] != '\0') {
1372 strcat(wdir,"-");
1373 strcat(wdir,site);
1374 }
1375
1376 strcpy(outdirname,wdir);
1377
1378 if(IndexTree != INDEX_TREE_DATE) {
1379 if(!OverwriteReport) {
1380 while(num) {
1381 if(access(wdir,R_OK) == 0) {
1382 sprintf(wdir,"%s.%d",outdirname,num);
1383 num++;
1384 count++;
1385 } else
1386 break;
1387 }
1388
1389 if(count > 0) {
1390 if(debug)
1391 debuga(_("File %s already exists, moved to %s\n"),outdirname,wdir);
1392 rename(outdirname,wdir);
1393 }
1394 } else {
1395 if(access(outdirname,R_OK) == 0) {
1396 unlinkdir(outdirname,1);
1397 }
1398 }
1399 my_mkdir(outdirname);
1400 } else {
1401 strcpy(dirname2,wdir);
1402 if(!OverwriteReport) {
1403 while(num) {
1404 if(access(wdir,R_OK) == 0) {
1405 sprintf(wdir,"%s.%d",dirname2,num);
1406 num++;
1407 count++;
1408 } else
1409 break;
1410 }
1411
1412 if(count > 0) {
1413 if(debug)
1414 debuga(_("File %s already exists, moved to %s\n"),dirname2,wdir);
1415 rename(dirname2,wdir);
1416 strcpy(dirname2,wdir);
1417 }
1418 } else {
1419 if(access(wdir,R_OK) == 0) {
1420 unlinkdir(wdir,1);
1421 }
1422 }
1423
1424 if(access(wdir, R_OK) != 0)
1425 my_mkdir(wdir);
1426 }
1427
1428 strcpy(dirname2,wdir);
1429
1430 if (snprintf(wdir,sizeof(wdir),"%s/sarg-date",outdirname)>=sizeof(wdir)) {
1431 debuga(_("Buffer too small to store "));
1432 debuga_more("%s/sarg-date",outdirname);
1433 exit(EXIT_FAILURE);
1434 }
1435 if ((fp_ou = fopen(wdir, "wt")) == 0) {
1436 debuga(_("cannot open %s for writing: %s\n"),wdir,strerror(errno));
1437 perror("SARG:");
1438 exit(EXIT_FAILURE);
1439 }
1440 time(&curtime);
1441 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1442 loctm=localtime(&curtime);
1443 strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
1444 if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
1445 debuga(_("Failed to write the date in %s\n"),wdir);
1446 perror("SARG:");
1447 exit(EXIT_FAILURE);
1448 }
1449 if (fclose(fp_ou)==EOF) {
1450 debuga(_("Failed to write the date in %s: %s\n"),wdir,strerror(errno));
1451 exit(EXIT_FAILURE);
1452 }
1453
1454 copy_images();
1455 return(0);
1456 }
1457
1458 /*!
1459 Copy a string without overflowing the buffer. The copied string
1460 is properly terminated by an ASCII zero.
1461
1462 \param dest The destination buffer.
1463 \param src The source buffer.
1464 \param length The size of the destination buffer. The program is aborted
1465 if the length is negative or zero.
1466 */
1467 void safe_strcpy(char *dest,const char *src,int length)
1468 {
1469 if (length<=0) {
1470 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1471 exit(EXIT_FAILURE);
1472 }
1473 strncpy(dest,src,length-1);
1474 dest[length-1]='\0';
1475 }
1476
1477 void strip_latin(char *line)
1478 {
1479 int i,j;
1480 int skip;
1481
1482 j=0;
1483 skip=0;
1484 for (i=0;line[i];i++){
1485 if (skip){
1486 if (line[i]==';') skip=0;
1487 } else {
1488 if (line[i]=='&')
1489 skip=1;
1490 else
1491 line[j++]=line[i];
1492 }
1493 }
1494 line[j]='\0';
1495 return;
1496 }
1497
1498 void zdate(char *ftime,int ftimesize, char DateFormat)
1499 {
1500 time_t t;
1501 struct tm *local;
1502
1503 t = time(NULL);
1504 local = localtime(&t);
1505 if (DateFormat=='u')
1506 strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
1507 else if (DateFormat=='e')
1508 strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
1509 else if (DateFormat=='w')
1510 strftime(ftime, ftimesize, "%W-%H-%M", local);
1511 return;
1512 }
1513
1514
1515 char *fixtime(long long int elap)
1516 {
1517 long int num = elap / 1000LL;
1518 int hor = 0;
1519 int min = 0;
1520 int sec = 0;
1521 static char buf[20];
1522
1523 hor=num / 3600L;
1524 min=(num % 3600L) / 60L;
1525 sec=num % 60L;
1526
1527 if(hor==0 && min==0 && sec==0)
1528 strcpy(buf,"0");
1529 else
1530 snprintf(buf,sizeof(buf),"%d:%02d:%02d",hor,min,sec);
1531
1532 return buf;
1533 }
1534
1535
1536 void date_from(char *date,int date_size, int *dfrom, int *duntil)
1537 {
1538 int d0=0;
1539 int m0=0;
1540 int y0=0;
1541 int d1=0;
1542 int m1=0;
1543 int y1=0;
1544
1545 if (isdigit(date[0])) {
1546 int next=-1;
1547
1548 if (sscanf(date,"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
1549 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1550 exit(EXIT_FAILURE);
1551 }
1552 if (date[next]=='-') {
1553 if (sscanf(date+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
1554 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1555 exit(EXIT_FAILURE);
1556 }
1557 } else if (date[next]!='\0') {
1558 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1559 exit(EXIT_FAILURE);
1560 } else {
1561 d1=d0;
1562 m1=m0;
1563 y1=y0;
1564 }
1565 } else {
1566 int i;
1567 time_t Today,t1;
1568 struct tm *Date0,Date1;
1569
1570 if (time(&Today)==(time_t)-1) {
1571 debuga(_("Failed to get the current time\n"));
1572 exit(EXIT_FAILURE);
1573 }
1574 if (sscanf(date,"day-%d",&i)==1) {
1575 if (i<0) {
1576 debuga(_("Invalid number of days in -d parameter\n"));
1577 exit(EXIT_FAILURE);
1578 }
1579 Today-=i*24*60*60;
1580 Date0=localtime(&Today);
1581 if (Date0==NULL) {
1582 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1583 exit(EXIT_FAILURE);
1584 }
1585 y0=y1=Date0->tm_year+1900;
1586 m0=m1=Date0->tm_mon+1;
1587 d0=d1=Date0->tm_mday;
1588 } else if (sscanf(date,"week-%d",&i)==1) {
1589 /*
1590 There is no portable way to find the first day of the week even though the
1591 information is available in the locale. nl_langinfo has the unofficial
1592 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1593 undocumented as is their return value and it is discouraged to use them.
1594 Beside, nl_langinfo isn't available on windows and the first day of the
1595 week isn't available at all on that system.
1596 */
1597 const int FirstWeekDay=1;
1598 time_t WeekBegin;
1599
1600 if (i<0) {
1601 debuga(_("Invalid number of weeks in -d parameter\n"));
1602 exit(EXIT_FAILURE);
1603 }
1604 Date0=localtime(&Today);
1605 if (Date0==NULL) {
1606 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1607 exit(EXIT_FAILURE);
1608 }
1609 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1610 WeekBegin-=i*7*24*60*60;
1611 Date0=localtime(&WeekBegin);
1612 if (Date0==NULL) {
1613 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1614 exit(EXIT_FAILURE);
1615 }
1616 y0=Date0->tm_year+1900;
1617 m0=Date0->tm_mon+1;
1618 d0=Date0->tm_mday;
1619 WeekBegin+=6*24*60*60;
1620 Date0=localtime(&WeekBegin);
1621 if (Date0==NULL) {
1622 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1623 exit(EXIT_FAILURE);
1624 }
1625 y1=Date0->tm_year+1900;
1626 m1=Date0->tm_mon+1;
1627 d1=Date0->tm_mday;
1628 } else if (sscanf(date,"month-%d",&i)==1) {
1629 if (i<0) {
1630 debuga(_("Invalid number of months in -d parameter\n"));
1631 exit(EXIT_FAILURE);
1632 }
1633 Date0=localtime(&Today);
1634 if (Date0==NULL) {
1635 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1636 exit(EXIT_FAILURE);
1637 }
1638 if (Date0->tm_mon<i%12) {
1639 y0=Date0->tm_year+1900-i/12-1;
1640 m0=(Date0->tm_mon+12-i%12)%12+1;
1641 d0=1;
1642 } else {
1643 y0=Date0->tm_year+1900-i/12;
1644 m0=Date0->tm_mon-i%12+1;
1645 d0=1;
1646 }
1647 memcpy(&Date1,Date0,sizeof(struct tm));
1648 Date1.tm_isdst=-1;
1649 Date1.tm_mday=1;
1650 if (m0<12) {
1651 Date1.tm_mon=m0;
1652 Date1.tm_year=y0-1900;
1653 } else {
1654 Date1.tm_mon=0;
1655 Date1.tm_year=y0-1900+1;
1656 }
1657 t1=mktime(&Date1);
1658 t1-=24*60*60;
1659 Date0=localtime(&t1);
1660 y1=Date0->tm_year+1900;
1661 m1=Date0->tm_mon+1;
1662 d1=Date0->tm_mday;
1663 } else {
1664 debuga(_("Invalid date range passed on command line\n"));
1665 exit(EXIT_FAILURE);
1666 }
1667 }
1668
1669 *dfrom=y0*10000+m0*100+d0;
1670 *duntil=y1*10000+m1*100+d1;
1671 snprintf(date,date_size,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
1672 return;
1673 }
1674
1675
1676 char *strlow(char *string)
1677 {
1678 char *s;
1679
1680 if (string)
1681 {
1682 for (s = string; *s; ++s)
1683 *s = tolower(*s);
1684 }
1685
1686 return string;
1687 }
1688
1689
1690
1691
1692 char *strup(char *string)
1693 {
1694 char *s;
1695
1696 if (string)
1697 {
1698 for (s = string; *s; ++s)
1699 *s = toupper(*s);
1700 }
1701
1702 return string;
1703 }
1704
1705
1706 void removetmp(const char *outdir)
1707 {
1708 FILE *fp_gen;
1709 char filename[256];
1710
1711 if(!RemoveTempFiles)
1712 return;
1713
1714 if(debug) {
1715 debuga(_("Purging temporary file sarg-general\n"));
1716 }
1717 if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
1718 debuga(_("Path too long: "));
1719 debuga_more("%s/sarg-period\n",outdir);
1720 exit(EXIT_FAILURE);
1721 }
1722 if((fp_gen=fopen(filename,"w"))==NULL){
1723 debuga(_("Cannot open file \"%s\": %s\n"),filename,strerror(errno));
1724 exit(EXIT_FAILURE);
1725 }
1726 totalger(fp_gen,filename);
1727 if (fclose(fp_gen)==EOF) {
1728 debuga(_("Failed to close %s after writing the total line: %s\n"),filename,strerror(errno));
1729 exit(EXIT_FAILURE);
1730 }
1731 }
1732
1733 void load_excludecodes(const char *ExcludeCodes)
1734 {
1735 FILE *fp_in;
1736 char data[80];
1737 int i;
1738 int Stored;
1739 long int MemSize;
1740
1741 if(ExcludeCodes[0] == '\0')
1742 return;
1743
1744 if((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
1745 debuga(_("Cannot open file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
1746 exit(EXIT_FAILURE);
1747 }
1748
1749 if (fseek(fp_in, 0, SEEK_END)==-1) {
1750 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1751 exit(EXIT_FAILURE);
1752 }
1753 MemSize = ftell(fp_in);
1754 if (MemSize<0) {
1755 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes);
1756 exit(EXIT_FAILURE);
1757 }
1758 if (fseek(fp_in, 0, SEEK_SET)==-1) {
1759 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1760 exit(EXIT_FAILURE);
1761 }
1762
1763 MemSize+=1;
1764 if((excludecode=(char *) malloc(MemSize))==NULL) {
1765 debuga(_("malloc error (%ld bytes required)\n"),MemSize);
1766 exit(EXIT_FAILURE);
1767 }
1768 memset(excludecode,0,MemSize);
1769
1770 Stored=0;
1771 while(fgets(data,sizeof(data),fp_in)!=NULL) {
1772 if (data[0]=='#') continue;
1773 for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
1774 if (i<0) continue;
1775 if (Stored+i+2>=MemSize) {
1776 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes);
1777 break;
1778 }
1779 strcat(excludecode,data);
1780 strcat(excludecode,";");
1781 Stored+=i+1;
1782 }
1783
1784 fclose(fp_in);
1785 return;
1786 }
1787
1788 void free_excludecodes(void)
1789 {
1790 if (excludecode) {
1791 free(excludecode);
1792 excludecode=NULL;
1793 }
1794 }
1795
1796 int vercode(const char *code)
1797 {
1798 char *cod;
1799 int clen;
1800
1801 if (excludecode && excludecode[0]!='\0') {
1802 clen=strlen(code);
1803 cod=excludecode;
1804 while (cod) {
1805 if (strncmp(code,cod,clen)==0 && cod[clen]==';')
1806 return 1;
1807 cod=strchr(cod,';');
1808 if (cod) cod++;
1809 }
1810 }
1811 return 0;
1812 }
1813
1814 void fixnone(char *str)
1815 {
1816 int i;
1817
1818 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--);
1819 if(i==3 && strncmp(str,"none",4) == 0)
1820 str[0]='\0';
1821
1822 return;
1823 }
1824
1825 void fixendofline(char *str)
1826 {
1827 int i;
1828
1829 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--) str[i]=0;
1830 }
1831
1832 #ifdef LEGACY_TESTVALIDUSERCHAR
1833 int testvaliduserchar(const char *user)
1834 {
1835 int x=0;
1836 int y=0;
1837
1838 for (y=0; y<strlen(UserInvalidChar); y++) {
1839 for (x=0; x<strlen(user); x++) {
1840 if(user[x] == UserInvalidChar[y])
1841 return 1;
1842 }
1843 }
1844 return 0;
1845 }
1846 #else
1847 int testvaliduserchar(const char *user)
1848 {
1849 char * p_UserInvalidChar = UserInvalidChar ;
1850 const char * p_user ;
1851
1852 while( *p_UserInvalidChar ) {
1853 p_user = user ;
1854 while ( *p_user ) {
1855 if( *p_UserInvalidChar == *p_user )
1856 return 1;
1857 p_user++ ;
1858 }
1859 p_UserInvalidChar++ ;
1860 }
1861 return 0;
1862 }
1863 #endif
1864
1865 int compar( const void *a, const void *b )
1866 {
1867 if( *(int *)a > *(int *)b ) return 1;
1868 if( *(int *)a < *(int *)b ) return -1;
1869 return 0;
1870 }
1871
1872 int getnumlist( char *buf, numlist *list, const int len, const int maxvalue )
1873 {
1874 int i, j, d, flag, r1, r2;
1875 char *pbuf, **bp, *strbufs[ 24 ];
1876
1877 bp = strbufs;
1878 strtok( buf, " \t" );
1879 for( *bp = strtok( NULL, "," ), list->len = 0; *bp; *bp = strtok( NULL, "," ) ) {
1880 if( ++bp >= &strbufs[ 24 ] )
1881 break;
1882 list->len++;
1883 }
1884 if( ! list->len )
1885 return -1;
1886 d = 0;
1887 for( i = 0; i < list->len; i++ ) {
1888 if( strchr( strbufs[ i ], '-' ) != 0 ) {
1889 pbuf = strbufs[ i ];
1890 strtok( pbuf, "-" );
1891 pbuf = strtok( NULL, "\0" );
1892 r1 = atoi( strbufs[ i ] );
1893 if( ( r2 = atoi( pbuf ) ) >= maxvalue || r1 >= r2 )
1894 return -1;
1895 if( i + d + ( r2 - r1 ) + 1 <= len ) {
1896 for( j = r1; j <= r2; j++ )
1897 list->list[ i + d++ ] = j;
1898 d--;
1899 }
1900 }
1901 else
1902 if( ( list->list[ i + d ] = atoi( strbufs[ i ] ) ) >= maxvalue )
1903 return 1;
1904 }
1905 list->len += d;
1906 qsort( list->list, list->len, sizeof( int ), compar );
1907 do {
1908 flag = 0;
1909 for( i = 0; i < list->len - 1; i++ )
1910 if( list->list[ i ] == list->list[ i + 1 ] ) {
1911 for( j = i + 1; j < list->len; j++ )
1912 list->list[ j - 1 ] = list->list[ j ];
1913 list->len--;
1914 flag = 1;
1915 break;
1916 }
1917 } while( flag );
1918 return 0;
1919 }
1920
1921 void show_info(FILE *fp_ou)
1922 {
1923 char ftime[127];
1924
1925 if(!ShowSargInfo) return;
1926 zdate(ftime, sizeof(ftime), df);
1927 fputs("<div class=\"info\">",fp_ou);
1928 fprintf(fp_ou,_("Generated by <a href='%s'>%s-%s</a> on %s"),URL,PGM,VERSION,ftime);
1929 fputs("</div>\n",fp_ou);
1930 }
1931
1932 void show_sarg(FILE *fp_ou, int depth)
1933 {
1934 int i;
1935
1936 if(!ShowSargLogo) return;
1937 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
1938 for (i=0 ; i<depth ; i++)
1939 fputs("../",fp_ou);
1940 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);
1941 }
1942
1943 void write_logo_image(FILE *fp_ou)
1944 {
1945 if(LogoImage[0]!='\0')
1946 fprintf(fp_ou, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\">&nbsp;%s</div>\n",LogoImage,Width,Height,LogoText);
1947 }
1948
1949 void write_html_head(FILE *fp_ou, int depth, const char *page_title,int javascript)
1950 {
1951 int i;
1952
1953 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
1954 fprintf(fp_ou, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
1955 if (page_title) fprintf(fp_ou,"<title>%s</title>\n",page_title);
1956 css(fp_ou);
1957 if ((javascript & HTML_JS_SORTTABLE)!=0 && SortTableJs[0]) {
1958 fputs("<script type=\"text/javascript\" src=\"",fp_ou);
1959 if (strncmp(SortTableJs,"../",3)==0) {
1960 for (i=0 ; i<depth ; i++) fputs("../",fp_ou);
1961 }
1962 fputs(SortTableJs,fp_ou);
1963 fputs("\"></script>\n",fp_ou);
1964 }
1965 fputs("</head>\n<body>\n",fp_ou);
1966 }
1967
1968 void write_html_header(FILE *fp_ou, int depth, const char *page_title,int javascript)
1969 {
1970 write_html_head(fp_ou,depth,page_title,javascript);
1971 write_logo_image(fp_ou);
1972 show_sarg(fp_ou, depth);
1973 fprintf(fp_ou,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title);
1974 }
1975
1976 void close_html_header(FILE *fp_ou)
1977 {
1978 fputs("</table></div>\n",fp_ou);
1979 }
1980
1981 void write_html_trailer(FILE *fp_ou)
1982 {
1983 show_info(fp_ou);
1984 fputs("</body>\n</html>\n",fp_ou);
1985 }
1986
1987 void output_html_string(FILE *fp_ou,const char *str,int maxlen)
1988 {
1989 int i=0;
1990
1991 while (*str && (maxlen<=0 || i<maxlen)) {
1992 switch (*str) {
1993 case '&':
1994 fputs("&amp;",fp_ou);
1995 break;
1996 case '<':
1997 fputs("&lt;",fp_ou);
1998 break;
1999 case '>':
2000 fputs("&gt;",fp_ou);
2001 break;
2002 case '"':
2003 fputs("&quot;",fp_ou);
2004 break;
2005 case '\'':
2006 fputs("&#39;",fp_ou);
2007 break;
2008 default:
2009 fputc(*str,fp_ou);
2010 }
2011 str++;
2012 i++;
2013 }
2014 if (maxlen>0 && i>=maxlen)
2015 fputs("&hellip;",fp_ou);
2016 }
2017
2018 void output_html_url(FILE *fp_ou,const char *url)
2019 {
2020 while (*url) {
2021 if (*url=='&')
2022 fputs("&amp;",fp_ou);
2023 else
2024 fputc(*url,fp_ou);
2025 url++;
2026 }
2027 }
2028
2029 /*!
2030 Write a host name inside an A tag of a HTML file. If the host name starts
2031 with a star, it is assumed to be an alias that cannot be put inside a link
2032 so the A tag is not written around the host name.
2033
2034 \param fp_ou The handle of the HTML file.
2035 \param url The host to display in the HTML file.
2036 \param maxlen The maximum number of characters to print into the host name.
2037 */
2038 void output_html_link(FILE *fp_ou,const char *url,int maxlen)
2039 {
2040 if (url[0]==ALIAS_PREFIX) {
2041 // this is an alias, no need for a A tag
2042 output_html_string(fp_ou,url+1,100);
2043 } else {
2044 if (skip_scheme(url)==url)
2045 fputs("<a href=\"http://",fp_ou);//no scheme in the url, assume http:// to make the link clickable
2046 else
2047 fputs("<a href=\"",fp_ou);//the scheme is in the url, no need to add one
2048 output_html_url(fp_ou,url);
2049 fputs("\">",fp_ou);
2050 output_html_string(fp_ou,url,100);
2051 fputs("</a>",fp_ou);
2052 }
2053 }
2054
2055 void url_module(const char *url, char *w2)
2056 {
2057 int x, y;
2058 char w[255];
2059
2060 y=0;
2061 for(x=strlen(url)-1; x>=0; x--) {
2062 if(url[x] == '/' || y>=sizeof(w)-1) break;
2063 w[y++]=url[x];
2064 }
2065 if (x<0) {
2066 w2[0]='\0';
2067 return;
2068 }
2069
2070 x=0;
2071 for(y=y-1; y>=0; y--) {
2072 w2[x++]=w[y];
2073 }
2074 w2[x]='\0';
2075 }
2076
2077 /*!
2078 Mangle an URL to produce a part that can be used as an anchor in
2079 a html <a name=""> tag.
2080
2081 \param url The URL to mangle.
2082 \param anchor The buffer to write the mangled URL.
2083 \param size The size of the buffer.
2084 */
2085 void url_to_anchor(const char *url,char *anchor,int size)
2086 {
2087 int i,j;
2088 bool skip;
2089
2090 // find url end
2091 for (i=0 ; url[i] && url[i]!='/' && url[i]!='?' ; i++);
2092 i--;
2093 if (i<=0) {
2094 anchor[0]='\0';
2095 return;
2096 }
2097
2098 // only keep really safe characters
2099 skip=false;
2100 j=size-1;
2101 anchor[j]='\0';
2102 while (j>0 && i>=0)
2103 {
2104 if(isalnum(url[i]) || url[i]=='-' || url[i]=='_' || url[i]=='.') {
2105 anchor[--j]=url[i];
2106 skip=false;
2107 } else {
2108 if (!skip) anchor[--j]='_';
2109 skip=true;
2110 }
2111 i--;
2112 }
2113 if (j>0)
2114 {
2115 while ( anchor[j])
2116 {
2117 *anchor=anchor[j];
2118 anchor++;
2119 }
2120 *anchor='\0';
2121 }
2122 }
2123
2124 void version(void)
2125 {
2126 printf(_("SARG Version: %s\n"),VERSION);
2127 #if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
2128 if (debug) {
2129 printf(_("\nFor the translation to work, a valid message file should be installed as "
2130 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR,PACKAGE_NAME);
2131 if (CurrentLocale) {
2132 printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale);
2133 } else {
2134 printf(_("Locale is not set in the environment variable.\n"));
2135 }
2136 // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
2137 printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
2138 }
2139 #endif
2140 exit(EXIT_SUCCESS);
2141 }
2142
2143 char *get_param_value(const char *param,char *line)
2144 {
2145 int plen;
2146
2147 while (*line==' ' || *line=='\t') line++;
2148 plen=strlen(param);
2149 if (strncasecmp(line,param,plen)) return(NULL);
2150 if (line[plen]!=' ' && line[plen]!='\t') return(NULL);
2151 line+=plen;
2152 while (*line==' ' || *line=='\t') line++;
2153 return(line);
2154 }
2155
2156 void unlinkdir(const char *dir,bool contentonly)
2157 {
2158 struct stat st;
2159 DIR *dirp;
2160 struct dirent *direntp;
2161 char dname[MAXLEN];
2162 int err;
2163
2164 dirp=opendir(dir);
2165 if (!dirp) return;
2166 while ((direntp = readdir(dirp)) != NULL) {
2167 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2168 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2169 continue;
2170 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2171 debuga(_("Path too long: "));
2172 debuga_more("%s/%s\n",dir,direntp->d_name);
2173 exit(EXIT_FAILURE);
2174 }
2175 #ifdef HAVE_LSTAT
2176 err=lstat(dname,&st);
2177 #else
2178 err=stat(dname,&st);
2179 #endif
2180 if (err) {
2181 debuga(_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2182 exit(EXIT_FAILURE);
2183 }
2184 if (S_ISREG(st.st_mode)) {
2185 if (unlink(dname)) {
2186 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2187 exit(EXIT_FAILURE);
2188 }
2189 } else if (S_ISDIR(st.st_mode)) {
2190 unlinkdir(dname,0);
2191 } else {
2192 debuga(_("Unknown path type %s\n"),dname);
2193 }
2194 }
2195 closedir(dirp);
2196
2197 if (!contentonly) {
2198 if (rmdir(dir)) {
2199 debuga(_("Cannot delete \"%s\": %s\n"),dir,strerror(errno));
2200 exit(EXIT_FAILURE);
2201 }
2202 }
2203 }
2204
2205 /*!
2206 Delete every file from the temporary directory where sarg is told to store its
2207 temporary files.
2208
2209 As any stray file left over by a previous run would be included in the report, we
2210 must delete every file from the temporary directory before we start processing the logs.
2211
2212 But the temporary directory is given by the user either in the configuration file or
2213 on the command line. We check that the user didn't give a wrong directory by looking
2214 at the files stored in the directory. If a single file is not one of ours, we abort.
2215
2216 \param dir The temporary directory to purge.
2217 */
2218 void emptytmpdir(const char *dir)
2219 {
2220 struct stat st;
2221 DIR *dirp;
2222 struct dirent *direntp;
2223 int dlen;
2224 int elen;
2225 char dname[MAXLEN];
2226 int err;
2227 int i;
2228 static const char *TmpExt[]=
2229 {
2230 ".int_unsort",
2231 ".int_log",
2232 ".day",
2233 "htmlrel.txt",
2234 ".user_unsort",
2235 ".user_log",
2236 ".utmp",
2237 ".ip",
2238 "lastlog1",
2239 "lastlog"
2240 };
2241
2242 dirp=opendir(dir);
2243 if (!dirp) return;
2244
2245 // make sure the temporary directory contains only our files
2246 while ((direntp = readdir(dirp)) != NULL) {
2247 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2248 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2249 continue;
2250
2251 // is it one of our files
2252 dlen=strlen(direntp->d_name);
2253 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2254 elen=strlen(TmpExt[i]);
2255 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2256 }
2257 if (i<0) {
2258 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2259 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2260 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2261 exit(EXIT_FAILURE);
2262 }
2263
2264 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2265 debuga(_("Path too long: "));
2266 debuga_more("%s/%s\n",dir,direntp->d_name);
2267 exit(EXIT_FAILURE);
2268 }
2269
2270 #ifdef HAVE_LSTAT
2271 err=lstat(dname,&st);
2272 #else
2273 err=stat(dname,&st);
2274 #endif
2275 if (err) {
2276 debuga(_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2277 exit(EXIT_FAILURE);
2278 }
2279 if (S_ISDIR(st.st_mode)) {
2280 unlinkdir(dname,0);
2281 } else if (!S_ISREG(st.st_mode)) {
2282 debuga(_("Unknown path type for \"%s\". Check temporary directory\n"),dname);
2283 exit(EXIT_FAILURE);
2284 }
2285 }
2286 rewinddir(dirp);
2287
2288 // now delete our files
2289 while ((direntp = readdir(dirp)) != NULL) {
2290 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2291 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2292 continue;
2293
2294 // is it one of our files
2295 dlen=strlen(direntp->d_name);
2296 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2297 elen=strlen(TmpExt[i]);
2298 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2299 }
2300 if (i<0) {
2301 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2302 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2303 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2304 exit(EXIT_FAILURE);
2305 }
2306
2307 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2308 debuga(_("Path too long: "));
2309 debuga_more("%s/%s\n",dir,direntp->d_name);
2310 exit(EXIT_FAILURE);
2311 }
2312 #ifdef HAVE_LSTAT
2313 err=lstat(dname,&st);
2314 #else
2315 err=stat(dname,&st);
2316 #endif
2317 if (err) {
2318 debuga(_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
2319 exit(EXIT_FAILURE);
2320 }
2321 if (S_ISREG(st.st_mode)) {
2322 if (unlink(dname)) {
2323 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2324 exit(EXIT_FAILURE);
2325 }
2326 } else {
2327 debuga(_("Unknown path type %s\n"),dname);
2328 }
2329 }
2330 closedir(dirp);
2331 }
2332
2333 /*!
2334 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2335 prefix size.
2336
2337 \param buf The buffer to parse.
2338 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
2339 The pointer may be NULL.
2340 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2341 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2342 \param nbits The number of prefix bits for an IP address.
2343 \param next The content of the line after the extracted address.
2344
2345 \retval 3 The pattern is a IPv6 address.
2346 \retval 2 The pattern is a IPv4 address.
2347 \retval 1 The patter is a string.
2348 \retval 0 Empty pattern.
2349 */
2350 int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next)
2351 {
2352 int i;
2353 int j;
2354 int ip_size;
2355 unsigned int value4, value6;
2356 unsigned short int addr[8];
2357 int addr_len;
2358 int nibble6_len;
2359 int mask, max_mask;
2360 int pad_pos;
2361 int pad_len;
2362 bool bracket=false;
2363 bool port=false;
2364 bool port_num=0;
2365
2366 // skip leading spaces and tabs
2367 while (*buf && (*buf==' ' || *buf=='\t')) buf++;
2368
2369 // find out the nature of the pattern
2370 ip_size=0x60 | 0x04;
2371 if (*buf=='[') {
2372 bracket=true;
2373 ip_size=0x60;
2374 buf++;
2375 }
2376 value4=0U;
2377 value6=0U;
2378 addr_len=0;
2379 nibble6_len=0;
2380 pad_pos=-1;
2381 for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
2382 if (ip_size & 0x04) {
2383 if (isdigit(buf[i])) {
2384 if (port) {
2385 port_num=port_num*10+(buf[i]-'0');
2386 if (port_num>65535) ip_size&=~0x04;
2387 } else {
2388 value4=value4*10+(buf[i]-'0');
2389 if (value4>0xFFU) ip_size&=~0x04;
2390 }
2391 } else if (buf[i]=='.' && addr_len<4) {
2392 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2393 value4=0U;
2394 } else if (!port && buf[i]==':') {
2395 port=true;
2396 } else {
2397 ip_size&=~0x04;
2398 }
2399 }
2400 if (ip_size & 0x60) {
2401 if (isdigit(buf[i])) {
2402 value6=(value6<<4)+(buf[i]-'0');
2403 nibble6_len++;
2404 if (value6>0xFFFFU) ip_size&=~0x60;
2405 } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') {
2406 value6=(value6<<4)+(toupper(buf[i])-'A'+10);
2407 nibble6_len++;
2408 if (value6>0xFFFFU) ip_size&=~0x60;
2409 } else if (buf[i]==':' && addr_len<8) {
2410 if (nibble6_len>0) {
2411 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2412 nibble6_len=0;
2413 }
2414 value6=0U;
2415 if (buf[i+1]==':') {
2416 pad_pos=addr_len;
2417 i++;
2418 }
2419 } else {
2420 ip_size&=~0x60;
2421 }
2422 }
2423 }
2424 if (i==0) return(0);
2425 if (ip_size & 0x04) {
2426 if (addr_len!=3)
2427 ip_size&=~0x04;
2428 else
2429 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2430 }
2431 if (ip_size & 0x60) {
2432 if (pad_pos<0 && addr_len!=7) {
2433 ip_size&=~0x60;
2434 } else if (pad_pos>=0 && addr_len>=7)
2435 ip_size&=~0x60;
2436 else if (nibble6_len>0)
2437 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2438 }
2439 if (!ip_size) {
2440 if (text) {
2441 *text=buf;
2442 if (bracket) (*text)--;
2443 }
2444 while ((unsigned char)buf[i]>' ') i++;
2445 if (next) *next=buf+i;
2446 return(1);
2447 }
2448 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
2449 if (buf[i]=='/') {
2450 i++;
2451 mask=atoi(buf+i);
2452 while (isdigit(buf[i])) i++;
2453 if (mask<0 || mask>max_mask) mask=max_mask;
2454 } else
2455 mask=max_mask;
2456 if (ip_size & 0x60 && bracket && buf[i]==']') i++;
2457 if (next) *next=buf+i;
2458 if (ip_size & 0x04) {
2459 if (nbits) *nbits=mask;
2460 for (i=0 ; i<addr_len ; i++)
2461 ipv4[i]=(unsigned char)addr[i];
2462 return(2);
2463 }
2464
2465 // IPv6 address
2466 if (nbits) *nbits=mask;
2467 i=0;
2468 j=0;
2469 if (pad_pos>=0) {
2470 while (i<pad_pos)
2471 ipv6[j++]=(unsigned short int)addr[i++];
2472 pad_len=8-addr_len;
2473 while (j<pad_pos+pad_len)
2474 ipv6[j++]=0;
2475 }
2476 while (i<addr_len)
2477 ipv6[j++]=(unsigned short int)addr[i++];
2478 return(3);
2479 }