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