]> git.ipfire.org Git - thirdparty/sarg.git/blame - util.c
Work around a bug in mingw's snprintf
[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
32e71fa4 501void buildymd(const char *dia, const char *mes, const char *ano, char *wdata)
25697a35 502{
9bd92830 503 int nmes;
25697a35 504
9bd92830
FM
505 nmes=month2num(mes);
506 sprintf(wdata,"%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
FM
604 strcpy(abbrev,num);
605 else if(numlen == 4 || numlen == 7 || numlen == 10 || numlen == 13) {
606 memcpy(abbrev,num,1);
607 abbrev[1]='.';
608 strncpy(abbrev+2,num+1,2);
609 abbrev[4]='\0';
9bd92830
FM
610 if(!n) return(abbrev);
611 if(numlen == 4)
d5a8da9d 612 strcat(abbrev,"K");
9bd92830 613 else if(numlen == 7)
d5a8da9d 614 strcat(abbrev,"M");
9bd92830 615 else if(numlen == 10)
d5a8da9d 616 strcat(abbrev,"G");
9bd92830 617 else if(numlen == 13)
d5a8da9d 618 strcat(abbrev,"T");
9bd92830 619 }
d5a8da9d
FM
620 else if(numlen == 5 || numlen == 8 || numlen == 11 || numlen == 14) {
621 memcpy(abbrev,num,2);
622 abbrev[2]='.';
623 strncpy(abbrev+3,num+2,2);
624 abbrev[5]='\0';
9bd92830
FM
625 if(!n) return(abbrev);
626 if(numlen == 5)
d5a8da9d 627 strcat(abbrev,"K");
9bd92830 628 else if(numlen == 8)
d5a8da9d 629 strcat(abbrev,"M");
9bd92830 630 else if(numlen == 11)
d5a8da9d 631 strcat(abbrev,"G");
9bd92830 632 else if(numlen == 14)
d5a8da9d 633 strcat(abbrev,"T");
9bd92830 634 }
d5a8da9d
FM
635 else if(numlen == 6 || numlen == 9 || numlen == 12 || numlen == 15) {
636 memcpy(abbrev,num,3);
637 abbrev[3]='.';
638 strncpy(abbrev+4,num+3,2);
639 abbrev[6]='\0';
9bd92830
FM
640 if(!n) return(abbrev);
641 if(numlen == 6)
d5a8da9d 642 strcat(abbrev,"K");
9bd92830 643 else if(numlen == 9)
d5a8da9d 644 strcat(abbrev,"M");
9bd92830 645 else if(numlen == 12)
d5a8da9d 646 strcat(abbrev,"G");
9bd92830 647 else if(numlen == 15)
d5a8da9d 648 strcat(abbrev,"T");
9bd92830
FM
649 }
650
651 return(abbrev);
652 }
653
654 bzero(buf, MAXLEN_FIXNUM*2);
655
656 pbuf = buf;
657 pret = ret;
658 k = 0;
659
660 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
661 if ( k == 2 && i != 0 ) {
662 k = 0;
663 pbuf[j++] = num[i];
664 pbuf[j++] = (UseComma) ? ',' : '.';
665 continue;
666 }
667 pbuf[j] = num[i];
668 j++;
669 k++;
670 }
671
672 pret[0]='\0';
673
674 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
675 pret[j] = pbuf[i];
676
677 pret[j] = '\0';
678
679 return pret;
25697a35
GS
680}
681
682
d6e703cc 683char *fixnum2(long long int value, int n)
d6e703cc 684{
32e71fa4 685#define MAXLEN_FIXNUM2 1024
9bd92830
FM
686 char num[MAXLEN_FIXNUM2];
687 char buf[MAXLEN_FIXNUM2 * 2];
688 char *pbuf;
689 static char ret[MAXLEN_FIXNUM2 * 2];
690 char *pret;
691 register int i, j, k;
2357ef77 692
9bd92830
FM
693 my_lltoa(value, num, sizeof(num), 0);
694 bzero(buf, MAXLEN_FIXNUM2*2);
d6e703cc 695
9bd92830
FM
696 pbuf = buf;
697 pret = ret;
698 k = 0;
d6e703cc 699
9bd92830
FM
700 for ( i = strlen(num) - 1, j = 0 ; i > -1; i--) {
701 if ( k == 2 && i != 0 ) {
702 k = 0;
703 pbuf[j++] = num[i];
704 pbuf[j++] = (UseComma) ? ',' : '.';
705 continue;
706 }
707 pbuf[j] = num[i];
708 j++;
709 k++;
710 }
d6e703cc 711
9bd92830 712 pret[0]='\0';
d6e703cc 713
9bd92830
FM
714 for ( i = strlen(pbuf) - 1, j = 0 ; i > -1; i--, j++)
715 pret[j] = pbuf[i];
d6e703cc 716
9bd92830 717 pret[j] = '\0';
d6e703cc 718
9bd92830 719 return pret;
d6e703cc
FM
720}
721
722
25697a35
GS
723char *buildtime(long long int elap)
724{
9bd92830
FM
725 int num = elap / 1000;
726 int hor = 0;
727 int min = 0;
728 int sec = 0;
729 static char buf[12];
25697a35 730
9bd92830 731 buf[0]='\0';
25697a35 732
9bd92830
FM
733 hor=num / 3600;
734 min=(num % 3600) / 60;
735 sec=num % 60;
736 sprintf(buf,"%02d:%02d:%02d",hor,min,sec);
25697a35 737
9bd92830 738 return(buf);
25697a35
GS
739}
740
741
15d3cb5c
FM
742/*!
743Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
744
745\param dirname The directory to look for the connection directory.
746\param name The name of the directory whose <tt>sarg-date</tt> file must be read.
747\param data The buffer to store the content of the file. It must be more than 80
748bytes long.
749
750\retval 0 No error.
751\retval -1 File not found.
752*/
753int obtdate(const char *dirname, const char *name, char *data)
25697a35 754{
9bd92830
FM
755 FILE *fp_in;
756 char wdir[MAXLEN];
25697a35 757
9bd92830
FM
758 sprintf(wdir,"%s%s/sarg-date",dirname,name);
759 if ((fp_in = fopen(wdir, "rt")) == 0) {
760 sprintf(wdir,"%s%s/date",dirname,name);
761 if ((fp_in = fopen(wdir, "rt")) == 0) {
762 data[0]='\0';
15d3cb5c 763 return(-1);
9bd92830
FM
764 }
765 }
25697a35 766
9bd92830
FM
767 if (!fgets(data,80,fp_in)) {
768 debuga(_("Failed to read the date in %s\n"),wdir);
769 exit(EXIT_FAILURE);
770 }
771 fclose(fp_in);
772 fixendofline(data);
25697a35 773
15d3cb5c 774 return(0);
25697a35
GS
775}
776
777
a1de61fe 778void formatdate(char *date,int date_size,int year,int month,int day,int hour,int minute,int second,int dst)
9e41ca7e 779{
9bd92830
FM
780 struct tm ltm;
781 time_t unixtime;
782 struct tm *fulltm;
9e41ca7e 783
9bd92830
FM
784 memset(&ltm,0,sizeof(ltm));
785 if (year>=1900) ltm.tm_year=year-1900;
786 if (month>=1 && month<=12) ltm.tm_mon=month-1;
787 if (day>=1 && day<=31) ltm.tm_mday=day;
788 if (hour>=0 && hour<24) ltm.tm_hour=hour;
789 if (minute>=0 && minute<60) ltm.tm_min=minute;
790 if (second>=0 && second<60) ltm.tm_sec=second;
791 ltm.tm_isdst=dst;
792 unixtime=mktime(&ltm); //fill the missing entries
793 fulltm=localtime(&unixtime);
794 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
795 strftime(date,date_size,"%c",fulltm);
9e41ca7e
FM
796}
797
798
fa6552b0 799void computedate(int year,int month,int day,struct tm *t)
9426efec 800{
9bd92830
FM
801 memset(t,0,sizeof(*t));
802 t->tm_year=year-1900;
803 t->tm_mon=month-1;
804 t->tm_mday=day;
9426efec
FM
805}
806
807
d25d4e6a 808int obtuser(const char *dirname, const char *name)
25697a35 809{
9bd92830
FM
810 FILE *fp_in;
811 char wdir[MAXLEN];
812 char tuser[20];
813 int nuser;
25697a35 814
9bd92830
FM
815 sprintf(wdir,"%s%s/sarg-users",dirname,name);
816 if((fp_in=fopen(wdir,"r"))==NULL) {
817 sprintf(wdir,"%s%s/users",dirname,name);
818 if((fp_in=fopen(wdir,"r"))==NULL) {
819 return(0);
820 }
821 }
25697a35 822
9bd92830
FM
823 if (!fgets(tuser,sizeof(tuser),fp_in)) {
824 debuga(_("Failed to read the number of users in %s\n"),wdir);
825 exit(EXIT_FAILURE);
826 }
827 fclose(fp_in);
828 nuser=atoi(tuser);
25697a35 829
9bd92830 830 return(nuser);
25697a35
GS
831}
832
833
ea275279 834void obttotal(const char *dirname, const char *name, int nuser, long long int *tbytes, long long int *media)
25697a35 835{
9bd92830
FM
836 FILE *fp_in;
837 char *buf;
838 char wdir[MAXLEN];
839 char user[MAX_USER_LEN];
840 char sep;
841 struct getwordstruct gwarea;
842 longline line;
843
844 *tbytes=0;
845 *media=0;
846
847 sprintf(wdir,"%s%s/sarg-general",dirname,name);
848 if ((fp_in = fopen(wdir, "r")) == 0) {
849 sprintf(wdir,"%s%s/general",dirname,name);
850 if ((fp_in = fopen(wdir, "r")) == 0) {
851 return;
852 }
853 }
854
855 if ((line=longline_create())==NULL) {
856 debuga(_("Not enough memory to read the file %s\n"),wdir);
857 exit(EXIT_FAILURE);
858 }
859
860 while((buf=longline_read(fp_in,line))!=NULL) {
861 if (strncmp(buf,"TOTAL\t",6) == 0)
862 sep='\t'; //new file
863 else if (strncmp(buf,"TOTAL ",6) == 0)
864 sep=' '; //old file
865 else
866 continue;
867 getword_start(&gwarea,buf);
868 if (getword(user,sizeof(user),&gwarea,sep)<0) {
869 debuga(_("There is a invalid user in file %s\n"),wdir);
870 exit(EXIT_FAILURE);
871 }
872 if(strcmp(user,"TOTAL") != 0)
873 continue;
874 if (getword_skip(MAXLEN,&gwarea,sep)<0) {
875 debuga(_("There a broken total number of access in file %s\n"),wdir);
876 exit(EXIT_FAILURE);
877 }
878 if (getword_atoll(tbytes,&gwarea,sep)<0) {
879 debuga(_("There is a broken number of bytes in file %s\n"),wdir);
880 exit(EXIT_FAILURE);
881 }
882 break;
883 }
884 fclose(fp_in);
885 longline_destroy(&line);
886
887 if (nuser <= 0)
888 return;
889
890 *media=*tbytes / nuser;
891 return;
25697a35
GS
892}
893
fa6552b0 894int getperiod_fromsarglog(const char *arqtt,struct periodstruct *period)
25697a35 895{
9bd92830
FM
896 const char *str;
897 int day0, month0, year0, hour0, minute0;
898 int day1, month1, year1, hour1, minute1;
9bd92830
FM
899 int i;
900
901 memset(period,0,sizeof(*period));
902
903 str=arqtt;
904 while((str=strstr(str,"sarg-"))!=NULL) {
905 str+=5;
906 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
907 day0=(str[0]-'0')*10+(str[1]-'0');
cbe0740f 908 if (day0<1 || day0>31) continue;
9bd92830 909 str+=2;
cbe0740f
FM
910 month0=(str[0]-'0')*10+(str[1]-'0')-1;
911 if (month0<0 || month0>11) continue;
ddd6dbdc 912 str+=2;
9bd92830
FM
913 year0=0;
914 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year0=year0*10+(str[i]-'0');
915 if (i!=4) continue;
916 str+=4;
917 if (str[0]!='_') continue;
918 str++;
919
920 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
921 hour0=(str[0]-'0')*10+(str[1]-'0');
922 str+=2;
923 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
924 minute0=(str[0]-'0')*10+(str[1]-'0');
925 str+=2;
926
927 if (*str != '-') continue;
928 str++;
929
930 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
931 day1=(str[0]-'0')*10+(str[1]-'0');
cbe0740f 932 if (day1<1 || day1>31) continue;
9bd92830 933 str+=2;
cbe0740f
FM
934 month1=(str[0]-'0')*10+(str[1]-'0')-1;
935 if (month1<0 || month1>11) continue;
ddd6dbdc 936 str+=2;
9bd92830
FM
937 year1=0;
938 for (i=0 ; isdigit(str[i]) && i<4 ; i++) year1=year1*10+(str[i]-'0');
939 if (i!=4) continue;
940 str+=4;
941
942 if (str[0]!='_') continue;
943 str++;
944
945 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
946 hour1=(str[0]-'0')*10+(str[1]-'0');
947 str+=2;
948 if (!isdigit(str[0]) || !isdigit(str[1])) continue;
949 minute1=(str[0]-'0')*10+(str[1]-'0');
950 str+=2;
951
952 period->start.tm_mday=day0;
953 period->start.tm_mon=month0;
954 period->start.tm_year=year0-1900;
955 period->start.tm_hour=hour0;
956 period->start.tm_min=minute0;
957 period->end.tm_mday=day1;
958 period->end.tm_mon=month1;
959 period->end.tm_year=year1-1900;
960 period->end.tm_hour=hour1;
961 period->end.tm_min=minute1;
962 return(0);
963 }
964 return(-1);
fa6552b0 965}
48864d28 966
42b117e3
FM
967void getperiod_fromrange(struct periodstruct *period,int dfrom,int duntil)
968{
9bd92830
FM
969 memset(&period->start,0,sizeof(period->start));
970 period->start.tm_mday=dfrom%100;
971 period->start.tm_mon=(dfrom/100)%100-1;
972 period->start.tm_year=(dfrom/10000)-1900;
42b117e3 973
9bd92830
FM
974 memset(&period->end,0,sizeof(period->end));
975 period->end.tm_mday=duntil%100;
976 period->end.tm_mon=(duntil/100)%100-1;
977 period->end.tm_year=(duntil/10000)-1900;
42b117e3
FM
978}
979
cc6af460
FM
980/*!
981Update the \a main period to encompass the period in \a candidate.
982*/
983void getperiod_merge(struct periodstruct *main,struct periodstruct *candidate)
984{
985 int cdate;
986 int mdate;
987
988 mdate=(main->start.tm_year)*10000+(main->start.tm_mon)*100+main->start.tm_mday;
989 cdate=(candidate->start.tm_year)*10000+(candidate->start.tm_mon)*100+candidate->start.tm_mday;
990 if (cdate<mdate) memcpy(&main->start,&candidate->start,sizeof(struct tm));
991
992 mdate=(main->end.tm_year)*10000+(main->end.tm_mon)*100+main->end.tm_mday;
993 cdate=(candidate->end.tm_year)*10000+(candidate->end.tm_mon)*100+candidate->end.tm_mday;
994 if (cdate>mdate) memcpy(&main->end,&candidate->end,sizeof(struct tm));
995}
996
fa6552b0
FM
997int getperiod_buildtext(struct periodstruct *period)
998{
9bd92830
FM
999 int i;
1000 int range;
1001 char text1[40], text2[40];
1002
81a022d8 1003 if (df=='u') {
9bd92830 1004 i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
81a022d8 1005 } else if(df=='e') {
9bd92830 1006 i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
81a022d8 1007 } else /*if (df=='w')*/ {
9bd92830
FM
1008 IndexTree=INDEX_TREE_FILE;
1009 i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
1010 }
1011 if (i == 0) return(-1);
1012
1013 range=(period->start.tm_year!=period->end.tm_year ||
007905af
FM
1014 period->start.tm_mon!=period->end.tm_mon ||
1015 period->start.tm_mday!=period->end.tm_mday);
9bd92830 1016 if (range) {
81a022d8 1017 if (df=='u') {
9bd92830 1018 i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
81a022d8 1019 } else if (df=='e') {
9bd92830
FM
1020 i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
1021 } else {
1022 i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
1023 }
1024 if (i == 0) return(-1);
1025 }
1026
1027 if (range) {
1028 snprintf(period->text,sizeof(period->text),"%s-%s",text1,text2);
1029 snprintf(period->html,sizeof(period->html),"%s&mdash;%s",text1,text2);
1030 } else {
a87d4d11
FM
1031 safe_strcpy(period->text,text1,sizeof(period->text));
1032 safe_strcpy(period->html,text1,sizeof(period->html));
9bd92830
FM
1033 }
1034 return(0);
25697a35
GS
1035}
1036
06ced858 1037static void copy_images(void)
25697a35 1038{
9bd92830
FM
1039 FILE *img_in, *img_ou;
1040 char images[512];
1041 char imgdir[MAXLEN];
1042 char srcfile[MAXLEN];
1043 char dstfile[MAXLEN];
1044 DIR *dirp;
1045 struct dirent *direntp;
1046 char buffer[MAXLEN];
1047 size_t nread;
1048 struct stat info;
1049
1050 if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
1051 debuga(_("Cannot copy images to target directory %simages\n"),outdir);
1052 exit(EXIT_FAILURE);
1053 }
1054 if (access(images,R_OK)!=0) {
affa72c5
FM
1055 if (mkdir(images,0755)) {
1056 debuga(_("Cannot create directory %s - %s\n"),images,strerror(errno));
1057 exit(EXIT_FAILURE);
1058 }
9bd92830
FM
1059 }
1060
1061 strcpy(imgdir,IMAGEDIR);
1062 dirp = opendir(imgdir);
1063 if(dirp==NULL) {
1064 debuga(_("(util) Can't open directory %s: %s\n"),imgdir,strerror(errno));
1065 return;
1066 }
1067 while ((direntp = readdir( dirp )) != NULL ){
1068 if(direntp->d_name[0]=='.')
1069 continue;
1070 sprintf(srcfile,"%s/%s",imgdir,direntp->d_name);
1071 if (stat(srcfile,&info)) {
1072 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile,strerror(errno));
1073 continue;
1074 }
1075 if (S_ISREG(info.st_mode)) {
1076 sprintf(dstfile,"%s/%s",images,direntp->d_name);
1077 img_in = fopen(srcfile, "rb");
1078 if(img_in!=NULL) {
1079 img_ou = fopen(dstfile, "wb");
1080 if(img_ou!=NULL) {
1081 while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
1082 if (fwrite(buffer,1,nread,img_ou)!=nread) {
1083 debuga(_("Failed to copy image %s to %s\n"),srcfile,dstfile);
1084 break;
1085 }
1086 }
507460ae
FM
1087 if (fclose(img_ou)==EOF) {
1088 debuga(_("Error while copying image %s: %s\n"),dstfile,strerror(errno));
1089 exit(EXIT_FAILURE);
1090 }
9bd92830
FM
1091 } else
1092 fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile, strerror(errno));
1093 fclose(img_in);
1094 } else
1095 fprintf(stderr,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile, strerror(errno));
1096 }
1097 }
1098 (void) closedir(dirp);
1099
1100 return;
06ced858
FM
1101}
1102
fa6552b0 1103int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us, const char *form)
06ced858 1104{
9bd92830
FM
1105 FILE *fp_ou;
1106 int num=1, count=0;
1107 char wdir[MAXLEN];
1108 char dirname2[MAXLEN];
1109 int y1, y2;
1110 int m1, m2;
1111 int d1, d2;
1112 int wlen, wlen2;
1113 time_t curtime;
1114 struct tm *loctm;
1115
1116 strcpy(wdir,outdir);
1117 wlen=strlen(wdir);
1118 y1=per1->start.tm_year+1900;
1119 y2=per1->end.tm_year+1900;
1120 m1=per1->start.tm_mon+1;
1121 m2=per1->end.tm_mon+1;
1122 d1=per1->start.tm_mday;
1123 d2=per1->end.tm_mday;
1124 if(IndexTree == INDEX_TREE_DATE) {
1125 wlen+=sprintf(wdir+wlen,"%04d",y1);
1126 if(y1!=y2) wlen+=sprintf(wdir+wlen,"-%04d",y2);
1127 if(access(wdir, R_OK) != 0)
1128 my_mkdir(wdir);
1129
1130 wlen+=sprintf(wdir+wlen,"/%02d",m1);
1131 if(m1 != m2) wlen+=sprintf(wdir+wlen,"-%02d",m2);
1132 if(access(wdir, R_OK) != 0)
1133 my_mkdir(wdir);
1134
1135 wlen+=sprintf(wdir+wlen,"/%02d",d1);
1136 if(d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
1137 } else {
81a022d8 1138 if (df == 'u') {
9bd92830 1139 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
007905af 1140 conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
81a022d8 1141 } else if (df == 'e') {
9bd92830 1142 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
007905af 1143 conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
81a022d8 1144 } else if (df == 'w') {
9bd92830
FM
1145 wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
1146 if (wlen2==0) return(-1);
1147 wlen+=wlen2;
1148 }
1149 }
1150
1151 if(us[0] != '\0') {
1152 struct userinfostruct *uinfo=userinfo_find_from_id(us);
1153 if (uinfo) {
1154 strcat(wdir,"-");
1155 strcat(wdir,uinfo->filename);
1156 }
1157 }
1158 if(addr[0] != '\0') {
1159 strcat(wdir,"-");
1160 strcat(wdir,addr);
1161 }
1162 if(site[0] != '\0') {
1163 strcat(wdir,"-");
1164 strcat(wdir,site);
1165 }
1166
1167 strcpy(outdirname,wdir);
1168
1169 if(IndexTree != INDEX_TREE_DATE) {
1170 if(!OverwriteReport) {
1171 while(num) {
1172 if(access(wdir,R_OK) == 0) {
1173 sprintf(wdir,"%s.%d",outdirname,num);
1174 num++;
1175 count++;
1176 } else
1177 break;
1178 }
1179
1180 if(count > 0) {
1181 if(debug)
1182 debuga(_("File %s already exists, moved to %s\n"),outdirname,wdir);
1183 rename(outdirname,wdir);
1184 }
1185 } else {
1186 if(access(outdirname,R_OK) == 0) {
1187 unlinkdir(outdirname,1);
1188 }
1189 }
1190 my_mkdir(outdirname);
1191 } else {
1192 strcpy(dirname2,wdir);
1193 if(!OverwriteReport) {
1194 while(num) {
1195 if(access(wdir,R_OK) == 0) {
1196 sprintf(wdir,"%s.%d",dirname2,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"),dirname2,wdir);
1206 rename(dirname2,wdir);
1207 strcpy(dirname2,wdir);
1208 }
1209 } else {
1210 if(access(wdir,R_OK) == 0) {
1211 unlinkdir(wdir,1);
1212 }
1213 }
1214
1215 if(access(wdir, R_OK) != 0)
1216 my_mkdir(wdir);
1217 }
1218
1219 strcpy(dirname2,wdir);
1220
1221 sprintf(wdir,"%s/sarg-date",outdirname);
1222 if ((fp_ou = fopen(wdir, "wt")) == 0) {
d6f0349d 1223 debuga(_("cannot open %s for writing: %s\n"),wdir,strerror(errno));
9bd92830
FM
1224 perror("SARG:");
1225 exit(EXIT_FAILURE);
1226 }
1227 time(&curtime);
1228 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1229 loctm=localtime(&curtime);
1230 strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
1231 if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
1232 debuga(_("Failed to write the date in %s\n"),wdir);
1233 perror("SARG:");
1234 exit(EXIT_FAILURE);
1235 }
1236 if (fclose(fp_ou)==EOF) {
507460ae 1237 debuga(_("Failed to write the date in %s: %s\n"),wdir,strerror(errno));
9bd92830
FM
1238 exit(EXIT_FAILURE);
1239 }
1240
1241 copy_images();
1242 return(0);
25697a35
GS
1243}
1244
a87d4d11
FM
1245/*!
1246 Copy a string without overflowing the buffer. The copied string
1247 is properly terminated by an ASCII zero.
b902df7e 1248
a87d4d11
FM
1249 \param dest The destination buffer.
1250 \param src The source buffer.
1251 \param length The size of the destination buffer. The program is aborted
1252 if the length is negative or zero.
1253*/
1254void safe_strcpy(char *dest,const char *src,int length)
1255{
1256 if (length<=0) {
1257 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1258 exit(EXIT_FAILURE);
1259 }
1260 strncpy(dest,src,length-1);
1261 dest[length-1]='\0';
1262}
1263
25697a35
GS
1264void strip_latin(char *line)
1265{
9bd92830
FM
1266 int i,j;
1267 int skip;
1268
1269 j=0;
1270 skip=0;
1271 for (i=0;line[i];i++){
1272 if (skip){
1273 if (line[i]==';') skip=0;
1274 } else {
1275 if (line[i]=='&')
1276 skip=1;
1277 else
1278 line[j++]=line[i];
1279 }
1280 }
1281 line[j]='\0';
1282 return;
25697a35
GS
1283}
1284
81a022d8 1285void zdate(char *ftime,int ftimesize, char DateFormat)
25697a35 1286{
9bd92830
FM
1287 time_t t;
1288 struct tm *local;
25697a35 1289
9bd92830
FM
1290 t = time(NULL);
1291 local = localtime(&t);
81a022d8 1292 if (DateFormat=='u')
9bd92830 1293 strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
81a022d8 1294 else if (DateFormat=='e')
9bd92830 1295 strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
81a022d8 1296 else if (DateFormat=='w')
9bd92830
FM
1297 strftime(ftime, ftimesize, "%W-%H-%M", local);
1298 return;
25697a35
GS
1299}
1300
1301
324ba7f3 1302char *fixtime(long long int elap)
25697a35 1303{
9bd92830
FM
1304 int num = elap / 1000;
1305 int hor = 0;
1306 int min = 0;
1307 int sec = 0;
1308 static char buf[12];
25697a35 1309
9bd92830
FM
1310 hor=num / 3600;
1311 min=(num % 3600) / 60;
1312 sec=num % 60;
25697a35 1313
9bd92830
FM
1314 if(hor==0 && min==0 && sec==0)
1315 strcpy(buf,"0");
1316 else
1317 sprintf(buf,"%d:%02d:%02d",hor,min,sec);
25697a35 1318
9bd92830 1319 return buf;
25697a35
GS
1320}
1321
1322
42b117e3 1323void date_from(char *date, int *dfrom, int *duntil)
25697a35 1324{
9bd92830
FM
1325 int d0=0;
1326 int m0=0;
1327 int y0=0;
1328 int d1=0;
1329 int m1=0;
1330 int y1=0;
1331
1332 if (isdigit(date[0])) {
1333 int next=-1;
1334
1335 if (sscanf(date,"%d/%d/%d%n",&d0,&m0,&y0,&next)!=3 || y0<100 || m0<1 || m0>12 || d0<1 || d0>31 || next<0) {
1336 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1337 exit(EXIT_FAILURE);
1338 }
1339 if (date[next]=='-') {
1340 if (sscanf(date+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
1341 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1342 exit(EXIT_FAILURE);
1343 }
1344 } else if (date[next]!='\0') {
1345 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1346 exit(EXIT_FAILURE);
1347 } else {
1348 d1=d0;
1349 m1=m0;
1350 y1=y0;
1351 }
1352 } else {
1353 int i;
1354 time_t Today,t1;
1355 struct tm *Date0,Date1;
1356
1357 if (time(&Today)==(time_t)-1) {
1358 debuga(_("Failed to get the current time\n"));
1359 exit(EXIT_FAILURE);
1360 }
1361 if (sscanf(date,"day-%d",&i)==1) {
1362 if (i<0) {
1363 debuga(_("Invalid number of days in -d parameter\n"));
1364 exit(EXIT_FAILURE);
1365 }
1366 Today-=i*24*60*60;
1367 Date0=localtime(&Today);
1368 if (Date0==NULL) {
1369 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1370 exit(EXIT_FAILURE);
1371 }
1372 y0=y1=Date0->tm_year+1900;
1373 m0=m1=Date0->tm_mon+1;
1374 d0=d1=Date0->tm_mday;
1375 } else if (sscanf(date,"week-%d",&i)==1) {
1376 /*
1377 There is no portable way to find the first day of the week even though the
1378 information is available in the locale. nl_langinfo has the unofficial
1379 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1380 undocumented as is their return value and it is discouraged to use them.
1381 Beside, nl_langinfo isn't available on windows and the first day of the
1382 week isn't available at all on that system.
1383 */
1384 const int FirstWeekDay=1;
1385 time_t WeekBegin;
1386
1387 if (i<0) {
1388 debuga(_("Invalid number of weeks in -d parameter\n"));
1389 exit(EXIT_FAILURE);
1390 }
1391 Date0=localtime(&Today);
1392 if (Date0==NULL) {
1393 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1394 exit(EXIT_FAILURE);
1395 }
1396 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1397 WeekBegin-=i*7*24*60*60;
1398 Date0=localtime(&WeekBegin);
1399 if (Date0==NULL) {
1400 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1401 exit(EXIT_FAILURE);
1402 }
1403 y0=Date0->tm_year+1900;
1404 m0=Date0->tm_mon+1;
1405 d0=Date0->tm_mday;
1406 WeekBegin+=6*24*60*60;
1407 Date0=localtime(&WeekBegin);
1408 if (Date0==NULL) {
1409 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1410 exit(EXIT_FAILURE);
1411 }
1412 y1=Date0->tm_year+1900;
1413 m1=Date0->tm_mon+1;
1414 d1=Date0->tm_mday;
1415 } else if (sscanf(date,"month-%d",&i)==1) {
1416 if (i<0) {
1417 debuga(_("Invalid number of months in -d parameter\n"));
1418 exit(EXIT_FAILURE);
1419 }
1420 Date0=localtime(&Today);
1421 if (Date0==NULL) {
1422 debuga(_("Cannot convert local time: %s\n"),strerror(errno));
1423 exit(EXIT_FAILURE);
1424 }
1425 if (Date0->tm_mon<i%12) {
1426 y0=Date0->tm_year+1900-i/12-1;
1427 m0=(Date0->tm_mon+12-i%12)%12+1;
1428 d0=1;
1429 } else {
1430 y0=Date0->tm_year+1900-i/12;
1431 m0=Date0->tm_mon-i%12+1;
1432 d0=1;
1433 }
1434 memcpy(&Date1,Date0,sizeof(struct tm));
1435 Date1.tm_isdst=-1;
1436 Date1.tm_mday=1;
1437 if (m0<12) {
1438 Date1.tm_mon=m0;
1439 Date1.tm_year=y0-1900;
1440 } else {
1441 Date1.tm_mon=0;
1442 Date1.tm_year=y0-1900+1;
1443 }
1444 t1=mktime(&Date1);
1445 t1-=24*60*60;
1446 Date0=localtime(&t1);
1447 y1=Date0->tm_year+1900;
1448 m1=Date0->tm_mon+1;
1449 d1=Date0->tm_mday;
1450 } else {
1451 debuga(_("Invalid date range passed on command line\n"));
1452 exit(EXIT_FAILURE);
1453 }
1454 }
1455
1456 *dfrom=y0*10000+m0*100+d0;
1457 *duntil=y1*10000+m1*100+d1;
1458 sprintf(date,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
1459 return;
25697a35
GS
1460}
1461
1462
1463char *strlow(char *string)
1464{
9bd92830 1465 char *s;
25697a35 1466
9bd92830
FM
1467 if (string)
1468 {
1469 for (s = string; *s; ++s)
1470 *s = tolower(*s);
1471 }
25697a35 1472
9bd92830 1473 return string;
25697a35
GS
1474}
1475
1476
1477
1478
1479char *strup(char *string)
1480{
9bd92830 1481 char *s;
25697a35 1482
9bd92830
FM
1483 if (string)
1484 {
1485 for (s = string; *s; ++s)
1486 *s = toupper(*s);
1487 }
25697a35 1488
9bd92830 1489 return string;
25697a35
GS
1490}
1491
1492
32e71fa4 1493void removetmp(const char *outdir)
25697a35 1494{
9dc20988
FM
1495 FILE *fp_gen;
1496 char filename[256];
9bd92830
FM
1497
1498 if(!RemoveTempFiles)
1499 return;
1500
1501 if(debug) {
1502 debuga(_("Purging temporary file sarg-general\n"));
1503 }
9dc20988 1504 if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
9bd92830
FM
1505 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir);
1506 exit(EXIT_FAILURE);
1507 }
9dc20988 1508 if((fp_gen=fopen(filename,"w"))==NULL){
d6f0349d 1509 debuga(_("(removetmp) Cannot open file %s: %s\n"),filename,strerror(errno));
9bd92830
FM
1510 exit(EXIT_FAILURE);
1511 }
9dc20988
FM
1512 totalger(fp_gen,filename);
1513 if (fclose(fp_gen)==EOF) {
507460ae 1514 debuga(_("Failed to close %s after writing the total line: %s\n"),filename,strerror(errno));
9bd92830
FM
1515 exit(EXIT_FAILURE);
1516 }
25697a35
GS
1517}
1518
48864d28 1519void load_excludecodes(const char *ExcludeCodes)
25697a35 1520{
9bd92830
FM
1521 FILE *fp_in;
1522 char data[80];
1523 int i;
1524 int Stored;
1525 long int MemSize;
1526
1527 if(ExcludeCodes[0] == '\0')
1528 return;
1529
1530 if((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
d6f0349d 1531 debuga(_("(util) Cannot open file %s (exclude_codes): %s\n"),ExcludeCodes,strerror(errno));
9bd92830
FM
1532 exit(EXIT_FAILURE);
1533 }
1534
1535 if (fseek(fp_in, 0, SEEK_END)==-1) {
1536 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1537 exit(EXIT_FAILURE);
1538 }
1539 MemSize = ftell(fp_in);
1540 if (MemSize<0) {
1541 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes);
1542 exit(EXIT_FAILURE);
1543 }
1544 if (fseek(fp_in, 0, SEEK_SET)==-1) {
1545 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes,strerror(errno));
1546 exit(EXIT_FAILURE);
1547 }
1548
1549 MemSize+=1;
1550 if((excludecode=(char *) malloc(MemSize))==NULL) {
1551 debuga(_("malloc error (%ld)\n"),MemSize);
1552 exit(EXIT_FAILURE);
1553 }
1554 memset(excludecode,0,MemSize);
1555
1556 Stored=0;
1557 while(fgets(data,sizeof(data),fp_in)!=NULL) {
1558 if (data[0]=='#') continue;
1559 for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
1560 if (i<0) continue;
1561 if (Stored+i+2>=MemSize) {
1562 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes);
1563 break;
1564 }
1565 strcat(excludecode,data);
1566 strcat(excludecode,";");
1567 Stored+=i+1;
1568 }
1569
1570 fclose(fp_in);
1571 return;
25697a35
GS
1572}
1573
48864d28
FM
1574void free_excludecodes(void)
1575{
9bd92830
FM
1576 if (excludecode) {
1577 free(excludecode);
1578 excludecode=NULL;
1579 }
48864d28
FM
1580}
1581
32e71fa4 1582int vercode(const char *code)
25697a35 1583{
9bd92830
FM
1584 char *cod;
1585 int clen;
48864d28 1586
9bd92830
FM
1587 if (excludecode && excludecode[0]!='\0') {
1588 clen=strlen(code);
1589 cod=excludecode;
1590 while (cod) {
1591 if (strncmp(code,cod,clen)==0 && cod[clen]==';')
1592 return 1;
1593 cod=strchr(cod,';');
1594 if (cod) cod++;
1595 }
1596 }
1597 return 0;
25697a35
GS
1598}
1599
1600void fixnone(char *str)
1601{
9bd92830 1602 int i;
32e71fa4 1603
9bd92830
FM
1604 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--);
1605 if(i==3 && strncmp(str,"none",4) == 0)
1606 str[0]='\0';
25697a35 1607
9bd92830 1608 return;
25697a35
GS
1609}
1610
2357ef77
FM
1611void fixendofline(char *str)
1612{
9bd92830 1613 int i;
2357ef77 1614
9bd92830 1615 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--) str[i]=0;
2357ef77
FM
1616}
1617
25697a35 1618#ifdef LEGACY_TESTVALIDUSERCHAR
32e71fa4 1619int testvaliduserchar(const char *user)
25697a35 1620{
9bd92830
FM
1621 int x=0;
1622 int y=0;
25697a35 1623
9bd92830
FM
1624 for (y=0; y<strlen(UserInvalidChar); y++) {
1625 for (x=0; x<strlen(user); x++) {
1626 if(user[x] == UserInvalidChar[y])
1627 return 1;
1628 }
1629 }
1630 return 0;
25697a35
GS
1631}
1632#else
32e71fa4 1633int testvaliduserchar(const char *user)
25697a35 1634{
9bd92830
FM
1635 char * p_UserInvalidChar = UserInvalidChar ;
1636 const char * p_user ;
25697a35 1637
9bd92830
FM
1638 while( *p_UserInvalidChar ) {
1639 p_user = user ;
1640 while ( *p_user ) {
1641 if( *p_UserInvalidChar == *p_user )
1642 return 1;
1643 p_user++ ;
1644 }
1645 p_UserInvalidChar++ ;
1646 }
1647 return 0;
25697a35
GS
1648}
1649#endif
1650
1651int compar( const void *a, const void *b )
9bd92830
FM
1652{
1653 if( *(int *)a > *(int *)b ) return 1;
1654 if( *(int *)a < *(int *)b ) return -1;
1655 return 0;
25697a35
GS
1656}
1657
1658int getnumlist( char *buf, numlist *list, const int len, const int maxvalue )
48864d28 1659{
9bd92830
FM
1660 int i, j, d, flag, r1, r2;
1661 char *pbuf, **bp, *strbufs[ 24 ];
1662
1663 bp = strbufs;
1664 strtok( buf, " \t" );
1665 for( *bp = strtok( NULL, "," ), list->len = 0; *bp; *bp = strtok( NULL, "," ) ) {
1666 if( ++bp >= &strbufs[ 24 ] )
1667 break;
1668 list->len++;
1669 }
1670 if( ! list->len )
1671 return -1;
1672 d = 0;
1673 for( i = 0; i < list->len; i++ ) {
1674 if( strchr( strbufs[ i ], '-' ) != 0 ) {
1675 pbuf = strbufs[ i ];
1676 strtok( pbuf, "-" );
1677 pbuf = strtok( NULL, "\0" );
1678 r1 = atoi( strbufs[ i ] );
1679 if( ( r2 = atoi( pbuf ) ) >= maxvalue || r1 >= r2 )
1680 return -1;
1681 if( i + d + ( r2 - r1 ) + 1 <= len ) {
1682 for( j = r1; j <= r2; j++ )
1683 list->list[ i + d++ ] = j;
1684 d--;
1685 }
1686 }
1687 else
1688 if( ( list->list[ i + d ] = atoi( strbufs[ i ] ) ) >= maxvalue )
1689 return 1;
1690 }
1691 list->len += d;
1692 qsort( list->list, list->len, sizeof( int ), compar );
1693 do {
1694 flag = 0;
1695 for( i = 0; i < list->len - 1; i++ )
1696 if( list->list[ i ] == list->list[ i + 1 ] ) {
1697 for( j = i + 1; j < list->len; j++ )
1698 list->list[ j - 1 ] = list->list[ j ];
1699 list->len--;
1700 flag = 1;
1701 break;
1702 }
1703 } while( flag );
1704 return 0;
25697a35
GS
1705}
1706
1707
32e71fa4 1708char *get_size(const char *path, const char *file)
491b862f 1709{
9bd92830
FM
1710 FILE *fp;
1711 static char response[255];
1712 char cmd[255];
1713 char *ptr;
1714
1715 if (snprintf(cmd,sizeof(cmd),"du -skh %s%s",path,file)>=sizeof(cmd)) {
1716 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path,file);
1717 exit(EXIT_FAILURE);
1718 }
1719 if ((fp = popen(cmd, "r")) == NULL) {
1720 debuga(_("Cannot get disk space with command %s\n"),cmd);
1721 exit(EXIT_FAILURE);
1722 }
1723 if (!fgets(response, sizeof(response), fp)) {
1724 debuga(_("Cannot get disk size with command %s\n"),cmd);
1725 exit(EXIT_FAILURE);
1726 }
1727 ptr=strchr(response,'\t');
1728 if (ptr==NULL) {
1729 debuga(_("The command %s failed\n"),cmd);
1730 exit(EXIT_FAILURE);
1731 }
1732 pclose(fp);
1733 *ptr='\0';
1734
1735 return (response);
491b862f
GS
1736}
1737
dfb337be
FM
1738void show_info(FILE *fp_ou)
1739{
9bd92830 1740 char ftime[127];
dfb337be 1741
9bd92830 1742 if(!ShowSargInfo) return;
81a022d8 1743 zdate(ftime, sizeof(ftime), df);
b3a3c51c
FM
1744 fputs("<div class=\"info\">",fp_ou);
1745 fprintf(fp_ou,_("Generated by <a href='%s'>%s-%s</a> on %s"),URL,PGM,VERSION,ftime);
1746 fputs("</div>\n",fp_ou);
dfb337be
FM
1747}
1748
c0ec9cc7 1749void show_sarg(FILE *fp_ou, int depth)
dfb337be 1750{
9bd92830 1751 int i;
c0ec9cc7 1752
9bd92830
FM
1753 if(!ShowSargLogo) return;
1754 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
1755 for (i=0 ; i<depth ; i++)
1756 fputs("../",fp_ou);
1757 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
1758}
1759
1760void write_logo_image(FILE *fp_ou)
1761{
9bd92830
FM
1762 if(LogoImage[0]!='\0')
1763 fprintf(fp_ou, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\">&nbsp;%s</div>\n",LogoImage,Width,Height,LogoText);
dfb337be 1764}
491b862f 1765
2e96438d 1766void write_html_head(FILE *fp_ou, int depth, const char *page_title,int javascript)
491b862f 1767{
9bd92830 1768 int i;
2e96438d 1769
9bd92830
FM
1770 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
1771 fprintf(fp_ou, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
1772 if (page_title) fprintf(fp_ou,"<title>%s</title>\n",page_title);
1773 css(fp_ou);
1774 if ((javascript & HTML_JS_SORTTABLE)!=0 && SortTableJs[0]) {
1775 fputs("<script type=\"text/javascript\" src=\"",fp_ou);
1776 if (strncmp(SortTableJs,"../",3)==0) {
1777 for (i=0 ; i<depth ; i++) fputs("../",fp_ou);
1778 }
1779 fputs(SortTableJs,fp_ou);
1780 fputs("\"></script>\n",fp_ou);
1781 }
1782 fputs("</head>\n<body>\n",fp_ou);
7f2382f6
FM
1783}
1784
2e96438d 1785void write_html_header(FILE *fp_ou, int depth, const char *page_title,int javascript)
7f2382f6 1786{
9bd92830
FM
1787 write_html_head(fp_ou,depth,page_title,javascript);
1788 write_logo_image(fp_ou);
1789 show_sarg(fp_ou, depth);
1790 fprintf(fp_ou,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title);
c0ec9cc7
FM
1791}
1792
1793void close_html_header(FILE *fp_ou)
1794{
9bd92830 1795 fputs("</table></div>\n",fp_ou);
c0ec9cc7
FM
1796}
1797
fa6552b0 1798int write_html_trailer(FILE *fp_ou)
c0ec9cc7 1799{
9bd92830
FM
1800 show_info(fp_ou);
1801 if (fputs("</body>\n</html>\n",fp_ou)==EOF) return(-1);
1802 return(0);
dfb337be
FM
1803}
1804
ac422f9b 1805void output_html_string(FILE *fp_ou,const char *str,int maxlen)
dfb337be 1806{
9bd92830
FM
1807 int i=0;
1808
1809 while (*str && (maxlen<=0 || i<maxlen)) {
1810 switch (*str) {
1811 case '&':
1812 fputs("&amp;",fp_ou);
1813 break;
1814 case '<':
1815 fputs("&lt;",fp_ou);
1816 break;
1817 case '>':
1818 fputs("&gt;",fp_ou);
1819 break;
1820 case '"':
1821 fputs("&quot;",fp_ou);
1822 break;
1823 case '\'':
1824 fputs("&#39;",fp_ou);
1825 break;
1826 default:
1827 fputc(*str,fp_ou);
1828 }
1829 str++;
1830 i++;
1831 }
1832 if (maxlen>0 && i>=maxlen)
1833 fputs("&hellip;",fp_ou);
ac422f9b
FM
1834}
1835
1836void output_html_url(FILE *fp_ou,const char *url)
1837{
9bd92830
FM
1838 while (*url) {
1839 if (*url=='&')
1840 fputs("&amp;",fp_ou);
1841 else
1842 fputc(*url,fp_ou);
1843 url++;
1844 }
491b862f
GS
1845}
1846
67a93701
FM
1847/*!
1848 Write a host name inside an A tag of a HTML file. If the host name starts
1849 with a star, it is assumed to be an alias that cannot be put inside a link
1850 so the A tag is not written around the host name.
b902df7e 1851
67a93701
FM
1852 \param fp_ou The handle of the HTML file.
1853 \param url The host to display in the HTML file.
1854 \param maxlen The maximum number of characters to print into the host name.
1855 */
6fa33a32 1856void output_html_link(FILE *fp_ou,const char *url,int maxlen)
67a93701
FM
1857{
1858 if (url[0]==ALIAS_PREFIX) {
1859 // this is an alias, no need for a A tag
1860 output_html_string(fp_ou,url+1,100);
1861 } else {
6fa33a32
FM
1862 if (skip_scheme(url)==url)
1863 fputs("<a href=\"http://",fp_ou);//no scheme in the url, assume http:// to make the link clickable
1864 else
1865 fputs("<a href=\"",fp_ou);//the scheme is in the url, no need to add one
67a93701
FM
1866 output_html_url(fp_ou,url);
1867 fputs("\">",fp_ou);
1868 output_html_string(fp_ou,url,100);
1869 fputs("</a>",fp_ou);
1870 }
1871}
1872
48864d28 1873void url_module(const char *url, char *w2)
25697a35 1874{
9bd92830
FM
1875 int x, y;
1876 char w[255];
25697a35 1877
9bd92830
FM
1878 y=0;
1879 for(x=strlen(url)-1; x>=0; x--) {
1880 if(url[x] == '/' || y>=sizeof(w)-1) break;
1881 w[y++]=url[x];
1882 }
1883 if (x<0) {
1884 w2[0]='\0';
1885 return;
1886 }
25697a35 1887
9bd92830
FM
1888 x=0;
1889 for(y=y-1; y>=0; y--) {
1890 w2[x++]=w[y];
1891 }
1892 w2[x]='\0';
25697a35
GS
1893}
1894
f72b484a
FM
1895/*!
1896Mangle an URL to produce a part that can be used as an anchor in
1897a html <a name=""> tag.
1898
1899\param url The URL to mangle.
1900\param anchor The buffer to write the mangled URL.
1901\param size The size of the buffer.
1902*/
1903void url_to_anchor(const char *url,char *anchor,int size)
e5b2c6f0 1904{
f72b484a
FM
1905 int i,j;
1906 bool skip;
e5b2c6f0 1907
f72b484a
FM
1908 // find url end
1909 for (i=0 ; url[i] && url[i]!='/' && url[i]!='?' ; i++);
1910 i--;
1911 if (i<=0) {
1912 anchor[0]='\0';
1913 return;
1914 }
1915
1916 // only keep really safe characters
1917 skip=false;
1918 j=size-1;
1919 anchor[j]='\0';
1920 while (j>0 && i>=0)
1921 {
1922 if(isalnum(url[i]) || url[i]=='-' || url[i]=='_' || url[i]=='.') {
1923 anchor[--j]=url[i];
1924 skip=false;
9bd92830 1925 } else {
f72b484a
FM
1926 if (!skip) anchor[--j]='_';
1927 skip=true;
1928 }
1929 i--;
1930 }
1931 if (j>0)
1932 {
1933 while ( anchor[j])
1934 {
1935 *anchor=anchor[j];
1936 anchor++;
9bd92830 1937 }
f72b484a 1938 *anchor='\0';
9bd92830 1939 }
e5b2c6f0 1940}
d6e703cc 1941
32e71fa4 1942void version(void)
25697a35 1943{
9bd92830
FM
1944 printf(_("SARG Version: %s\n"),VERSION);
1945 exit(EXIT_SUCCESS);
25697a35 1946}
5f3cfd1d
FM
1947
1948char *get_param_value(const char *param,char *line)
1949{
9bd92830 1950 int plen;
2357ef77 1951
9bd92830
FM
1952 while (*line==' ' || *line=='\t') line++;
1953 plen=strlen(param);
1954 if (strncasecmp(line,param,plen)) return(NULL);
1955 if (line[plen]!=' ' && line[plen]!='\t') return(NULL);
1956 line+=plen;
1957 while (*line==' ' || *line=='\t') line++;
1958 return(line);
5f3cfd1d 1959}
936c9905 1960
170a77ea 1961void unlinkdir(const char *dir,bool contentonly)
304a739d 1962{
9bd92830
FM
1963 struct stat st;
1964 DIR *dirp;
1965 struct dirent *direntp;
1966 char dname[MAXLEN];
1967 int err;
1968
1969 dirp=opendir(dir);
1970 if (!dirp) return;
1971 while ((direntp = readdir(dirp)) != NULL) {
1972 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
007905af 1973 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
9bd92830
FM
1974 continue;
1975 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
1976 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
1977 exit(EXIT_FAILURE);
1978 }
463f8e09 1979#ifdef HAVE_LSTAT
9bd92830 1980 err=lstat(dname,&st);
463f8e09 1981#else
9bd92830 1982 err=stat(dname,&st);
463f8e09 1983#endif
9bd92830
FM
1984 if (err) {
1985 debuga(_("cannot stat %s\n"),dname);
1986 exit(EXIT_FAILURE);
1987 }
1988 if (S_ISREG(st.st_mode)) {
1989 if (unlink(dname)) {
7c4264ec 1990 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
9bd92830
FM
1991 exit(EXIT_FAILURE);
1992 }
1993 } else if (S_ISDIR(st.st_mode)) {
1994 unlinkdir(dname,0);
1995 } else {
1996 debuga(_("unknown path type %s\n"),dname);
1997 }
1998 }
1999 closedir(dirp);
2000
2001 if (!contentonly) {
2002 if (rmdir(dir)) {
7c4264ec 2003 debuga(_("Cannot delete \"%s\": %s\n"),dir,strerror(errno));
9bd92830
FM
2004 exit(EXIT_FAILURE);
2005 }
2006 }
51465d08 2007}
ac422f9b 2008
170a77ea
FM
2009/*!
2010Delete every file from the temporary directory where sarg is told to store its
2011temporary files.
2012
2013As any stray file left over by a previous run would be included in the report, we
2014must delete every file from the temporary directory before we start processing the logs.
2015
2016But the temporary directory is given by the user either in the configuration file or
2017on the command line. We check that the user didn't give a wrong directory by looking
2018at the files stored in the directory. If a single file is not one of ours, we abort.
2019
2020\param dir The temporary directory to purge.
2021*/
2022void emptytmpdir(const char *dir)
2023{
2024 struct stat st;
2025 DIR *dirp;
2026 struct dirent *direntp;
2027 int dlen;
2028 int elen;
2029 char dname[MAXLEN];
2030 int err;
2031 int i;
2032 static const char *TmpExt[]=
2033 {
2034 ".int_unsort",
2035 ".int_log",
2036 ".day",
2037 "htmlrel.txt",
2038 ".user_unsort",
2039 ".user_log",
2040 ".utmp",
2041 ".ip"
2042 };
2043
2044 dirp=opendir(dir);
2045 if (!dirp) return;
bd43d81f 2046
170a77ea
FM
2047 // make sure the temporary directory contains only our files
2048 while ((direntp = readdir(dirp)) != NULL) {
2049 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2050 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2051 continue;
2052
2053 // is it one of our files
2054 dlen=strlen(direntp->d_name);
2055 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2056 elen=strlen(TmpExt[i]);
2057 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2058 }
2059 if (i<0) {
2060 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2061 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2062 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2063 exit(EXIT_FAILURE);
2064 }
bd43d81f 2065
170a77ea
FM
2066 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2067 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
2068 exit(EXIT_FAILURE);
2069 }
bd43d81f 2070
170a77ea
FM
2071#ifdef HAVE_LSTAT
2072 err=lstat(dname,&st);
2073#else
2074 err=stat(dname,&st);
2075#endif
2076 if (err) {
2077 debuga(_("cannot stat \"%s\"\n"),dname);
2078 exit(EXIT_FAILURE);
2079 }
2080 if (S_ISDIR(st.st_mode)) {
2081 unlinkdir(dname,0);
2082 } else if (!S_ISREG(st.st_mode)) {
6884aba6 2083 debuga(_("Unknown path type for \"%s\". Check temporary directory\n"),dname);
170a77ea
FM
2084 exit(EXIT_FAILURE);
2085 }
2086 }
2087 rewinddir(dirp);
2088
2089 // now delete our files
2090 while ((direntp = readdir(dirp)) != NULL) {
2091 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2092 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2093 continue;
2094
2095 // is it one of our files
2096 dlen=strlen(direntp->d_name);
2097 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2098 elen=strlen(TmpExt[i]);
2099 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2100 }
2101 if (i<0) {
2102 debuga(_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
2103 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2104 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2105 exit(EXIT_FAILURE);
2106 }
bd43d81f 2107
170a77ea
FM
2108 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
2109 debuga(_("directory name to delete too long: %s/%s\n"),dir,direntp->d_name);
2110 exit(EXIT_FAILURE);
2111 }
2112#ifdef HAVE_LSTAT
2113 err=lstat(dname,&st);
2114#else
2115 err=stat(dname,&st);
2116#endif
2117 if (err) {
2118 debuga(_("cannot stat \"%s\"\n"),dname);
2119 exit(EXIT_FAILURE);
2120 }
2121 if (S_ISREG(st.st_mode)) {
2122 if (unlink(dname)) {
2123 debuga(_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
2124 exit(EXIT_FAILURE);
2125 }
2126 } else {
2127 debuga(_("unknown path type %s\n"),dname);
2128 }
2129 }
2130 closedir(dirp);
2131}
2132
5207d9f8
FM
2133/*!
2134 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2135 prefix size.
2136
2137 \param buf The buffer to parse.
2138 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
a16cb22a 2139 The pointer may be NULL.
5207d9f8
FM
2140 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2141 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2142 \param nbits The number of prefix bits for an IP address.
2143 \param next The content of the line after the extracted address.
2144
2145 \retval 3 The pattern is a IPv6 address.
2146 \retval 2 The pattern is a IPv4 address.
2147 \retval 1 The patter is a string.
2148 \retval 0 Empty pattern.
2149 */
7819e0d5 2150int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next)
5207d9f8
FM
2151{
2152 int i;
2153 int j;
2154 int ip_size;
2155 unsigned int value4, value6;
2156 unsigned short int addr[8];
2157 int addr_len;
0ec4b481 2158 int nibble6_len;
5207d9f8
FM
2159 int mask, max_mask;
2160 int pad_pos;
2161 int pad_len;
08eb52bb
FM
2162 bool bracket=false;
2163 bool port=false;
2164 bool port_num=0;
5207d9f8
FM
2165
2166 // skip leading spaces and tabs
2167 while (*buf && (*buf==' ' || *buf=='\t')) buf++;
bd43d81f 2168
5207d9f8
FM
2169 // find out the nature of the pattern
2170 ip_size=0x60 | 0x04;
0ec4b481
FM
2171 if (*buf=='[') {
2172 bracket=true;
2173 ip_size=0x60;
2174 buf++;
2175 }
5207d9f8
FM
2176 value4=0U;
2177 value6=0U;
2178 addr_len=0;
0ec4b481 2179 nibble6_len=0;
5207d9f8 2180 pad_pos=-1;
84aefd39 2181 for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
5207d9f8
FM
2182 if (ip_size & 0x04) {
2183 if (isdigit(buf[i])) {
08eb52bb
FM
2184 if (port) {
2185 port_num=port_num*10+(buf[i]-'0');
2186 if (port_num>65535) ip_size&=~0x04;
2187 } else {
2188 value4=value4*10+(buf[i]-'0');
2189 if (value4>0xFFU) ip_size&=~0x04;
2190 }
5207d9f8
FM
2191 } else if (buf[i]=='.' && addr_len<4) {
2192 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2193 value4=0U;
08eb52bb
FM
2194 } else if (!port && buf[i]==':') {
2195 port=true;
5207d9f8
FM
2196 } else {
2197 ip_size&=~0x04;
2198 }
2199 }
2200 if (ip_size & 0x60) {
2201 if (isdigit(buf[i])) {
2202 value6=(value6<<4)+(buf[i]-'0');
0ec4b481 2203 nibble6_len++;
5207d9f8
FM
2204 if (value6>0xFFFFU) ip_size&=~0x60;
2205 } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') {
2206 value6=(value6<<4)+(toupper(buf[i])-'A'+10);
0ec4b481 2207 nibble6_len++;
5207d9f8
FM
2208 if (value6>0xFFFFU) ip_size&=~0x60;
2209 } else if (buf[i]==':' && addr_len<8) {
0ec4b481
FM
2210 if (nibble6_len>0) {
2211 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2212 nibble6_len=0;
2213 }
5207d9f8 2214 value6=0U;
0ec4b481
FM
2215 if (buf[i+1]==':') {
2216 pad_pos=addr_len;
2217 i++;
2218 }
5207d9f8
FM
2219 } else {
2220 ip_size&=~0x60;
2221 }
2222 }
2223 }
2224 if (i==0) return(0);
2225 if (ip_size & 0x04) {
2226 if (addr_len!=3)
2227 ip_size&=~0x04;
2228 else
2229 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2230 }
2231 if (ip_size & 0x60) {
2232 if (pad_pos<0 && addr_len!=7) {
2233 ip_size&=~0x60;
2234 } else if (pad_pos>=0 && addr_len>=7)
2235 ip_size&=~0x60;
0ec4b481 2236 else if (nibble6_len>0)
5207d9f8
FM
2237 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2238 }
2239 if (!ip_size) {
a16cb22a
FM
2240 if (text) {
2241 *text=buf;
2242 if (bracket) (*text)--;
2243 }
5207d9f8 2244 while ((unsigned char)buf[i]>' ') i++;
7819e0d5 2245 if (next) *next=buf+i;
5207d9f8
FM
2246 return(1);
2247 }
2248 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
2249 if (buf[i]=='/') {
2250 i++;
2251 mask=atoi(buf+i);
2252 while (isdigit(buf[i])) i++;
2253 if (mask<0 || mask>max_mask) mask=max_mask;
2254 } else
2255 mask=max_mask;
0ec4b481 2256 if (ip_size & 0x60 && bracket && buf[i]==']') i++;
7819e0d5 2257 if (next) *next=buf+i;
5207d9f8
FM
2258 if (ip_size & 0x04) {
2259 if (nbits) *nbits=mask;
2260 for (i=0 ; i<addr_len ; i++)
2261 ipv4[i]=(unsigned char)addr[i];
2262 return(2);
2263 }
2264
2265 // IPv6 address
2266 if (nbits) *nbits=mask;
2267 i=0;
2268 j=0;
2269 if (pad_pos>=0) {
2270 while (i<pad_pos)
2271 ipv6[j++]=(unsigned short int)addr[i++];
2272 pad_len=8-addr_len;
0ec4b481 2273 while (j<pad_pos+pad_len)
5207d9f8
FM
2274 ipv6[j++]=0;
2275 }
2276 while (i<addr_len)
2277 ipv6[j++]=(unsigned short int)addr[i++];
2278 return(3);
2279}