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