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