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