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