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