]> git.ipfire.org Git - thirdparty/sarg.git/blame - util.c
Strip suffix length is a global variable
[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*/
510int compare_date(struct tm *date1,struct tm *date2)
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');
991 if (i!=4) continue;
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');
1015 if (i!=4) continue;
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
42b117e3
FM
1043void getperiod_fromrange(struct periodstruct *period,int dfrom,int duntil)
1044{
9bd92830
FM
1045 memset(&period->start,0,sizeof(period->start));
1046 period->start.tm_mday=dfrom%100;
1047 period->start.tm_mon=(dfrom/100)%100-1;
1048 period->start.tm_year=(dfrom/10000)-1900;
42b117e3 1049
9bd92830
FM
1050 memset(&period->end,0,sizeof(period->end));
1051 period->end.tm_mday=duntil%100;
1052 period->end.tm_mon=(duntil/100)%100-1;
1053 period->end.tm_year=(duntil/10000)-1900;
42b117e3
FM
1054}
1055
cc6af460
FM
1056/*!
1057Update the \a main period to encompass the period in \a candidate.
1058*/
1059void getperiod_merge(struct periodstruct *main,struct periodstruct *candidate)
1060{
1061 int cdate;
1062 int mdate;
1063
1064 mdate=(main->start.tm_year)*10000+(main->start.tm_mon)*100+main->start.tm_mday;
1065 cdate=(candidate->start.tm_year)*10000+(candidate->start.tm_mon)*100+candidate->start.tm_mday;
1066 if (cdate<mdate) memcpy(&main->start,&candidate->start,sizeof(struct tm));
1067
1068 mdate=(main->end.tm_year)*10000+(main->end.tm_mon)*100+main->end.tm_mday;
1069 cdate=(candidate->end.tm_year)*10000+(candidate->end.tm_mon)*100+candidate->end.tm_mday;
1070 if (cdate>mdate) memcpy(&main->end,&candidate->end,sizeof(struct tm));
1071}
1072
fa6552b0
FM
1073int getperiod_buildtext(struct periodstruct *period)
1074{
9bd92830
FM
1075 int i;
1076 int range;
1077 char text1[40], text2[40];
1078
81a022d8 1079 if (df=='u') {
9bd92830 1080 i=strftime(text1, sizeof(text1), "%Y %b %d", &period->start);
81a022d8 1081 } else if(df=='e') {
9bd92830 1082 i=strftime(text1, sizeof(text1), "%d %b %Y", &period->start);
81a022d8 1083 } else /*if (df=='w')*/ {
9bd92830
FM
1084 IndexTree=INDEX_TREE_FILE;
1085 i=strftime(text1, sizeof(text1), "%Y.%U", &period->start);
1086 }
1087 if (i == 0) return(-1);
1088
1089 range=(period->start.tm_year!=period->end.tm_year ||
007905af
FM
1090 period->start.tm_mon!=period->end.tm_mon ||
1091 period->start.tm_mday!=period->end.tm_mday);
9bd92830 1092 if (range) {
81a022d8 1093 if (df=='u') {
9bd92830 1094 i=strftime(text2, sizeof(text2)-i, "%Y %b %d", &period->end);
81a022d8 1095 } else if (df=='e') {
9bd92830
FM
1096 i=strftime(text2, sizeof(text2)-i, "%d %b %Y", &period->end);
1097 } else {
1098 i=strftime(text2, sizeof(text2)-i, "%Y.%U", &period->end);
1099 }
1100 if (i == 0) return(-1);
1101 }
1102
1103 if (range) {
1104 snprintf(period->text,sizeof(period->text),"%s-%s",text1,text2);
1105 snprintf(period->html,sizeof(period->html),"%s&mdash;%s",text1,text2);
1106 } else {
a87d4d11
FM
1107 safe_strcpy(period->text,text1,sizeof(period->text));
1108 safe_strcpy(period->html,text1,sizeof(period->html));
9bd92830
FM
1109 }
1110 return(0);
25697a35
GS
1111}
1112
06ced858 1113static void copy_images(void)
25697a35 1114{
9bd92830
FM
1115 FILE *img_in, *img_ou;
1116 char images[512];
9bd92830
FM
1117 char srcfile[MAXLEN];
1118 char dstfile[MAXLEN];
1119 DIR *dirp;
1120 struct dirent *direntp;
1121 char buffer[MAXLEN];
1122 size_t nread;
1123 struct stat info;
1124
1125 if (snprintf(images,sizeof(images),"%simages",outdir)>=sizeof(images)) {
af961877 1126 debuga(__FILE__,__LINE__,_("Cannot copy images to target directory %simages\n"),outdir);
9bd92830
FM
1127 exit(EXIT_FAILURE);
1128 }
1129 if (access(images,R_OK)!=0) {
7a9d0965 1130 if (PortableMkDir(images,0755)) {
af961877 1131 debuga(__FILE__,__LINE__,_("Cannot create directory \"%s\": %s\n"),images,strerror(errno));
affa72c5
FM
1132 exit(EXIT_FAILURE);
1133 }
9bd92830
FM
1134 }
1135
66f507aa 1136 dirp = opendir(ImageDir);
9bd92830 1137 if(dirp==NULL) {
af961877 1138 debuga(__FILE__,__LINE__,_("Cannot open directory \"%s\": %s\n"),ImageDir,strerror(errno));
9bd92830
FM
1139 return;
1140 }
1141 while ((direntp = readdir( dirp )) != NULL ){
1142 if(direntp->d_name[0]=='.')
1143 continue;
66f507aa 1144 if (snprintf(srcfile,sizeof(srcfile),"%s/%s",ImageDir,direntp->d_name)>=sizeof(srcfile)) {
af961877 1145 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
041018b6 1146 debuga_more("%s/%s",ImageDir,direntp->d_name);
60ec7f09
FM
1147 exit(EXIT_FAILURE);
1148 }
9bd92830 1149 if (stat(srcfile,&info)) {
af961877 1150 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),srcfile,strerror(errno));
9bd92830
FM
1151 continue;
1152 }
1153 if (S_ISREG(info.st_mode)) {
60ec7f09 1154 if (snprintf(dstfile,sizeof(dstfile),"%s/%s",images,direntp->d_name)>=sizeof(dstfile)) {
af961877 1155 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
041018b6 1156 debuga_more("%s/%s",images,direntp->d_name);
60ec7f09
FM
1157 exit(EXIT_FAILURE);
1158 }
9bd92830
FM
1159 img_in = fopen(srcfile, "rb");
1160 if(img_in!=NULL) {
1161 img_ou = fopen(dstfile, "wb");
1162 if(img_ou!=NULL) {
1163 while ((nread = fread(buffer,1,sizeof(buffer),img_in))>0) {
1164 if (fwrite(buffer,1,nread,img_ou)!=nread) {
af961877 1165 debuga(__FILE__,__LINE__,_("Failed to copy image %s to %s\n"),srcfile,dstfile);
9bd92830
FM
1166 break;
1167 }
1168 }
507460ae 1169 if (fclose(img_ou)==EOF) {
af961877 1170 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),dstfile,strerror(errno));
507460ae
FM
1171 exit(EXIT_FAILURE);
1172 }
9bd92830 1173 } else
af961877 1174 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"), dstfile, strerror(errno));
204781f4 1175 if (fclose(img_in)==EOF) {
af961877 1176 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),srcfile,strerror(errno));
204781f4
FM
1177 exit(EXIT_FAILURE);
1178 }
9bd92830 1179 } else
af961877 1180 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"), srcfile, strerror(errno));
9bd92830
FM
1181 }
1182 }
1183 (void) closedir(dirp);
1184
1185 return;
06ced858
FM
1186}
1187
0971b2d6
FM
1188/*!
1189 * Check if the proposed file name conforms to the directory structure layed out
1190 * as a file tree. It is used to check if the file name enumerated while scanning
1191 * a directory content may have been created by sarg running with IndexTree set to
1192 * INDEX_TREE_FILE.
1193 */
1194bool IsTreeFileDirName(const char *Name)
1195{
1196 char DateFormat;
1197 int i;
1198
1199 // start year (date format u) or start day (date format e)
1200 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1201
1202 if (isdigit(Name[2]) && isdigit(Name[3]))
1203 {
1204 // date format is either u or w
1205 if (Name[4]=='.')
1206 {
1207 // date format is w
1208 if (!isdigit(Name[5]) || !isdigit(Name[6])) return(false);
1209 return(true);//date format w is confirmed
1210 }
1211
1212 // date format is u
1213 Name+=4;
1214
1215 // start month
1216 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1217 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1218 if (i<0) return(false);
1219 Name+=3;
1220
1221 // start day
1222 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1223 Name+=2;
1224
1225 DateFormat='u';
1226 }
1227 else if (isalpha(Name[2]) && isalpha(Name[3]) && isalpha(Name[4]))
1228 {
1229 // date format is e
1230 Name+=2;
1231
1232 // start month
1233 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1234 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1235 if (i<0) return(false);
1236 Name+=3;
1237
1238 // start day
1239 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1240 Name+=4;
1241
1242 DateFormat='e';
1243 }
1244 else
1245 return(false);
1246
1247 if (Name[0]!='-') return(false);
1248 Name++;
1249
1250 if (DateFormat=='u')
1251 {
1252 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1253 Name+=4;
1254
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 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1261 Name+=2;
1262 }
1263 else //DateFormat=='e'
1264 {
1265 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1266 Name+=2;
1267
1268 if (!isalpha(Name[0]) || !isalpha(Name[1]) || !isalpha(Name[2])) return(false);
1269 for (i=11 ; i>=0 && memcmp(mtab1[i],Name,3) ; i--);
1270 if (i<0) return(false);
1271 Name+=3;
1272
1273 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1274 Name+=4;
1275 }
1276 /*
16c12388
FM
1277 * The directory name may contains additional characters such as a counter if
1278 * a previous report is never overwritten.
1279 */
1280 return(true);
1281}
1282
1283/*!
1284 * Check if the proposed file name can be the year part of a report tree build with
1285 * IndexTree set to INDEX_TREE_DATE.
1286 */
1287bool IsTreeYearFileName(const char *Name)
1288{
1289 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1290 Name+=4;
1291 if (Name[0]=='-')
1292 {
1293 Name++;
1294 if (!isdigit(Name[0]) || !isdigit(Name[1]) || !isdigit(Name[2]) || !isdigit(Name[3])) return(false);
1295 Name+=4;
1296 }
1297 if (Name[0]) return(false);
1298 return(true);
1299}
1300
1301/*!
1302 * Check if the proposed file name can be the month part of a report tree build with
1303 * IndexTree set to INDEX_TREE_DATE.
1304 */
1305bool IsTreeMonthFileName(const char *Name)
1306{
1307 int m;
1308
1309 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1310 m=(Name[0]-'0')*10+(Name[1]-'0');
1311 if (m<1 || m>12) return(false);
1312 Name+=2;
1313 if (Name[0]=='-')
1314 {
1315 Name++;
1316 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1317 m=(Name[0]-'0')*10+(Name[1]-'0');
1318 if (m<1 || m>12) return(false);
1319 Name+=2;
1320 }
1321 if (Name[0]) return(false);
1322 return(true);
1323}
1324
1325/*!
1326 * Check if the proposed file name can be the day part of a report tree build with
1327 * IndexTree set to INDEX_TREE_DATE.
1328 */
1329bool IsTreeDayFileName(const char *Name)
1330{
1331 int d;
1332
1333 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1334 d=(Name[0]-'0')*10+(Name[1]-'0');
1335 if (d<1 || d>31) return(false);
1336 if (Name[2]=='-')
1337 {
1338 Name+=3;
1339 if (!isdigit(Name[0]) || !isdigit(Name[1])) return(false);
1340 d=(Name[0]-'0')*10+(Name[1]-'0');
1341 if (d<1 || d>31) return(false);
1342 }
1343 /*
1344 * The directory name may contains additional characters such as a counter if
1345 * a previous report is never overwritten.
0971b2d6
FM
1346 */
1347 return(true);
1348}
1349
b2c1a7b4
FM
1350/*!
1351 * Create a directory to generate a report for the specified connection data
1352 * and populate it with the a <tt>sarg-date</tt> file containing the current
1353 * date.
1354 *
1355 * The function also create an <tt>images</tt> directory in \a dir and copy all
1356 * the files from the <tt>SYSCONFDIR/images</tt> into that directory.
1357 *
1358 * \param per1 The date range in the form: YYYYMMMDD-YYYYMMMDD or DDMMMYYYY-DDMMMYYYY depending on the value of
1359 * ::DateFormat.
1360 * \param addr The ip address or host name to which the report is limited. If the string is empty, all the addresses are accepted.
1361 * \param site The destination site to which the report is limited. If the string is empty, all the sites are accepted.
1362 * \param us The user to whom the report is limited. It is an empty string if all the users are accepted.
1363 */
1364int vrfydir(const struct periodstruct *per1, const char *addr, const char *site, const char *us)
06ced858 1365{
9bd92830 1366 FILE *fp_ou;
9bd92830 1367 char wdir[MAXLEN];
9bd92830
FM
1368 int y1, y2;
1369 int m1, m2;
1370 int d1, d2;
1371 int wlen, wlen2;
1372 time_t curtime;
1373 struct tm *loctm;
1374
1375 strcpy(wdir,outdir);
1376 wlen=strlen(wdir);
1377 y1=per1->start.tm_year+1900;
1378 y2=per1->end.tm_year+1900;
1379 m1=per1->start.tm_mon+1;
1380 m2=per1->end.tm_mon+1;
1381 d1=per1->start.tm_mday;
1382 d2=per1->end.tm_mday;
1383 if(IndexTree == INDEX_TREE_DATE) {
1384 wlen+=sprintf(wdir+wlen,"%04d",y1);
1385 if(y1!=y2) wlen+=sprintf(wdir+wlen,"-%04d",y2);
1386 if(access(wdir, R_OK) != 0)
1387 my_mkdir(wdir);
1388
1389 wlen+=sprintf(wdir+wlen,"/%02d",m1);
1390 if(m1 != m2) wlen+=sprintf(wdir+wlen,"-%02d",m2);
1391 if(access(wdir, R_OK) != 0)
1392 my_mkdir(wdir);
1393
1394 wlen+=sprintf(wdir+wlen,"/%02d",d1);
1395 if(d1!=d2) wlen+=sprintf(wdir+wlen,"-%02d",d2);
1396 } else {
81a022d8 1397 if (df == 'u') {
9bd92830 1398 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%04d%s%02d-%04d%s%02d",y1,
007905af 1399 conv_month_name(m1),d1,y2,conv_month_name(m2),d2);
81a022d8 1400 } else if (df == 'e') {
9bd92830 1401 wlen=snprintf(wdir+wlen,sizeof(wdir)-wlen,"%02d%s%04d-%02d%s%04d",d1,
007905af 1402 conv_month_name(m1),y1,d2,conv_month_name(m2),y2);
81a022d8 1403 } else if (df == 'w') {
9bd92830
FM
1404 wlen2=strftime(wdir+wlen, sizeof(wdir)-wlen, "%Y.%U", &per1->start);
1405 if (wlen2==0) return(-1);
1406 wlen+=wlen2;
1407 }
1408 }
1409
1410 if(us[0] != '\0') {
1411 struct userinfostruct *uinfo=userinfo_find_from_id(us);
1412 if (uinfo) {
1413 strcat(wdir,"-");
1414 strcat(wdir,uinfo->filename);
1415 }
1416 }
1417 if(addr[0] != '\0') {
1418 strcat(wdir,"-");
1419 strcat(wdir,addr);
1420 }
1421 if(site[0] != '\0') {
1422 strcat(wdir,"-");
1423 strcat(wdir,site);
1424 }
1425
1426 strcpy(outdirname,wdir);
1427
b2c1a7b4
FM
1428 // manufacture a new unique name if configured to keep old reports or overwrite old report if configured to do so
1429 if (!OverwriteReport) {
1430 int num=1;
9bd92830 1431
b2c1a7b4
FM
1432 while (access(wdir,R_OK)==0 || errno==EACCES) //file exist or can't be read
1433 {
1434 sprintf(wdir,"%s.%d",outdirname,num);
1435 num++;
1436 }
1437 if (num>1) {
1438 if(debug)
1439 debuga(__FILE__,__LINE__,_("File %s already exists, moved to %s\n"),outdirname,wdir);
1440 rename(outdirname,wdir);
9bd92830 1441 }
9bd92830 1442 } else {
b2c1a7b4
FM
1443 if(access(outdirname,R_OK) == 0) {
1444 unlinkdir(outdirname,1);
9bd92830 1445 }
9bd92830 1446 }
b2c1a7b4 1447 my_mkdir(outdirname);
9bd92830 1448
b2c1a7b4 1449 // create sarg-date to keep track of the report creation date
60ec7f09 1450 if (snprintf(wdir,sizeof(wdir),"%s/sarg-date",outdirname)>=sizeof(wdir)) {
af961877 1451 debuga(__FILE__,__LINE__,_("Buffer too small to store "));
041018b6 1452 debuga_more("%s/sarg-date",outdirname);
60ec7f09
FM
1453 exit(EXIT_FAILURE);
1454 }
9bd92830 1455 if ((fp_ou = fopen(wdir, "wt")) == 0) {
af961877 1456 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),wdir,strerror(errno));
9bd92830
FM
1457 perror("SARG:");
1458 exit(EXIT_FAILURE);
1459 }
1460 time(&curtime);
1461 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1462 loctm=localtime(&curtime);
1463 strftime(wdir,sizeof(wdir),"%Y-%m-%d %H:%M:%S",loctm);
1464 if (fprintf(fp_ou,"%s %d\n",wdir,loctm->tm_isdst)<0) {
af961877 1465 debuga(__FILE__,__LINE__,_("Failed to write the date in %s\n"),wdir);
9bd92830
FM
1466 perror("SARG:");
1467 exit(EXIT_FAILURE);
1468 }
1469 if (fclose(fp_ou)==EOF) {
af961877 1470 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),wdir,strerror(errno));
9bd92830
FM
1471 exit(EXIT_FAILURE);
1472 }
1473
1474 copy_images();
1475 return(0);
25697a35
GS
1476}
1477
a87d4d11
FM
1478/*!
1479 Copy a string without overflowing the buffer. The copied string
1480 is properly terminated by an ASCII zero.
b902df7e 1481
a87d4d11
FM
1482 \param dest The destination buffer.
1483 \param src The source buffer.
1484 \param length The size of the destination buffer. The program is aborted
1485 if the length is negative or zero.
1486*/
1487void safe_strcpy(char *dest,const char *src,int length)
1488{
1489 if (length<=0) {
af961877 1490 debuga(__FILE__,__LINE__,_("Invalid buffer length passed to the function to safely copy a string\n"));
a87d4d11
FM
1491 exit(EXIT_FAILURE);
1492 }
1493 strncpy(dest,src,length-1);
1494 dest[length-1]='\0';
1495}
1496
25697a35
GS
1497void strip_latin(char *line)
1498{
9bd92830
FM
1499 int i,j;
1500 int skip;
1501
1502 j=0;
1503 skip=0;
1504 for (i=0;line[i];i++){
1505 if (skip){
1506 if (line[i]==';') skip=0;
1507 } else {
1508 if (line[i]=='&')
1509 skip=1;
1510 else
1511 line[j++]=line[i];
1512 }
1513 }
1514 line[j]='\0';
1515 return;
25697a35
GS
1516}
1517
81a022d8 1518void zdate(char *ftime,int ftimesize, char DateFormat)
25697a35 1519{
9bd92830
FM
1520 time_t t;
1521 struct tm *local;
25697a35 1522
9bd92830
FM
1523 t = time(NULL);
1524 local = localtime(&t);
81a022d8 1525 if (DateFormat=='u')
9bd92830 1526 strftime(ftime, ftimesize, "%b/%d/%Y %H:%M", local);
81a022d8 1527 else if (DateFormat=='e')
9bd92830 1528 strftime(ftime, ftimesize, "%d/%b/%Y-%H:%M", local);
81a022d8 1529 else if (DateFormat=='w')
9bd92830
FM
1530 strftime(ftime, ftimesize, "%W-%H-%M", local);
1531 return;
25697a35
GS
1532}
1533
1534
324ba7f3 1535char *fixtime(long long int elap)
25697a35 1536{
60ec7f09 1537 long int num = elap / 1000LL;
9bd92830
FM
1538 int hor = 0;
1539 int min = 0;
1540 int sec = 0;
60ec7f09 1541 static char buf[20];
25697a35 1542
60ec7f09
FM
1543 hor=num / 3600L;
1544 min=(num % 3600L) / 60L;
1545 sec=num % 60L;
25697a35 1546
9bd92830
FM
1547 if(hor==0 && min==0 && sec==0)
1548 strcpy(buf,"0");
1549 else
60ec7f09 1550 snprintf(buf,sizeof(buf),"%d:%02d:%02d",hor,min,sec);
25697a35 1551
9bd92830 1552 return buf;
25697a35
GS
1553}
1554
1555
60ec7f09 1556void date_from(char *date,int date_size, int *dfrom, int *duntil)
25697a35 1557{
9bd92830
FM
1558 int d0=0;
1559 int m0=0;
1560 int y0=0;
1561 int d1=0;
1562 int m1=0;
1563 int y1=0;
1564
1565 if (isdigit(date[0])) {
1566 int next=-1;
1567
1568 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 1569 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
1570 exit(EXIT_FAILURE);
1571 }
1572 if (date[next]=='-') {
1573 if (sscanf(date+next+1,"%d/%d/%d",&d1,&m1,&y1)!=3 || y1<100 || m1<1 || m1>12 || d1<1 || d1>31) {
af961877 1574 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
1575 exit(EXIT_FAILURE);
1576 }
1577 } else if (date[next]!='\0') {
af961877 1578 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
1579 exit(EXIT_FAILURE);
1580 } else {
1581 d1=d0;
1582 m1=m0;
1583 y1=y0;
1584 }
1585 } else {
1586 int i;
1587 time_t Today,t1;
1588 struct tm *Date0,Date1;
1589
1590 if (time(&Today)==(time_t)-1) {
af961877 1591 debuga(__FILE__,__LINE__,_("Failed to get the current time\n"));
9bd92830
FM
1592 exit(EXIT_FAILURE);
1593 }
1594 if (sscanf(date,"day-%d",&i)==1) {
1595 if (i<0) {
af961877 1596 debuga(__FILE__,__LINE__,_("Invalid number of days in -d parameter\n"));
9bd92830
FM
1597 exit(EXIT_FAILURE);
1598 }
1599 Today-=i*24*60*60;
1600 Date0=localtime(&Today);
1601 if (Date0==NULL) {
af961877 1602 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
9bd92830
FM
1603 exit(EXIT_FAILURE);
1604 }
1605 y0=y1=Date0->tm_year+1900;
1606 m0=m1=Date0->tm_mon+1;
1607 d0=d1=Date0->tm_mday;
1608 } else if (sscanf(date,"week-%d",&i)==1) {
1609 /*
1610 There is no portable way to find the first day of the week even though the
1611 information is available in the locale. nl_langinfo has the unofficial
1612 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1613 undocumented as is their return value and it is discouraged to use them.
1614 Beside, nl_langinfo isn't available on windows and the first day of the
1615 week isn't available at all on that system.
1616 */
1617 const int FirstWeekDay=1;
1618 time_t WeekBegin;
1619
1620 if (i<0) {
af961877 1621 debuga(__FILE__,__LINE__,_("Invalid number of weeks in -d parameter\n"));
9bd92830
FM
1622 exit(EXIT_FAILURE);
1623 }
1624 Date0=localtime(&Today);
1625 if (Date0==NULL) {
af961877 1626 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
9bd92830
FM
1627 exit(EXIT_FAILURE);
1628 }
1629 WeekBegin=Today-((Date0->tm_wday-FirstWeekDay+7)%7)*24*60*60;
1630 WeekBegin-=i*7*24*60*60;
1631 Date0=localtime(&WeekBegin);
1632 if (Date0==NULL) {
af961877 1633 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
9bd92830
FM
1634 exit(EXIT_FAILURE);
1635 }
1636 y0=Date0->tm_year+1900;
1637 m0=Date0->tm_mon+1;
1638 d0=Date0->tm_mday;
1639 WeekBegin+=6*24*60*60;
1640 Date0=localtime(&WeekBegin);
1641 if (Date0==NULL) {
af961877 1642 debuga(__FILE__,__LINE__,_("Cannot convert local time: %s\n"),strerror(errno));
9bd92830
FM
1643 exit(EXIT_FAILURE);
1644 }
1645 y1=Date0->tm_year+1900;
1646 m1=Date0->tm_mon+1;
1647 d1=Date0->tm_mday;
1648 } else if (sscanf(date,"month-%d",&i)==1) {
1649 if (i<0) {
af961877 1650 debuga(__FILE__,__LINE__,_("Invalid number of months in -d parameter\n"));
9bd92830
FM
1651 exit(EXIT_FAILURE);
1652 }
1653 Date0=localtime(&Today);
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 if (Date0->tm_mon<i%12) {
1659 y0=Date0->tm_year+1900-i/12-1;
1660 m0=(Date0->tm_mon+12-i%12)%12+1;
1661 d0=1;
1662 } else {
1663 y0=Date0->tm_year+1900-i/12;
1664 m0=Date0->tm_mon-i%12+1;
1665 d0=1;
1666 }
1667 memcpy(&Date1,Date0,sizeof(struct tm));
1668 Date1.tm_isdst=-1;
1669 Date1.tm_mday=1;
1670 if (m0<12) {
1671 Date1.tm_mon=m0;
1672 Date1.tm_year=y0-1900;
1673 } else {
1674 Date1.tm_mon=0;
1675 Date1.tm_year=y0-1900+1;
1676 }
1677 t1=mktime(&Date1);
1678 t1-=24*60*60;
1679 Date0=localtime(&t1);
1680 y1=Date0->tm_year+1900;
1681 m1=Date0->tm_mon+1;
1682 d1=Date0->tm_mday;
1683 } else {
af961877 1684 debuga(__FILE__,__LINE__,_("Invalid date range passed on command line\n"));
9bd92830
FM
1685 exit(EXIT_FAILURE);
1686 }
1687 }
1688
1689 *dfrom=y0*10000+m0*100+d0;
1690 *duntil=y1*10000+m1*100+d1;
60ec7f09 1691 snprintf(date,date_size,"%02d/%02d/%04d-%02d/%02d/%04d",d0,m0,y0,d1,m1,y1);
9bd92830 1692 return;
25697a35
GS
1693}
1694
1695
1696char *strlow(char *string)
1697{
9bd92830 1698 char *s;
25697a35 1699
9bd92830
FM
1700 if (string)
1701 {
1702 for (s = string; *s; ++s)
1703 *s = tolower(*s);
1704 }
25697a35 1705
9bd92830 1706 return string;
25697a35
GS
1707}
1708
1709
1710
1711
1712char *strup(char *string)
1713{
9bd92830 1714 char *s;
25697a35 1715
9bd92830
FM
1716 if (string)
1717 {
1718 for (s = string; *s; ++s)
1719 *s = toupper(*s);
1720 }
25697a35 1721
9bd92830 1722 return string;
25697a35
GS
1723}
1724
1725
32e71fa4 1726void removetmp(const char *outdir)
25697a35 1727{
9dc20988
FM
1728 FILE *fp_gen;
1729 char filename[256];
9bd92830
FM
1730
1731 if(!RemoveTempFiles)
1732 return;
1733
1734 if(debug) {
af961877 1735 debuga(__FILE__,__LINE__,_("Purging temporary file sarg-general\n"));
9bd92830 1736 }
9dc20988 1737 if (snprintf(filename,sizeof(filename),"%s/sarg-general",outdir)>=sizeof(filename)) {
af961877 1738 debuga(__FILE__,__LINE__,_("Path too long: "));
041018b6 1739 debuga_more("%s/sarg-period\n",outdir);
9bd92830
FM
1740 exit(EXIT_FAILURE);
1741 }
9dc20988 1742 if((fp_gen=fopen(filename,"w"))==NULL){
af961877 1743 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),filename,strerror(errno));
9bd92830
FM
1744 exit(EXIT_FAILURE);
1745 }
9dc20988
FM
1746 totalger(fp_gen,filename);
1747 if (fclose(fp_gen)==EOF) {
af961877 1748 debuga(__FILE__,__LINE__,_("Write error in \"%s\": %s\n"),filename,strerror(errno));
9bd92830
FM
1749 exit(EXIT_FAILURE);
1750 }
25697a35
GS
1751}
1752
48864d28 1753void load_excludecodes(const char *ExcludeCodes)
25697a35 1754{
9bd92830
FM
1755 FILE *fp_in;
1756 char data[80];
1757 int i;
1758 int Stored;
1759 long int MemSize;
1760
1761 if(ExcludeCodes[0] == '\0')
1762 return;
1763
1764 if((fp_in=fopen(ExcludeCodes,"r"))==NULL) {
af961877 1765 debuga(__FILE__,__LINE__,_("Cannot open file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
9bd92830
FM
1766 exit(EXIT_FAILURE);
1767 }
1768
1769 if (fseek(fp_in, 0, SEEK_END)==-1) {
af961877 1770 debuga(__FILE__,__LINE__,_("Failed to move till the end of file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
9bd92830
FM
1771 exit(EXIT_FAILURE);
1772 }
1773 MemSize = ftell(fp_in);
1774 if (MemSize<0) {
af961877 1775 debuga(__FILE__,__LINE__,_("Cannot get the size of file \"%s\"\n"),ExcludeCodes);
9bd92830
FM
1776 exit(EXIT_FAILURE);
1777 }
1778 if (fseek(fp_in, 0, SEEK_SET)==-1) {
af961877 1779 debuga(__FILE__,__LINE__,_("Failed to rewind file \"%s\": %s\n"),ExcludeCodes,strerror(errno));
9bd92830
FM
1780 exit(EXIT_FAILURE);
1781 }
1782
1783 MemSize+=1;
1784 if((excludecode=(char *) malloc(MemSize))==NULL) {
af961877 1785 debuga(__FILE__,__LINE__,_("malloc error (%ld bytes required)\n"),MemSize);
9bd92830
FM
1786 exit(EXIT_FAILURE);
1787 }
1788 memset(excludecode,0,MemSize);
1789
1790 Stored=0;
1791 while(fgets(data,sizeof(data),fp_in)!=NULL) {
1792 if (data[0]=='#') continue;
1793 for (i=strlen(data)-1 ; i>=0 && (unsigned char)data[i]<=' ' ; i--) data[i]='\0';
1794 if (i<0) continue;
1795 if (Stored+i+2>=MemSize) {
af961877 1796 debuga(__FILE__,__LINE__,_("Too many codes to exclude in file \"%s\"\n"),ExcludeCodes);
9bd92830
FM
1797 break;
1798 }
1799 strcat(excludecode,data);
1800 strcat(excludecode,";");
1801 Stored+=i+1;
1802 }
1803
204781f4 1804 if (fclose(fp_in)==EOF) {
af961877 1805 debuga(__FILE__,__LINE__,_("Read error in \"%s\": %s\n"),ExcludeCodes,strerror(errno));
204781f4
FM
1806 exit(EXIT_FAILURE);
1807 }
9bd92830 1808 return;
25697a35
GS
1809}
1810
48864d28
FM
1811void free_excludecodes(void)
1812{
9bd92830
FM
1813 if (excludecode) {
1814 free(excludecode);
1815 excludecode=NULL;
1816 }
48864d28
FM
1817}
1818
32e71fa4 1819int vercode(const char *code)
25697a35 1820{
9bd92830
FM
1821 char *cod;
1822 int clen;
48864d28 1823
9bd92830
FM
1824 if (excludecode && excludecode[0]!='\0') {
1825 clen=strlen(code);
1826 cod=excludecode;
1827 while (cod) {
1828 if (strncmp(code,cod,clen)==0 && cod[clen]==';')
1829 return 1;
1830 cod=strchr(cod,';');
1831 if (cod) cod++;
1832 }
1833 }
1834 return 0;
25697a35
GS
1835}
1836
1837void fixnone(char *str)
1838{
9bd92830 1839 int i;
32e71fa4 1840
9bd92830
FM
1841 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--);
1842 if(i==3 && strncmp(str,"none",4) == 0)
1843 str[0]='\0';
25697a35 1844
9bd92830 1845 return;
25697a35
GS
1846}
1847
2357ef77
FM
1848void fixendofline(char *str)
1849{
9bd92830 1850 int i;
2357ef77 1851
9bd92830 1852 for (i=strlen(str)-1 ; i>=0 && (unsigned char)str[i]<=' ' ; i--) str[i]=0;
2357ef77
FM
1853}
1854
25697a35 1855#ifdef LEGACY_TESTVALIDUSERCHAR
32e71fa4 1856int testvaliduserchar(const char *user)
25697a35 1857{
9bd92830
FM
1858 int x=0;
1859 int y=0;
25697a35 1860
9bd92830
FM
1861 for (y=0; y<strlen(UserInvalidChar); y++) {
1862 for (x=0; x<strlen(user); x++) {
1863 if(user[x] == UserInvalidChar[y])
1864 return 1;
1865 }
1866 }
1867 return 0;
25697a35
GS
1868}
1869#else
32e71fa4 1870int testvaliduserchar(const char *user)
25697a35 1871{
9bd92830
FM
1872 char * p_UserInvalidChar = UserInvalidChar ;
1873 const char * p_user ;
25697a35 1874
9bd92830
FM
1875 while( *p_UserInvalidChar ) {
1876 p_user = user ;
1877 while ( *p_user ) {
1878 if( *p_UserInvalidChar == *p_user )
1879 return 1;
1880 p_user++ ;
1881 }
1882 p_UserInvalidChar++ ;
1883 }
1884 return 0;
25697a35
GS
1885}
1886#endif
1887
1888int compar( const void *a, const void *b )
9bd92830
FM
1889{
1890 if( *(int *)a > *(int *)b ) return 1;
1891 if( *(int *)a < *(int *)b ) return -1;
1892 return 0;
25697a35
GS
1893}
1894
1895int getnumlist( char *buf, numlist *list, const int len, const int maxvalue )
48864d28 1896{
9bd92830
FM
1897 int i, j, d, flag, r1, r2;
1898 char *pbuf, **bp, *strbufs[ 24 ];
1899
1900 bp = strbufs;
1901 strtok( buf, " \t" );
1902 for( *bp = strtok( NULL, "," ), list->len = 0; *bp; *bp = strtok( NULL, "," ) ) {
1903 if( ++bp >= &strbufs[ 24 ] )
1904 break;
1905 list->len++;
1906 }
1907 if( ! list->len )
1908 return -1;
1909 d = 0;
1910 for( i = 0; i < list->len; i++ ) {
1911 if( strchr( strbufs[ i ], '-' ) != 0 ) {
1912 pbuf = strbufs[ i ];
1913 strtok( pbuf, "-" );
1914 pbuf = strtok( NULL, "\0" );
1915 r1 = atoi( strbufs[ i ] );
1916 if( ( r2 = atoi( pbuf ) ) >= maxvalue || r1 >= r2 )
1917 return -1;
1918 if( i + d + ( r2 - r1 ) + 1 <= len ) {
1919 for( j = r1; j <= r2; j++ )
1920 list->list[ i + d++ ] = j;
1921 d--;
1922 }
1923 }
1924 else
1925 if( ( list->list[ i + d ] = atoi( strbufs[ i ] ) ) >= maxvalue )
1926 return 1;
1927 }
1928 list->len += d;
1929 qsort( list->list, list->len, sizeof( int ), compar );
1930 do {
1931 flag = 0;
1932 for( i = 0; i < list->len - 1; i++ )
1933 if( list->list[ i ] == list->list[ i + 1 ] ) {
1934 for( j = i + 1; j < list->len; j++ )
1935 list->list[ j - 1 ] = list->list[ j ];
1936 list->len--;
1937 flag = 1;
1938 break;
1939 }
1940 } while( flag );
1941 return 0;
25697a35
GS
1942}
1943
dfb337be
FM
1944void show_info(FILE *fp_ou)
1945{
9bd92830 1946 char ftime[127];
dfb337be 1947
9bd92830 1948 if(!ShowSargInfo) return;
81a022d8 1949 zdate(ftime, sizeof(ftime), df);
b3a3c51c 1950 fputs("<div class=\"info\">",fp_ou);
05a933cc 1951 fprintf(fp_ou,_("Generated by <a href=\"%s\">%s-%s</a> on %s"),URL,PGM,VERSION,ftime);
b3a3c51c 1952 fputs("</div>\n",fp_ou);
dfb337be
FM
1953}
1954
c0ec9cc7 1955void show_sarg(FILE *fp_ou, int depth)
dfb337be 1956{
9bd92830 1957 int i;
c0ec9cc7 1958
9bd92830
FM
1959 if(!ShowSargLogo) return;
1960 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou);
1961 for (i=0 ; i<depth ; i++)
1962 fputs("../",fp_ou);
1963 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
1964}
1965
1966void write_logo_image(FILE *fp_ou)
1967{
9bd92830
FM
1968 if(LogoImage[0]!='\0')
1969 fprintf(fp_ou, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\">&nbsp;%s</div>\n",LogoImage,Width,Height,LogoText);
dfb337be 1970}
491b862f 1971
2e96438d 1972void write_html_head(FILE *fp_ou, int depth, const char *page_title,int javascript)
491b862f 1973{
9bd92830 1974 int i;
2e96438d 1975
9bd92830
FM
1976 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou);
1977 fprintf(fp_ou, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet);
1978 if (page_title) fprintf(fp_ou,"<title>%s</title>\n",page_title);
1979 css(fp_ou);
1980 if ((javascript & HTML_JS_SORTTABLE)!=0 && SortTableJs[0]) {
1981 fputs("<script type=\"text/javascript\" src=\"",fp_ou);
1982 if (strncmp(SortTableJs,"../",3)==0) {
1983 for (i=0 ; i<depth ; i++) fputs("../",fp_ou);
1984 }
1985 fputs(SortTableJs,fp_ou);
1986 fputs("\"></script>\n",fp_ou);
1987 }
1988 fputs("</head>\n<body>\n",fp_ou);
7f2382f6
FM
1989}
1990
2e96438d 1991void write_html_header(FILE *fp_ou, int depth, const char *page_title,int javascript)
7f2382f6 1992{
9bd92830
FM
1993 write_html_head(fp_ou,depth,page_title,javascript);
1994 write_logo_image(fp_ou);
1995 show_sarg(fp_ou, depth);
1996 fprintf(fp_ou,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title);
c0ec9cc7
FM
1997}
1998
1999void close_html_header(FILE *fp_ou)
2000{
9bd92830 2001 fputs("</table></div>\n",fp_ou);
c0ec9cc7
FM
2002}
2003
342bd723 2004void write_html_trailer(FILE *fp_ou)
c0ec9cc7 2005{
9bd92830 2006 show_info(fp_ou);
342bd723 2007 fputs("</body>\n</html>\n",fp_ou);
dfb337be
FM
2008}
2009
ac422f9b 2010void output_html_string(FILE *fp_ou,const char *str,int maxlen)
dfb337be 2011{
9bd92830
FM
2012 int i=0;
2013
2014 while (*str && (maxlen<=0 || i<maxlen)) {
2015 switch (*str) {
2016 case '&':
2017 fputs("&amp;",fp_ou);
2018 break;
2019 case '<':
2020 fputs("&lt;",fp_ou);
2021 break;
2022 case '>':
2023 fputs("&gt;",fp_ou);
2024 break;
2025 case '"':
2026 fputs("&quot;",fp_ou);
2027 break;
2028 case '\'':
2029 fputs("&#39;",fp_ou);
2030 break;
2031 default:
2032 fputc(*str,fp_ou);
2033 }
2034 str++;
2035 i++;
2036 }
2037 if (maxlen>0 && i>=maxlen)
2038 fputs("&hellip;",fp_ou);
ac422f9b
FM
2039}
2040
2041void output_html_url(FILE *fp_ou,const char *url)
2042{
9bd92830
FM
2043 while (*url) {
2044 if (*url=='&')
2045 fputs("&amp;",fp_ou);
2046 else
2047 fputc(*url,fp_ou);
2048 url++;
2049 }
491b862f
GS
2050}
2051
67a93701
FM
2052/*!
2053 Write a host name inside an A tag of a HTML file. If the host name starts
2054 with a star, it is assumed to be an alias that cannot be put inside a link
2055 so the A tag is not written around the host name.
b902df7e 2056
67a93701
FM
2057 \param fp_ou The handle of the HTML file.
2058 \param url The host to display in the HTML file.
2059 \param maxlen The maximum number of characters to print into the host name.
2060 */
6fa33a32 2061void output_html_link(FILE *fp_ou,const char *url,int maxlen)
67a93701
FM
2062{
2063 if (url[0]==ALIAS_PREFIX) {
2064 // this is an alias, no need for a A tag
2065 output_html_string(fp_ou,url+1,100);
2066 } else {
6fa33a32
FM
2067 if (skip_scheme(url)==url)
2068 fputs("<a href=\"http://",fp_ou);//no scheme in the url, assume http:// to make the link clickable
2069 else
2070 fputs("<a href=\"",fp_ou);//the scheme is in the url, no need to add one
67a93701
FM
2071 output_html_url(fp_ou,url);
2072 fputs("\">",fp_ou);
2073 output_html_string(fp_ou,url,100);
2074 fputs("</a>",fp_ou);
2075 }
2076}
2077
48864d28 2078void url_module(const char *url, char *w2)
25697a35 2079{
9bd92830
FM
2080 int x, y;
2081 char w[255];
25697a35 2082
9bd92830
FM
2083 y=0;
2084 for(x=strlen(url)-1; x>=0; x--) {
2085 if(url[x] == '/' || y>=sizeof(w)-1) break;
2086 w[y++]=url[x];
2087 }
2088 if (x<0) {
2089 w2[0]='\0';
2090 return;
2091 }
25697a35 2092
9bd92830
FM
2093 x=0;
2094 for(y=y-1; y>=0; y--) {
2095 w2[x++]=w[y];
2096 }
2097 w2[x]='\0';
25697a35
GS
2098}
2099
f72b484a
FM
2100/*!
2101Mangle an URL to produce a part that can be used as an anchor in
2102a html <a name=""> tag.
2103
2104\param url The URL to mangle.
2105\param anchor The buffer to write the mangled URL.
2106\param size The size of the buffer.
2107*/
2108void url_to_anchor(const char *url,char *anchor,int size)
e5b2c6f0 2109{
f72b484a
FM
2110 int i,j;
2111 bool skip;
e5b2c6f0 2112
f72b484a
FM
2113 // find url end
2114 for (i=0 ; url[i] && url[i]!='/' && url[i]!='?' ; i++);
2115 i--;
2116 if (i<=0) {
2117 anchor[0]='\0';
2118 return;
2119 }
2120
2121 // only keep really safe characters
2122 skip=false;
2123 j=size-1;
2124 anchor[j]='\0';
2125 while (j>0 && i>=0)
2126 {
2127 if(isalnum(url[i]) || url[i]=='-' || url[i]=='_' || url[i]=='.') {
2128 anchor[--j]=url[i];
2129 skip=false;
9bd92830 2130 } else {
f72b484a
FM
2131 if (!skip) anchor[--j]='_';
2132 skip=true;
2133 }
2134 i--;
2135 }
2136 if (j>0)
2137 {
2138 while ( anchor[j])
2139 {
2140 *anchor=anchor[j];
2141 anchor++;
9bd92830 2142 }
f72b484a 2143 *anchor='\0';
9bd92830 2144 }
e5b2c6f0 2145}
d6e703cc 2146
32e71fa4 2147void version(void)
25697a35 2148{
9bd92830 2149 printf(_("SARG Version: %s\n"),VERSION);
728f6a04
FM
2150#if defined(ENABLE_NLS) && defined(HAVE_LOCALE_H)
2151 if (debug) {
cedca111 2152 printf(_("\nFor the translation to work, a valid message file should be copied to "
2683bb62
FM
2153 "\"%s/<Locale>/LC_MESSAGES/%s.mo\" where <Locale> is derived from the effective locale.\n"),LOCALEDIR,PACKAGE_NAME);
2154 if (CurrentLocale) {
2155 printf(_("Currently effective locale is \"%s\".\n"),CurrentLocale);
2156 } else {
2157 printf(_("Locale is not set in the environment variable.\n"));
2158 }
2159 // TRANSLATORS: You may change this message to tell the reader that the language is correctly supported.
2160 printf(_("If this message is in English, then your language is not supported or not correctly installed.\n"));
728f6a04
FM
2161 }
2162#endif
2b41f02c
FM
2163 if (debug) {
2164#ifdef HAVE_GLOB_H
2165 printf(_("File globbing compiled in.\n"));
2166#else
2167 printf(_("File globbing NOT compiled in.\n"));
2168#endif
2169 }
9bd92830 2170 exit(EXIT_SUCCESS);
25697a35 2171}
5f3cfd1d
FM
2172
2173char *get_param_value(const char *param,char *line)
2174{
9bd92830 2175 int plen;
2357ef77 2176
9bd92830
FM
2177 while (*line==' ' || *line=='\t') line++;
2178 plen=strlen(param);
2179 if (strncasecmp(line,param,plen)) return(NULL);
2180 if (line[plen]!=' ' && line[plen]!='\t') return(NULL);
2181 line+=plen;
2182 while (*line==' ' || *line=='\t') line++;
2183 return(line);
5f3cfd1d 2184}
936c9905 2185
170a77ea 2186void unlinkdir(const char *dir,bool contentonly)
304a739d 2187{
9bd92830
FM
2188 struct stat st;
2189 DIR *dirp;
2190 struct dirent *direntp;
2191 char dname[MAXLEN];
2192 int err;
2193
2194 dirp=opendir(dir);
2195 if (!dirp) return;
2196 while ((direntp = readdir(dirp)) != NULL) {
2197 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
007905af 2198 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
9bd92830
FM
2199 continue;
2200 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
af961877 2201 debuga(__FILE__,__LINE__,_("Path too long: "));
041018b6 2202 debuga_more("%s/%s\n",dir,direntp->d_name);
9bd92830
FM
2203 exit(EXIT_FAILURE);
2204 }
463f8e09 2205#ifdef HAVE_LSTAT
9bd92830 2206 err=lstat(dname,&st);
463f8e09 2207#else
9bd92830 2208 err=stat(dname,&st);
463f8e09 2209#endif
9bd92830 2210 if (err) {
af961877 2211 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
9bd92830
FM
2212 exit(EXIT_FAILURE);
2213 }
2214 if (S_ISREG(st.st_mode)) {
2215 if (unlink(dname)) {
af961877 2216 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
9bd92830
FM
2217 exit(EXIT_FAILURE);
2218 }
2219 } else if (S_ISDIR(st.st_mode)) {
2220 unlinkdir(dname,0);
2221 } else {
af961877 2222 debuga(__FILE__,__LINE__,_("Don't know how to delete \"%s\" (not a regular file nor a directory)\n"),dname);
9bd92830
FM
2223 }
2224 }
2225 closedir(dirp);
2226
2227 if (!contentonly) {
2228 if (rmdir(dir)) {
af961877 2229 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dir,strerror(errno));
9bd92830
FM
2230 exit(EXIT_FAILURE);
2231 }
2232 }
51465d08 2233}
ac422f9b 2234
170a77ea
FM
2235/*!
2236Delete every file from the temporary directory where sarg is told to store its
2237temporary files.
2238
2239As any stray file left over by a previous run would be included in the report, we
2240must delete every file from the temporary directory before we start processing the logs.
2241
2242But the temporary directory is given by the user either in the configuration file or
2243on the command line. We check that the user didn't give a wrong directory by looking
2244at the files stored in the directory. If a single file is not one of ours, we abort.
2245
2246\param dir The temporary directory to purge.
2247*/
2248void emptytmpdir(const char *dir)
2249{
2250 struct stat st;
2251 DIR *dirp;
2252 struct dirent *direntp;
2253 int dlen;
2254 int elen;
2255 char dname[MAXLEN];
2256 int err;
2257 int i;
2258 static const char *TmpExt[]=
2259 {
2260 ".int_unsort",
2261 ".int_log",
2262 ".day",
2263 "htmlrel.txt",
2264 ".user_unsort",
2265 ".user_log",
2266 ".utmp",
0428e5fd
FM
2267 ".ip",
2268 "lastlog1",
4d04f072
FM
2269 "lastlog",
2270 "emailrep"
170a77ea
FM
2271 };
2272
2273 dirp=opendir(dir);
2274 if (!dirp) return;
bd43d81f 2275
170a77ea
FM
2276 // make sure the temporary directory contains only our files
2277 while ((direntp = readdir(dirp)) != NULL) {
2278 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2279 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2280 continue;
2281
2282 // is it one of our files
2283 dlen=strlen(direntp->d_name);
2284 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2285 elen=strlen(TmpExt[i]);
2286 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2287 }
2288 if (i<0) {
af961877 2289 debuga(__FILE__,__LINE__,_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
170a77ea
FM
2290 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2291 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2292 exit(EXIT_FAILURE);
2293 }
bd43d81f 2294
170a77ea 2295 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
af961877 2296 debuga(__FILE__,__LINE__,_("Path too long: "));
041018b6 2297 debuga_more("%s/%s\n",dir,direntp->d_name);
170a77ea
FM
2298 exit(EXIT_FAILURE);
2299 }
bd43d81f 2300
170a77ea
FM
2301#ifdef HAVE_LSTAT
2302 err=lstat(dname,&st);
2303#else
2304 err=stat(dname,&st);
2305#endif
2306 if (err) {
af961877 2307 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
170a77ea
FM
2308 exit(EXIT_FAILURE);
2309 }
e9390734 2310 if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) {
af961877 2311 debuga(__FILE__,__LINE__,_("Unknown path type for \"%s\". Check temporary directory\n"),dname);
170a77ea
FM
2312 exit(EXIT_FAILURE);
2313 }
2314 }
2315 rewinddir(dirp);
2316
2317 // now delete our files
2318 while ((direntp = readdir(dirp)) != NULL) {
2319 if (direntp->d_name[0] == '.' && (direntp->d_name[1] == '\0' ||
2320 (direntp->d_name[1] == '.' && direntp->d_name[2] == '\0')))
2321 continue;
2322
2323 // is it one of our files
2324 dlen=strlen(direntp->d_name);
2325 for (i=sizeof(TmpExt)/sizeof(TmpExt[0])-1 ; i>=0 ; i--) {
2326 elen=strlen(TmpExt[i]);
2327 if (dlen>=elen && strcasecmp(direntp->d_name+dlen-elen,TmpExt[i])==0) break;
2328 }
2329 if (i<0) {
af961877 2330 debuga(__FILE__,__LINE__,_("Unknown file \"%s\" found in temporary directory \"%s\". It is not one of our files. "
170a77ea
FM
2331 "Please check the temporary directory you gave to sarg. Adjust the path to a safe "
2332 "directory or manually delete the content of \"%s\"\n"),direntp->d_name,dir,dir);
2333 exit(EXIT_FAILURE);
2334 }
bd43d81f 2335
170a77ea 2336 if (snprintf(dname,sizeof(dname),"%s/%s",dir,direntp->d_name)>=sizeof(dname)) {
af961877 2337 debuga(__FILE__,__LINE__,_("Path too long: "));
041018b6 2338 debuga_more("%s/%s\n",dir,direntp->d_name);
170a77ea
FM
2339 exit(EXIT_FAILURE);
2340 }
2341#ifdef HAVE_LSTAT
2342 err=lstat(dname,&st);
2343#else
2344 err=stat(dname,&st);
2345#endif
2346 if (err) {
af961877 2347 debuga(__FILE__,__LINE__,_("Cannot stat \"%s\": %s\n"),dname,strerror(errno));
170a77ea
FM
2348 exit(EXIT_FAILURE);
2349 }
e9390734
FM
2350 if (S_ISDIR(st.st_mode)) {
2351 unlinkdir(dname,0);
2352 } else if (S_ISREG(st.st_mode)) {
170a77ea 2353 if (unlink(dname)) {
af961877 2354 debuga(__FILE__,__LINE__,_("Cannot delete \"%s\": %s\n"),dname,strerror(errno));
170a77ea
FM
2355 exit(EXIT_FAILURE);
2356 }
2357 } else {
af961877 2358 debuga(__FILE__,__LINE__,_("Don't know how to delete \"%s\" (not a regular file)\n"),dname);
170a77ea
FM
2359 }
2360 }
2361 closedir(dirp);
2362}
2363
5207d9f8
FM
2364/*!
2365 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
2366 prefix size.
2367
2368 \param buf The buffer to parse.
2369 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
a16cb22a 2370 The pointer may be NULL.
5207d9f8
FM
2371 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
2372 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
2373 \param nbits The number of prefix bits for an IP address.
2374 \param next The content of the line after the extracted address.
2375
2376 \retval 3 The pattern is a IPv6 address.
2377 \retval 2 The pattern is a IPv4 address.
2378 \retval 1 The patter is a string.
2379 \retval 0 Empty pattern.
2380 */
7819e0d5 2381int extract_address_mask(const char *buf,const char **text,unsigned char *ipv4,unsigned short int *ipv6,int *nbits,const char **next)
5207d9f8
FM
2382{
2383 int i;
2384 int j;
2385 int ip_size;
2386 unsigned int value4, value6;
2387 unsigned short int addr[8];
2388 int addr_len;
0ec4b481 2389 int nibble6_len;
5207d9f8
FM
2390 int mask, max_mask;
2391 int pad_pos;
2392 int pad_len;
08eb52bb
FM
2393 bool bracket=false;
2394 bool port=false;
2395 bool port_num=0;
5207d9f8
FM
2396
2397 // skip leading spaces and tabs
2398 while (*buf && (*buf==' ' || *buf=='\t')) buf++;
bd43d81f 2399
5207d9f8
FM
2400 // find out the nature of the pattern
2401 ip_size=0x60 | 0x04;
0ec4b481
FM
2402 if (*buf=='[') {
2403 bracket=true;
2404 ip_size=0x60;
2405 buf++;
2406 }
5207d9f8
FM
2407 value4=0U;
2408 value6=0U;
2409 addr_len=0;
0ec4b481 2410 nibble6_len=0;
5207d9f8 2411 pad_pos=-1;
84aefd39 2412 for (i=0 ; (unsigned char)buf[i]>' ' && buf[i]!='/' && buf[i]!='?' && (!bracket || buf[i]!=']') && ip_size ; i++) {
5207d9f8
FM
2413 if (ip_size & 0x04) {
2414 if (isdigit(buf[i])) {
08eb52bb
FM
2415 if (port) {
2416 port_num=port_num*10+(buf[i]-'0');
2417 if (port_num>65535) ip_size&=~0x04;
2418 } else {
2419 value4=value4*10+(buf[i]-'0');
2420 if (value4>0xFFU) ip_size&=~0x04;
2421 }
5207d9f8
FM
2422 } else if (buf[i]=='.' && addr_len<4) {
2423 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2424 value4=0U;
08eb52bb
FM
2425 } else if (!port && buf[i]==':') {
2426 port=true;
5207d9f8
FM
2427 } else {
2428 ip_size&=~0x04;
2429 }
2430 }
2431 if (ip_size & 0x60) {
2432 if (isdigit(buf[i])) {
2433 value6=(value6<<4)+(buf[i]-'0');
0ec4b481 2434 nibble6_len++;
5207d9f8
FM
2435 if (value6>0xFFFFU) ip_size&=~0x60;
2436 } else if (toupper(buf[i])>='A' && toupper(buf[i])<='F') {
2437 value6=(value6<<4)+(toupper(buf[i])-'A'+10);
0ec4b481 2438 nibble6_len++;
5207d9f8
FM
2439 if (value6>0xFFFFU) ip_size&=~0x60;
2440 } else if (buf[i]==':' && addr_len<8) {
0ec4b481
FM
2441 if (nibble6_len>0) {
2442 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2443 nibble6_len=0;
2444 }
5207d9f8 2445 value6=0U;
0ec4b481
FM
2446 if (buf[i+1]==':') {
2447 pad_pos=addr_len;
2448 i++;
2449 }
5207d9f8
FM
2450 } else {
2451 ip_size&=~0x60;
2452 }
2453 }
2454 }
2455 if (i==0) return(0);
2456 if (ip_size & 0x04) {
2457 if (addr_len!=3)
2458 ip_size&=~0x04;
2459 else
2460 addr[addr_len++]=(unsigned short)(value4 & 0xFFU);
2461 }
2462 if (ip_size & 0x60) {
2463 if (pad_pos<0 && addr_len!=7) {
2464 ip_size&=~0x60;
2465 } else if (pad_pos>=0 && addr_len>=7)
2466 ip_size&=~0x60;
0ec4b481 2467 else if (nibble6_len>0)
5207d9f8
FM
2468 addr[addr_len++]=(unsigned short)(value6 & 0xFFFFU);
2469 }
2470 if (!ip_size) {
a16cb22a
FM
2471 if (text) {
2472 *text=buf;
2473 if (bracket) (*text)--;
2474 }
5207d9f8 2475 while ((unsigned char)buf[i]>' ') i++;
7819e0d5 2476 if (next) *next=buf+i;
5207d9f8
FM
2477 return(1);
2478 }
2479 max_mask=(ip_size & 0x04) ? 4*8 : 8*16;
2480 if (buf[i]=='/') {
2481 i++;
2482 mask=atoi(buf+i);
2483 while (isdigit(buf[i])) i++;
2484 if (mask<0 || mask>max_mask) mask=max_mask;
2485 } else
2486 mask=max_mask;
0ec4b481 2487 if (ip_size & 0x60 && bracket && buf[i]==']') i++;
7819e0d5 2488 if (next) *next=buf+i;
5207d9f8
FM
2489 if (ip_size & 0x04) {
2490 if (nbits) *nbits=mask;
2491 for (i=0 ; i<addr_len ; i++)
2492 ipv4[i]=(unsigned char)addr[i];
2493 return(2);
2494 }
2495
2496 // IPv6 address
2497 if (nbits) *nbits=mask;
2498 i=0;
2499 j=0;
2500 if (pad_pos>=0) {
2501 while (i<pad_pos)
2502 ipv6[j++]=(unsigned short int)addr[i++];
2503 pad_len=8-addr_len;
0ec4b481 2504 while (j<pad_pos+pad_len)
5207d9f8
FM
2505 ipv6[j++]=0;
2506 }
2507 while (i<addr_len)
2508 ipv6[j++]=(unsigned short int)addr[i++];
2509 return(3);
2510}