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