]>
git.ipfire.org Git - thirdparty/sarg.git/blob - util.c
2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
6 * please look at http://sarg.sourceforge.net/donations.php
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
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.
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.
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.
27 // #define LEGACY_MY_ATOLL
28 // #define LEGACY_TESTVALIDUSERCHAR
30 #include "include/conf.h"
31 #include "include/defs.h"
33 #if defined(HAVE_BACKTRACE)
34 #define USE_GETWORD_BACKTRACE 1
36 #define USE_GETWORD_BACKTRACE 0
39 static char mtab1
[12][4]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
41 //! The list of the HTTP codes to exclude from the report.
42 static char *excludecode
=NULL
;
44 #if USE_GETWORD_BACKTRACE
45 static void getword_backtrace(void)
51 n
=backtrace(buffer
,sizeof(buffer
)/sizeof(buffer
[0]));
53 calls
=backtrace_symbols(buffer
,n
);
55 debuga(_("getword backtrace:\n"));
56 for (i
=0 ; i
<n
; i
++) {
57 fprintf(stderr
,"SARG: %d:%s\n",i
+1,calls
[i
]);
62 #endif //USE_GETWORD_BACKTRACE
64 void getword_start(struct getwordstruct
*gwarea
, const char *line
)
66 gwarea
->beginning
=line
;
71 void getword_restart(struct getwordstruct
*gwarea
)
73 if (gwarea
->modified
) {
74 debuga(_("Cannot parse again the line as it was modified\n"));
77 gwarea
->current
=gwarea
->beginning
;
80 int getword(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
84 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
86 printf("SARG: getword loop detected after %d bytes.\n",x
);
87 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
88 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
89 printf("SARG: searching for \'x%x\'\n",stop
);
90 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
91 word
[(limit
>0) ? limit
-1 : 0]='\0';
92 #if USE_GETWORD_BACKTRACE
97 word
[x
] = gwarea
->current
[x
];
101 if (gwarea
->current
[x
]) ++x
;
106 int getword_limit(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
111 for(x
=0; x
<limit
&& gwarea
->current
[x
] && gwarea
->current
[x
] != stop
;x
++) {
112 word
[x
] = gwarea
->current
[x
];
116 while (*gwarea
->current
&& *gwarea
->current
!= stop
) gwarea
->current
++;
117 if (*gwarea
->current
) ++gwarea
->current
;
121 int getword_multisep(char *word
, int limit
, struct getwordstruct
*gwarea
, char stop
)
125 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++) {
127 printf("SARG: getword_multisep loop detected.\n");
128 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
129 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
130 printf("SARG: searching for \'x%x\'\n",stop
);
131 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
132 if (limit
>0) word
[limit
-1]='\0';
133 #if USE_GETWORD_BACKTRACE
136 //exit(EXIT_FAILURE);
139 word
[x
] = gwarea
->current
[x
];
143 while (gwarea
->current
[x
] && gwarea
->current
[x
]==stop
) ++x
;
148 int getword_skip(int limit
, struct getwordstruct
*gwarea
, char stop
)
152 for(x
=0;(gwarea
->current
[x
] && (gwarea
->current
[x
] != stop
));x
++) {
154 printf("SARG: getword_skip loop detected after %d bytes.\n",x
);
155 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
156 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
157 printf("SARG: searching for \'x%x\'\n",stop
);
158 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
159 #if USE_GETWORD_BACKTRACE
166 if (gwarea
->current
[x
]) ++x
;
171 int getword_atoll(long long int *number
, struct getwordstruct
*gwarea
, char stop
)
177 if (gwarea
->current
[0] == '-') {
180 } else if (gwarea
->current
[0] == '+') {
184 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
185 digit
=gwarea
->current
[x
]-'0';
186 if (*number
>= (LLONG_MAX
-digit
)/10) {
187 debuga(_("Integer overflow detected in getword_atoll in line %s\n"),gwarea
->beginning
);
190 *number
=(*number
* 10) + digit
;
192 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
193 printf("SARG: getword_atoll loop detected after %d bytes.\n",x
);
194 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
195 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
196 printf("SARG: searching for \'x%x\'\n",stop
);
197 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
198 #if USE_GETWORD_BACKTRACE
205 if (gwarea
->current
[x
]) ++x
;
210 int getword_atoi(int *number
, struct getwordstruct
*gwarea
, char stop
)
216 if (gwarea
->current
[0] == '-') {
219 } else if (gwarea
->current
[0] == '+') {
223 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
224 digit
=gwarea
->current
[x
]-'0';
225 if (*number
> (INT_MAX
-digit
)/10) {
226 debuga(_("Integer overflow detected in getword_atoi in line %s\n"),gwarea
->beginning
);
229 *number
=(*number
* 10) + digit
;
231 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
232 printf("SARG: getword_atoi loop detected after %d bytes.\n",x
);
233 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
234 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
235 printf("SARG: searching for \'x%x\'\n",stop
);
236 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
237 #if USE_GETWORD_BACKTRACE
244 if (gwarea
->current
[x
]) ++x
;
249 int getword_atol(long int *number
, struct getwordstruct
*gwarea
, char stop
)
255 if (gwarea
->current
[0] == '-') {
258 } else if (gwarea
->current
[0] == '+') {
262 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
263 digit
=gwarea
->current
[x
]-'0';
264 if (*number
> (LONG_MAX
-digit
)/10) {
265 debuga(_("Integer overflow detected in getword_atol in line %s\n"),gwarea
->beginning
);
268 *number
=(*number
* 10) + digit
;
270 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
271 printf("SARG: getword_atol loop detected after %ld bytes.\n",x
);
272 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
273 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
274 printf("SARG: searching for \'x%x\'\n",stop
);
275 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
276 #if USE_GETWORD_BACKTRACE
283 if (gwarea
->current
[x
]) ++x
;
288 int getword_atolu(unsigned long int *number
, struct getwordstruct
*gwarea
, char stop
)
293 if (gwarea
->current
[0] == '-') {
294 printf("SARG: getword_atolu got a negative number.\n");
295 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
296 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
299 if (gwarea
->current
[0] == '+') {
303 for(x
=0;isdigit(gwarea
->current
[x
]);x
++) {
304 digit
=gwarea
->current
[x
]-'0';
305 if (*number
> (ULONG_MAX
-digit
)/10) {
306 debuga(_("Integer overflow detected in getword_atolu in line %s\n"),gwarea
->beginning
);
309 *number
=(*number
* 10) + digit
;
311 if(gwarea
->current
[x
] && gwarea
->current
[x
]!=stop
) {
312 printf("SARG: getword_atolu loop detected after %ld bytes.\n",x
);
313 printf("SARG: Line=\"%s\"\n",gwarea
->beginning
);
314 printf("SARG: Record=\"%s\"\n",gwarea
->current
);
315 printf("SARG: searching for \'x%x\'\n",stop
);
316 //printf("SARG: Maybe you have a broken record or garbage in your access.log file.\n");
317 #if USE_GETWORD_BACKTRACE
323 if (gwarea
->current
[x
]) ++x
;
329 int getword_ptr(char *orig_line
,char **word
, struct getwordstruct
*gwarea
, char stop
)
332 \note Why pass the original buffer to the function ? Because we must modify it to
333 insert the terminating ASCII zero for the word we return and that's not compatible
334 with getword_restart(). Moreover, getword_start() sometime works on constant strings
335 so this function require the original buffer to detect any missuse.
341 if (orig_line
&& orig_line
!=gwarea
->beginning
) {
342 debuga(_("Invalid buffer passed to getword_ptr\n"));
346 start
=(gwarea
->current
-gwarea
->beginning
);
347 if (word
&& orig_line
) *word
=orig_line
+start
;
348 for(x
=0;((gwarea
->current
[x
]) && (gwarea
->current
[x
] != stop
));x
++);
349 sep
=(gwarea
->current
[x
]!='\0');
350 if (word
&& orig_line
) orig_line
[start
+x
] = '\0';
357 #define MAXLLL 30 //!< Maximum number of digits in long long (a guess).
358 long long int my_atoll (const char *nptr
)
360 long long int returnval
=0LL;
361 int max_digits
= MAXLLL
;
363 // Soak up all the white space
364 while (isspace( *nptr
)) {
368 //For each character left to right
369 //change the character to a single digit
370 //multiply what we had before by 10 and add the new digit
372 while (--max_digits
&& isdigit( *nptr
))
374 returnval
= ( returnval
* 10 ) + ( *nptr
++ - '0' ) ;
380 int is_absolute(const char *path
)
382 if (*path
=='/') return(1);
384 if (isalpha(path
[0]) && path
[1]==':') return(1);
389 void my_mkdir(const char *name
)
395 if(!is_absolute(name
)) {
396 debuga(_("Invalid path (%s). Please, use absolute paths only.\n"),name
);
397 debuga(_("process aborted.\n"));
402 for (i
=0 ; name
[i
] ; i
++) {
404 debuga(_("directory name too long: %s\n"),name
);
407 if (chars
>0 && name
[i
] == '/') {
409 if (access(w0
, R_OK
) != 0) {
410 if (mkdir(w0
,0755)) {
411 debuga(_("Cannot create directory %s - %s\n"),w0
,strerror(errno
));
412 debuga(_("process aborted.\n"));
417 if (name
[i
] != '/') chars
++;
421 if (access(name
, R_OK
) != 0) {
422 if (mkdir(name
,0755)) {
423 debuga(_("Cannot create directory %s - %s\n"),name
,strerror(errno
));
424 debuga(_("process aborted.\n"));
431 void my_lltoa(unsigned long long int n
, char *s
, int ssize
, int len
)
440 debuga(_("The requested number of digits passed to my_lltoa (%d) is bigger than the output buffer size (%d)\n"),len
,ssize
);
445 s
[slen
++] = (n
% 10) + '0';
446 } while ((n
/= 10) > 0 && slen
<ssize
);
449 for (i
= 0, j
= slen
-1; i
<j
; i
++, j
--) {
457 for(j
=slen
; j
>=0; j
--)
464 int month2num(const char *month
)
468 for(m
=0 ; m
<12 && strcmp(mtab1
[m
],month
) != 0; m
++);
472 int builddia(int day
, int month
, int year
)
474 return(year
*10000+month
*100+day
);
478 void buildymd(const char *dia
, const char *mes
, const char *ano
, char *wdata
)
483 sprintf(wdata
,"%04d%02d%02d",atoi(ano
),nmes
+1,atoi(dia
));
487 int conv_month(const char *month
)
491 for(x
=0; x
<12 && strncmp(mtab1
[x
],month
,3)!=0; x
++);
496 const char *conv_month_name(int month
)
500 if (month
<1 || month
>12) {
501 snprintf(str
,sizeof(str
),"%03d",month
);
504 return(mtab1
[month
-1]);
508 void name_month(char *month
,int month_len
)
510 int x
, z
=atoi(month
)-1;
513 struct getwordstruct gwarea
;
515 strcpy(m
,_("January,February,March,April,May,June,July,August,September,October,November,December"));
516 getword_start(&gwarea
,m
);
519 if (getword_multisep(w
,sizeof(w
),&gwarea
,',')<0) {
520 printf("SARG: Maybe you have a broken record or garbage in the names of the months.\n");
523 if (getword_multisep(month
,month_len
,&gwarea
,',')<0) {
524 printf("SARG: Maybe you have a broken record or garbage in the name of the months.\n");
531 Write a debug message to stderr. The message is prefixed by "SARG:" to identify its origin.
533 \param msg The printf like message to format.
534 \param ... The arguments to format in the message.
536 void debuga(const char *msg
,...)
540 fputs(_("SARG: "),stderr
);
542 vfprintf(stderr
,msg
,ap
);
548 Write a debug message to stderr. The message is prefixed by "SARG: (info)".
550 \param msg The printf like message to format.
551 \param ... The arguments to format in the message.
553 void debugaz(const char *msg
,...)
557 fputs(_("SARG: (info) "),stderr
);
559 vfprintf(stderr
,msg
,ap
);
564 char *fixnum(long long int value
, int n
)
566 #define MAXLEN_FIXNUM 256
567 char num
[MAXLEN_FIXNUM
]="";
568 char buf
[MAXLEN_FIXNUM
* 2];
570 static char ret
[MAXLEN_FIXNUM
* 2];
572 register int i
, j
, k
;
574 static char abbrev
[30];
576 my_lltoa(value
, num
, sizeof(num
), 0);
578 if(DisplayedValues
==DISPLAY_ABBREV
) {
579 numlen
= strlen(num
);
581 sprintf(abbrev
,"%s",num
);
582 if(numlen
== 4 || numlen
== 7 || numlen
== 10 || numlen
== 13) {
583 snprintf(abbrev
,2,"%s",num
);
584 strncat(abbrev
,".",1);
585 strncat(abbrev
,num
+1,2);
586 if(!n
) return(abbrev
);
588 strncat(abbrev
,"K",1);
590 strncat(abbrev
,"M",1);
591 else if(numlen
== 10)
592 strncat(abbrev
,"G",1);
593 else if(numlen
== 13)
594 strncat(abbrev
,"T",1);
596 if(numlen
== 5 || numlen
== 8 || numlen
== 11 || numlen
== 14) {
597 snprintf(abbrev
,3,"%s",num
);
598 strncat(abbrev
,".",1);
599 strncat(abbrev
,num
+2,2);
600 if(!n
) return(abbrev
);
602 strncat(abbrev
,"K",1);
604 strncat(abbrev
,"M",1);
605 else if(numlen
== 11)
606 strncat(abbrev
,"G",1);
607 else if(numlen
== 14)
608 strncat(abbrev
,"T",1);
610 if(numlen
== 6 || numlen
== 9 || numlen
== 12 || numlen
== 15) {
611 snprintf(abbrev
,4,"%s",num
);
612 strncat(abbrev
,".",1);
613 strncat(abbrev
,num
+3,2);
614 if(!n
) return(abbrev
);
616 strncat(abbrev
,"K",1);
618 strncat(abbrev
,"M",1);
619 else if(numlen
== 12)
620 strncat(abbrev
,"G",1);
621 else if(numlen
== 15)
622 strncat(abbrev
,"T",1);
628 bzero(buf
, MAXLEN_FIXNUM
*2);
634 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
635 if ( k
== 2 && i
!= 0 ) {
638 pbuf
[j
++] = (UseComma
) ? ',' : '.';
648 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
657 char *fixnum2(long long int value
, int n
)
659 #define MAXLEN_FIXNUM2 1024
660 char num
[MAXLEN_FIXNUM2
];
661 char buf
[MAXLEN_FIXNUM2
* 2];
663 static char ret
[MAXLEN_FIXNUM2
* 2];
665 register int i
, j
, k
;
667 my_lltoa(value
, num
, sizeof(num
), 0);
668 bzero(buf
, MAXLEN_FIXNUM2
*2);
674 for ( i
= strlen(num
) - 1, j
= 0 ; i
> -1; i
--) {
675 if ( k
== 2 && i
!= 0 ) {
678 pbuf
[j
++] = (UseComma
) ? ',' : '.';
688 for ( i
= strlen(pbuf
) - 1, j
= 0 ; i
> -1; i
--, j
++)
697 char *buildtime(long long int elap
)
699 int num
= elap
/ 1000;
708 min
=(num
% 3600) / 60;
710 sprintf(buf
,"%02d:%02d:%02d",hor
,min
,sec
);
717 Get the date stored in the <tt>sarg-date</tt> file of a directory with the connection data.
719 \param dirname The directory to look for the connection directory.
720 \param name The name of the directory whose <tt>sarg-date</tt> file must be read.
721 \param data The buffer to store the content of the file. It must be more than 80
725 \retval -1 File not found.
727 int obtdate(const char *dirname
, const char *name
, char *data
)
732 sprintf(wdir
,"%s%s/sarg-date",dirname
,name
);
733 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
734 sprintf(wdir
,"%s%s/date",dirname
,name
);
735 if ((fp_in
= fopen(wdir
, "rt")) == 0) {
741 if (!fgets(data
,80,fp_in
)) {
742 debuga(_("Failed to read the date in %s\n"),wdir
);
752 void formatdate(char *date
,int date_size
,int year
,int month
,int day
,int hour
,int minute
,int second
,int dst
)
758 memset(<m
,0,sizeof(ltm
));
759 if (year
>=1900) ltm
.tm_year
=year
-1900;
760 if (month
>=1 && month
<=12) ltm
.tm_mon
=month
-1;
761 if (day
>=1 && day
<=31) ltm
.tm_mday
=day
;
762 if (hour
>=0 && hour
<24) ltm
.tm_hour
=hour
;
763 if (minute
>=0 && minute
<60) ltm
.tm_min
=minute
;
764 if (second
>=0 && second
<60) ltm
.tm_sec
=second
;
766 unixtime
=mktime(<m
); //fill the missing entries
767 fulltm
=localtime(&unixtime
);
768 //strftime(date,date_size,"%a %b %d %H:%M:%S %Z %Y",fulltm);
769 strftime(date
,date_size
,"%c",fulltm
);
773 void computedate(int year
,int month
,int day
,struct tm
*t
)
775 memset(t
,0,sizeof(*t
));
776 t
->tm_year
=year
-1900;
782 int obtuser(const char *dirname
, const char *name
)
789 sprintf(wdir
,"%s%s/sarg-users",dirname
,name
);
790 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
791 sprintf(wdir
,"%s%s/users",dirname
,name
);
792 if((fp_in
=fopen(wdir
,"r"))==NULL
) {
797 if (!fgets(tuser
,sizeof(tuser
),fp_in
)) {
798 debuga(_("Failed to read the number of users in %s\n"),wdir
);
808 void obttotal(const char *dirname
, const char *name
, int nuser
, long long int *tbytes
, long long int *media
)
813 char user
[MAX_USER_LEN
];
815 struct getwordstruct gwarea
;
821 sprintf(wdir
,"%s%s/sarg-general",dirname
,name
);
822 if ((fp_in
= fopen(wdir
, "r")) == 0) {
823 sprintf(wdir
,"%s%s/general",dirname
,name
);
824 if ((fp_in
= fopen(wdir
, "r")) == 0) {
829 if ((line
=longline_create())==NULL
) {
830 debuga(_("Not enough memory to read the file %s\n"),wdir
);
834 while((buf
=longline_read(fp_in
,line
))!=NULL
) {
835 if (strncmp(buf
,"TOTAL\t",6) == 0)
837 else if (strncmp(buf
,"TOTAL ",6) == 0)
841 getword_start(&gwarea
,buf
);
842 if (getword(user
,sizeof(user
),&gwarea
,sep
)<0) {
843 debuga(_("There is a invalid user in file %s\n"),wdir
);
846 if(strcmp(user
,"TOTAL") != 0)
848 if (getword_skip(MAXLEN
,&gwarea
,sep
)<0) {
849 debuga(_("There a broken total number of access in file %s\n"),wdir
);
852 if (getword_atoll(tbytes
,&gwarea
,sep
)<0) {
853 debuga(_("There is a broken number of bytes in file %s\n"),wdir
);
859 longline_destroy(&line
);
864 *media
=*tbytes
/ nuser
;
868 int getperiod_fromsarglog(const char *arqtt
,struct periodstruct
*period
)
871 int day0
, month0
, year0
, hour0
, minute0
;
872 int day1
, month1
, year1
, hour1
, minute1
;
875 memset(period
,0,sizeof(*period
));
878 while((str
=strstr(str
,"sarg-"))!=NULL
) {
880 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
881 day0
=(str
[0]-'0')*10+(str
[1]-'0');
882 if (day0
<1 || day0
>31) continue;
884 month0
=(str
[0]-'0')*10+(str
[1]-'0')-1;
885 if (month0
<0 || month0
>11) continue;
888 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year0
=year0
*10+(str
[i
]-'0');
891 if (str
[0]!='_') continue;
894 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
895 hour0
=(str
[0]-'0')*10+(str
[1]-'0');
897 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
898 minute0
=(str
[0]-'0')*10+(str
[1]-'0');
901 if (*str
!= '-') continue;
904 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
905 day1
=(str
[0]-'0')*10+(str
[1]-'0');
906 if (day1
<1 || day1
>31) continue;
908 month1
=(str
[0]-'0')*10+(str
[1]-'0')-1;
909 if (month1
<0 || month1
>11) continue;
912 for (i
=0 ; isdigit(str
[i
]) && i
<4 ; i
++) year1
=year1
*10+(str
[i
]-'0');
916 if (str
[0]!='_') continue;
919 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
920 hour1
=(str
[0]-'0')*10+(str
[1]-'0');
922 if (!isdigit(str
[0]) || !isdigit(str
[1])) continue;
923 minute1
=(str
[0]-'0')*10+(str
[1]-'0');
926 period
->start
.tm_mday
=day0
;
927 period
->start
.tm_mon
=month0
;
928 period
->start
.tm_year
=year0
-1900;
929 period
->start
.tm_hour
=hour0
;
930 period
->start
.tm_min
=minute0
;
931 period
->end
.tm_mday
=day1
;
932 period
->end
.tm_mon
=month1
;
933 period
->end
.tm_year
=year1
-1900;
934 period
->end
.tm_hour
=hour1
;
935 period
->end
.tm_min
=minute1
;
941 void getperiod_fromrange(struct periodstruct
*period
,int dfrom
,int duntil
)
943 memset(&period
->start
,0,sizeof(period
->start
));
944 period
->start
.tm_mday
=dfrom
%100;
945 period
->start
.tm_mon
=(dfrom
/100)%100-1;
946 period
->start
.tm_year
=(dfrom
/10000)-1900;
948 memset(&period
->end
,0,sizeof(period
->end
));
949 period
->end
.tm_mday
=duntil
%100;
950 period
->end
.tm_mon
=(duntil
/100)%100-1;
951 period
->end
.tm_year
=(duntil
/10000)-1900;
954 int getperiod_buildtext(struct periodstruct
*period
)
958 char text1
[40], text2
[40];
961 i
=strftime(text1
, sizeof(text1
), "%Y %b %d", &period
->start
);
962 }else if(df
[0]=='e') {
963 i
=strftime(text1
, sizeof(text1
), "%d %b %Y", &period
->start
);
964 } else /*if(df[0]=='w')*/ {
965 IndexTree
=INDEX_TREE_FILE
;
966 i
=strftime(text1
, sizeof(text1
), "%Y.%U", &period
->start
);
968 if (i
== 0) return(-1);
970 range
=(period
->start
.tm_year
!=period
->end
.tm_year
||
971 period
->start
.tm_mon
!=period
->end
.tm_mon
||
972 period
->start
.tm_mday
!=period
->end
.tm_mday
);
975 i
=strftime(text2
, sizeof(text2
)-i
, "%Y %b %d", &period
->end
);
976 } else if(df
[0]=='e') {
977 i
=strftime(text2
, sizeof(text2
)-i
, "%d %b %Y", &period
->end
);
979 i
=strftime(text2
, sizeof(text2
)-i
, "%Y.%U", &period
->end
);
981 if (i
== 0) return(-1);
985 snprintf(period
->text
,sizeof(period
->text
),"%s-%s",text1
,text2
);
986 snprintf(period
->html
,sizeof(period
->html
),"%s—%s",text1
,text2
);
988 safe_strcpy(period
->text
,text1
,sizeof(period
->text
));
989 safe_strcpy(period
->html
,text1
,sizeof(period
->html
));
994 static void copy_images(void)
996 FILE *img_in
, *img_ou
;
999 char srcfile
[MAXLEN
];
1000 char dstfile
[MAXLEN
];
1002 struct dirent
*direntp
;
1003 char buffer
[MAXLEN
];
1007 if (snprintf(images
,sizeof(images
),"%simages",outdir
)>=sizeof(images
)) {
1008 debuga(_("Cannot copy images to target directory %simages\n"),outdir
);
1011 if (access(images
,R_OK
)!=0) {
1012 if (mkdir(images
,0755)) {
1013 debuga(_("Cannot create directory %s - %s\n"),images
,strerror(errno
));
1018 strcpy(imgdir
,IMAGEDIR
);
1019 dirp
= opendir(imgdir
);
1021 debuga(_("(util) Can't open directory %s: %s\n"),imgdir
,strerror(errno
));
1024 while ((direntp
= readdir( dirp
)) != NULL
){
1025 if(direntp
->d_name
[0]=='.')
1027 sprintf(srcfile
,"%s/%s",imgdir
,direntp
->d_name
);
1028 if (stat(srcfile
,&info
)) {
1029 debuga(_("Cannot stat \"%s\" - %s\n"),srcfile
,strerror(errno
));
1032 if (S_ISREG(info
.st_mode
)) {
1033 sprintf(dstfile
,"%s/%s",images
,direntp
->d_name
);
1034 img_in
= fopen(srcfile
, "rb");
1036 img_ou
= fopen(dstfile
, "wb");
1038 while ((nread
= fread(buffer
,1,sizeof(buffer
),img_in
))>0) {
1039 if (fwrite(buffer
,1,nread
,img_ou
)!=nread
) {
1040 debuga(_("Failed to copy image %s to %s\n"),srcfile
,dstfile
);
1046 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open/create file", dstfile
, strerror(errno
));
1049 fprintf(stderr
,"SARG: (util): %s %s: %s\n", _("Cannot open file")?_("Cannot open file"):"Can't open file", srcfile
, strerror(errno
));
1052 (void) closedir(dirp
);
1057 int vrfydir(const struct periodstruct
*per1
, const char *addr
, const char *site
, const char *us
, const char *form
)
1062 char dirname2
[MAXLEN
];
1070 strcpy(wdir
,outdir
);
1072 y1
=per1
->start
.tm_year
+1900;
1073 y2
=per1
->end
.tm_year
+1900;
1074 m1
=per1
->start
.tm_mon
+1;
1075 m2
=per1
->end
.tm_mon
+1;
1076 d1
=per1
->start
.tm_mday
;
1077 d2
=per1
->end
.tm_mday
;
1078 if(IndexTree
== INDEX_TREE_DATE
) {
1079 wlen
+=sprintf(wdir
+wlen
,"%04d",y1
);
1080 if(y1
!=y2
) wlen
+=sprintf(wdir
+wlen
,"-%04d",y2
);
1081 if(access(wdir
, R_OK
) != 0)
1084 wlen
+=sprintf(wdir
+wlen
,"/%02d",m1
);
1085 if(m1
!= m2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",m2
);
1086 if(access(wdir
, R_OK
) != 0)
1089 wlen
+=sprintf(wdir
+wlen
,"/%02d",d1
);
1090 if(d1
!=d2
) wlen
+=sprintf(wdir
+wlen
,"-%02d",d2
);
1093 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%04d%s%02d-%04d%s%02d",y1
,
1094 conv_month_name(m1
),d1
,y2
,conv_month_name(m2
),d2
);
1095 } else if(df
[0] == 'e') {
1096 wlen
=snprintf(wdir
+wlen
,sizeof(wdir
)-wlen
,"%02d%s%04d-%02d%s%04d",d1
,
1097 conv_month_name(m1
),y1
,d2
,conv_month_name(m2
),y2
);
1098 } else if(df
[0] == 'w') {
1099 wlen2
=strftime(wdir
+wlen
, sizeof(wdir
)-wlen
, "%Y.%U", &per1
->start
);
1100 if (wlen2
==0) return(-1);
1106 struct userinfostruct
*uinfo
=userinfo_find_from_id(us
);
1109 strcat(wdir
,uinfo
->filename
);
1112 if(addr
[0] != '\0') {
1116 if(site
[0] != '\0') {
1121 strcpy(outdirname
,wdir
);
1123 if(IndexTree
!= INDEX_TREE_DATE
) {
1124 if(!OverwriteReport
) {
1126 if(access(wdir
,R_OK
) == 0) {
1127 sprintf(wdir
,"%s.%d",outdirname
,num
);
1136 debuga(_("File %s already exists, moved to %s\n"),outdirname
,wdir
);
1137 rename(outdirname
,wdir
);
1140 if(access(outdirname
,R_OK
) == 0) {
1141 unlinkdir(outdirname
,1);
1144 my_mkdir(outdirname
);
1146 strcpy(dirname2
,wdir
);
1147 if(!OverwriteReport
) {
1149 if(access(wdir
,R_OK
) == 0) {
1150 sprintf(wdir
,"%s.%d",dirname2
,num
);
1159 debuga(_("File %s already exists, moved to %s\n"),dirname2
,wdir
);
1160 rename(dirname2
,wdir
);
1161 strcpy(dirname2
,wdir
);
1164 if(access(wdir
,R_OK
) == 0) {
1169 if(access(wdir
, R_OK
) != 0)
1173 strcpy(dirname2
,wdir
);
1175 sprintf(wdir
,"%s/sarg-date",outdirname
);
1176 if ((fp_ou
= fopen(wdir
, "wt")) == 0) {
1177 debuga(_("cannot open %s for writing\n"),wdir
);
1182 //strftime(wdir,sizeof(wdir),"%a %b %d %H:%M:%S %Z %Y",localtime(&curtime));
1183 loctm
=localtime(&curtime
);
1184 strftime(wdir
,sizeof(wdir
),"%Y-%m-%d %H:%M:%S",loctm
);
1185 if (fprintf(fp_ou
,"%s %d\n",wdir
,loctm
->tm_isdst
)<0) {
1186 debuga(_("Failed to write the date in %s\n"),wdir
);
1190 if (fclose(fp_ou
)==EOF
) {
1191 debuga(_("Failed to write the date in %s\n"),wdir
);
1201 Copy a string without overflowing the buffer. The copied string
1202 is properly terminated by an ASCII zero.
1204 \param dest The destination buffer.
1205 \param src The source buffer.
1206 \param length The size of the destination buffer. The program is aborted
1207 if the length is negative or zero.
1209 void safe_strcpy(char *dest
,const char *src
,int length
)
1212 debuga(_("Invalid buffer length passed to the function to safely copy a string\n"));
1215 strncpy(dest
,src
,length
-1);
1216 dest
[length
-1]='\0';
1219 void strip_latin(char *line
)
1226 for (i
=0;line
[i
];i
++){
1228 if (line
[i
]==';') skip
=0;
1240 void zdate(char *ftime
,int ftimesize
, const char *DateFormat
)
1246 local
= localtime(&t
);
1247 if(strcmp(DateFormat
,"u") == 0)
1248 strftime(ftime
, ftimesize
, "%b/%d/%Y %H:%M", local
);
1249 if(strcmp(DateFormat
,"e") == 0)
1250 strftime(ftime
, ftimesize
, "%d/%b/%Y-%H:%M", local
);
1251 if(strcmp(DateFormat
,"w") == 0)
1252 strftime(ftime
, ftimesize
, "%W-%H-%M", local
);
1257 char *fixtime(long long int elap
)
1259 int num
= elap
/ 1000;
1263 static char buf
[12];
1266 min
=(num
% 3600) / 60;
1269 if(hor
==0 && min
==0 && sec
==0)
1272 sprintf(buf
,"%d:%02d:%02d",hor
,min
,sec
);
1278 void date_from(char *date
, int *dfrom
, int *duntil
)
1287 if (isdigit(date
[0])) {
1290 if (sscanf(date
,"%d/%d/%d%n",&d0
,&m0
,&y0
,&next
)!=3 || y0
<100 || m0
<1 || m0
>12 || d0
<1 || d0
>31 || next
<0) {
1291 debuga(_("The date passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1294 if (date
[next
]=='-') {
1295 if (sscanf(date
+next
+1,"%d/%d/%d",&d1
,&m1
,&y1
)!=3 || y1
<100 || m1
<1 || m1
>12 || d1
<1 || d1
>31) {
1296 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1299 } else if (date
[next
]!='\0') {
1300 debuga(_("The date range passed as argument is not formated as dd/mm/yyyy or dd/mm/yyyy-dd/mm/yyyy\n"));
1310 struct tm
*Date0
,Date1
;
1312 if (time(&Today
)==(time_t)-1) {
1313 debuga(_("Failed to get the current time\n"));
1316 if (sscanf(date
,"day-%d",&i
)==1) {
1318 debuga(_("Invalid number of days in -d parameter\n"));
1322 Date0
=localtime(&Today
);
1324 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1327 y0
=y1
=Date0
->tm_year
+1900;
1328 m0
=m1
=Date0
->tm_mon
+1;
1329 d0
=d1
=Date0
->tm_mday
;
1330 } else if (sscanf(date
,"week-%d",&i
)==1) {
1332 There is no portable way to find the first day of the week even though the
1333 information is available in the locale. nl_langinfo has the unofficial
1334 parameters _NL_TIME_FIRST_WEEKDAY and _NL_TIME_WEEK_1STDAY but they are
1335 undocumented as is their return value and it is discouraged to use them.
1336 Beside, nl_langinfo isn't available on windows and the first day of the
1337 week isn't available at all on that system.
1339 const int FirstWeekDay
=1;
1343 debuga(_("Invalid number of weeks in -d parameter\n"));
1346 Date0
=localtime(&Today
);
1348 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1351 WeekBegin
=Today
-((Date0
->tm_wday
-FirstWeekDay
+7)%7)*24*60*60;
1352 WeekBegin
-=i
*7*24*60*60;
1353 Date0
=localtime(&WeekBegin
);
1355 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1358 y0
=Date0
->tm_year
+1900;
1361 WeekBegin
+=6*24*60*60;
1362 Date0
=localtime(&WeekBegin
);
1364 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1367 y1
=Date0
->tm_year
+1900;
1370 } else if (sscanf(date
,"month-%d",&i
)==1) {
1372 debuga(_("Invalid number of months in -d parameter\n"));
1375 Date0
=localtime(&Today
);
1377 debuga(_("Cannot convert local time: %s\n"),strerror(errno
));
1380 if (Date0
->tm_mon
<i
%12) {
1381 y0
=Date0
->tm_year
+1900-i
/12-1;
1382 m0
=(Date0
->tm_mon
+12-i
%12)%12+1;
1385 y0
=Date0
->tm_year
+1900-i
/12;
1386 m0
=Date0
->tm_mon
-i
%12+1;
1389 memcpy(&Date1
,Date0
,sizeof(struct tm
));
1394 Date1
.tm_year
=y0
-1900;
1397 Date1
.tm_year
=y0
-1900+1;
1401 Date0
=localtime(&t1
);
1402 y1
=Date0
->tm_year
+1900;
1406 debuga(_("Invalid date range passed on command line\n"));
1411 *dfrom
=y0
*10000+m0
*100+d0
;
1412 *duntil
=y1
*10000+m1
*100+d1
;
1413 sprintf(date
,"%02d/%02d/%04d-%02d/%02d/%04d",d0
,m0
,y0
,d1
,m1
,y1
);
1418 char *strlow(char *string
)
1424 for (s
= string
; *s
; ++s
)
1434 char *strup(char *string
)
1440 for (s
= string
; *s
; ++s
)
1448 void removetmp(const char *outdir
)
1453 if(!RemoveTempFiles
)
1457 debuga(_("Purging temporary file sarg-general\n"));
1459 if (snprintf(filename
,sizeof(filename
),"%s/sarg-general",outdir
)>=sizeof(filename
)) {
1460 debuga(_("(removetmp) directory too long to remove %s/sarg-period\n"),outdir
);
1463 if((fp_gen
=fopen(filename
,"w"))==NULL
){
1464 debuga(_("(removetmp) Cannot open file %s\n"),filename
);
1467 totalger(fp_gen
,filename
);
1468 if (fclose(fp_gen
)==EOF
) {
1469 debuga(_("Failed to close %s after writing the total line - %s\n"),filename
,strerror(errno
));
1474 void load_excludecodes(const char *ExcludeCodes
)
1482 if(ExcludeCodes
[0] == '\0')
1485 if((fp_in
=fopen(ExcludeCodes
,"r"))==NULL
) {
1486 debuga(_("(util) Cannot open file %s (exclude_codes)\n"),ExcludeCodes
);
1490 if (fseek(fp_in
, 0, SEEK_END
)==-1) {
1491 debuga(_("Failed to move till the end of the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1494 MemSize
= ftell(fp_in
);
1496 debuga(_("Cannot get the size of file %s\n"),ExcludeCodes
);
1499 if (fseek(fp_in
, 0, SEEK_SET
)==-1) {
1500 debuga(_("Failed to rewind the excluded codes file %s: %s\n"),ExcludeCodes
,strerror(errno
));
1505 if((excludecode
=(char *) malloc(MemSize
))==NULL
) {
1506 debuga(_("malloc error (%ld)\n"),MemSize
);
1509 memset(excludecode
,0,MemSize
);
1512 while(fgets(data
,sizeof(data
),fp_in
)!=NULL
) {
1513 if (data
[0]=='#') continue;
1514 for (i
=strlen(data
)-1 ; i
>=0 && (unsigned char)data
[i
]<=' ' ; i
--) data
[i
]='\0';
1516 if (Stored
+i
+2>=MemSize
) {
1517 debuga(_("Too many codes to exclude in file %s\n"),ExcludeCodes
);
1520 strcat(excludecode
,data
);
1521 strcat(excludecode
,";");
1529 void free_excludecodes(void)
1537 int vercode(const char *code
)
1542 if (excludecode
&& excludecode
[0]!='\0') {
1546 if (strncmp(code
,cod
,clen
)==0 && cod
[clen
]==';')
1548 cod
=strchr(cod
,';');
1555 void fixnone(char *str
)
1559 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--);
1560 if(i
==3 && strncmp(str
,"none",4) == 0)
1566 void fixendofline(char *str
)
1570 for (i
=strlen(str
)-1 ; i
>=0 && (unsigned char)str
[i
]<=' ' ; i
--) str
[i
]=0;
1573 #ifdef LEGACY_TESTVALIDUSERCHAR
1574 int testvaliduserchar(const char *user
)
1579 for (y
=0; y
<strlen(UserInvalidChar
); y
++) {
1580 for (x
=0; x
<strlen(user
); x
++) {
1581 if(user
[x
] == UserInvalidChar
[y
])
1588 int testvaliduserchar(const char *user
)
1590 char * p_UserInvalidChar
= UserInvalidChar
;
1591 const char * p_user
;
1593 while( *p_UserInvalidChar
) {
1596 if( *p_UserInvalidChar
== *p_user
)
1600 p_UserInvalidChar
++ ;
1606 int compar( const void *a
, const void *b
)
1608 if( *(int *)a
> *(int *)b
) return 1;
1609 if( *(int *)a
< *(int *)b
) return -1;
1613 int getnumlist( char *buf
, numlist
*list
, const int len
, const int maxvalue
)
1615 int i
, j
, d
, flag
, r1
, r2
;
1616 char *pbuf
, **bp
, *strbufs
[ 24 ];
1619 strtok( buf
, " \t" );
1620 for( *bp
= strtok( NULL
, "," ), list
->len
= 0; *bp
; *bp
= strtok( NULL
, "," ) ) {
1621 if( ++bp
>= &strbufs
[ 24 ] )
1628 for( i
= 0; i
< list
->len
; i
++ ) {
1629 if( strchr( strbufs
[ i
], '-' ) != 0 ) {
1630 pbuf
= strbufs
[ i
];
1631 strtok( pbuf
, "-" );
1632 pbuf
= strtok( NULL
, "\0" );
1633 r1
= atoi( strbufs
[ i
] );
1634 if( ( r2
= atoi( pbuf
) ) >= maxvalue
|| r1
>= r2
)
1636 if( i
+ d
+ ( r2
- r1
) + 1 <= len
) {
1637 for( j
= r1
; j
<= r2
; j
++ )
1638 list
->list
[ i
+ d
++ ] = j
;
1643 if( ( list
->list
[ i
+ d
] = atoi( strbufs
[ i
] ) ) >= maxvalue
)
1647 qsort( list
->list
, list
->len
, sizeof( int ), compar
);
1650 for( i
= 0; i
< list
->len
- 1; i
++ )
1651 if( list
->list
[ i
] == list
->list
[ i
+ 1 ] ) {
1652 for( j
= i
+ 1; j
< list
->len
; j
++ )
1653 list
->list
[ j
- 1 ] = list
->list
[ j
];
1663 char *get_size(const char *path
, const char *file
)
1666 static char response
[255];
1670 if (snprintf(cmd
,sizeof(cmd
),"du -skh %s%s",path
,file
)>=sizeof(cmd
)) {
1671 debuga(_("Cannot get disk space because the path %s%s is too long\n"),path
,file
);
1674 if ((fp
= popen(cmd
, "r")) == NULL
) {
1675 debuga(_("Cannot get disk space with command %s\n"),cmd
);
1678 if (!fgets(response
, sizeof(response
), fp
)) {
1679 debuga(_("Cannot get disk size with command %s\n"),cmd
);
1682 ptr
=strchr(response
,'\t');
1684 debuga(_("The command %s failed\n"),cmd
);
1693 void show_info(FILE *fp_ou
)
1697 if(!ShowSargInfo
) return;
1698 zdate(ftime
, sizeof(ftime
), DateFormat
);
1699 fprintf(fp_ou
,"<div class=\"info\">%s <a href='%s'>%s-%s</a> %s %s</div>\n",_("Generated by"),URL
,PGM
,VERSION
,_("on"),ftime
);
1702 void show_sarg(FILE *fp_ou
, int depth
)
1706 if(!ShowSargLogo
) return;
1707 fputs("<div class=\"logo\"><a href=\"http://sarg.sourceforge.net\"><img src=\"",fp_ou
);
1708 for (i
=0 ; i
<depth
; i
++)
1710 fputs("images/sarg.png\" title=\"SARG, Squid Analysis Report Generator. Logo by Osamu Matsuzaki\" alt=\"Sarg\"></a> Squid Analysis Report Generator</div>\n",fp_ou
);
1713 void write_logo_image(FILE *fp_ou
)
1715 if(LogoImage
[0]!='\0')
1716 fprintf(fp_ou
, "<div class=\"logo\"><img src=\"%s\" width=\"%s\" height=\"%s\" alt=\"Logo\"> %s</div>\n",LogoImage
,Width
,Height
,LogoText
);
1719 void write_html_head(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1723 fputs("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n<html>\n",fp_ou
);
1724 fprintf(fp_ou
, "<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n",CharSet
);
1725 if (page_title
) fprintf(fp_ou
,"<title>%s</title>\n",page_title
);
1727 if ((javascript
& HTML_JS_SORTTABLE
)!=0 && SortTableJs
[0]) {
1728 fputs("<script type=\"text/javascript\" src=\"",fp_ou
);
1729 if (strncmp(SortTableJs
,"../",3)==0) {
1730 for (i
=0 ; i
<depth
; i
++) fputs("../",fp_ou
);
1732 fputs(SortTableJs
,fp_ou
);
1733 fputs("\"></script>\n",fp_ou
);
1735 fputs("</head>\n<body>\n",fp_ou
);
1738 void write_html_header(FILE *fp_ou
, int depth
, const char *page_title
,int javascript
)
1740 write_html_head(fp_ou
,depth
,page_title
,javascript
);
1741 write_logo_image(fp_ou
);
1742 show_sarg(fp_ou
, depth
);
1743 fprintf(fp_ou
,"<div class=\"title\"><table cellpadding=\"0\" cellspacing=\"0\">\n<tr><th class=\"title_c\">%s</th></tr>\n",Title
);
1746 void close_html_header(FILE *fp_ou
)
1748 fputs("</table></div>\n",fp_ou
);
1751 int write_html_trailer(FILE *fp_ou
)
1754 if (fputs("</body>\n</html>\n",fp_ou
)==EOF
) return(-1);
1758 void output_html_string(FILE *fp_ou
,const char *str
,int maxlen
)
1762 while (*str
&& (maxlen
<=0 || i
<maxlen
)) {
1765 fputs("&",fp_ou
);
1768 fputs("<",fp_ou
);
1771 fputs(">",fp_ou
);
1774 fputs(""",fp_ou
);
1777 fputs("'",fp_ou
);
1785 if (maxlen
>0 && i
>=maxlen
)
1786 fputs("…",fp_ou
);
1789 void output_html_url(FILE *fp_ou
,const char *url
)
1793 fputs("&",fp_ou
);
1801 Write a host name inside an A tag of a HTML file. If the host name starts
1802 with a star, it is assumed to be an alias that cannot be put inside a link
1803 so the A tag is not written around the host name.
1805 \param fp_ou The handle of the HTML file.
1806 \param url The host to display in the HTML file.
1807 \param maxlen The maximum number of characters to print into the host name.
1809 void output_html_link(FILE *fp_ou
,const char *url
,int maxlen
)
1811 if (url
[0]==ALIAS_PREFIX
) {
1812 // this is an alias, no need for a A tag
1813 output_html_string(fp_ou
,url
+1,100);
1815 if (skip_scheme(url
)==url
)
1816 fputs("<a href=\"http://",fp_ou
);//no scheme in the url, assume http:// to make the link clickable
1818 fputs("<a href=\"",fp_ou
);//the scheme is in the url, no need to add one
1819 output_html_url(fp_ou
,url
);
1821 output_html_string(fp_ou
,url
,100);
1822 fputs("</a>",fp_ou
);
1826 void url_module(const char *url
, char *w2
)
1832 for(x
=strlen(url
)-1; x
>=0; x
--) {
1833 if(url
[x
] == '/' || y
>=sizeof(w
)-1) break;
1842 for(y
=y
-1; y
>=0; y
--) {
1848 void url_to_file(const char *url
,char *file
,int filesize
)
1854 for(i
=0; i
<filesize
&& *url
; url
++) {
1855 if(isalnum(*url
) || *url
=='-' || *url
=='_' || *url
=='.' || *url
=='%') {
1859 if (!skip
) file
[i
++]='_';
1868 printf(_("SARG Version: %s\n"),VERSION
);
1872 char *get_param_value(const char *param
,char *line
)
1876 while (*line
==' ' || *line
=='\t') line
++;
1878 if (strncasecmp(line
,param
,plen
)) return(NULL
);
1879 if (line
[plen
]!=' ' && line
[plen
]!='\t') return(NULL
);
1881 while (*line
==' ' || *line
=='\t') line
++;
1885 void unlinkdir(const char *dir
,int contentonly
)
1889 struct dirent
*direntp
;
1895 while ((direntp
= readdir(dirp
)) != NULL
) {
1896 if (direntp
->d_name
[0] == '.' && (direntp
->d_name
[1] == '\0' ||
1897 (direntp
->d_name
[1] == '.' && direntp
->d_name
[2] == '\0')))
1899 if (snprintf(dname
,sizeof(dname
),"%s/%s",dir
,direntp
->d_name
)>=sizeof(dname
)) {
1900 debuga(_("directory name to delete too long: %s/%s\n"),dir
,direntp
->d_name
);
1904 err
=lstat(dname
,&st
);
1906 err
=stat(dname
,&st
);
1909 debuga(_("cannot stat %s\n"),dname
);
1912 if (S_ISREG(st
.st_mode
)) {
1913 if (unlink(dname
)) {
1914 debuga(_("cannot delete %s - %s\n"),dname
,strerror(errno
));
1917 } else if (S_ISDIR(st
.st_mode
)) {
1920 debuga(_("unknown path type %s\n"),dname
);
1927 debuga(_("cannot delete %s - %s\n"),dir
,strerror(errno
));
1934 Extract an url, IPv4 or IPv6 from a buffer. The IP addresses may end with a
1937 \param buf The buffer to parse.
1938 \param text A pointer to set to the beginning of the string pattern. No terminating zero is inserted.
1939 The pointer may be NULL.
1940 \param ipv4 A 4 bytes buffer to store the bytes of the IPv4 address.
1941 \param ipv6 A 8 short integers buffer to store the values of the IPv6 address.
1942 \param nbits The number of prefix bits for an IP address.
1943 \param next The content of the line after the extracted address.
1945 \retval 3 The pattern is a IPv6 address.
1946 \retval 2 The pattern is a IPv4 address.
1947 \retval 1 The patter is a string.
1948 \retval 0 Empty pattern.
1950 int extract_address_mask(const char *buf
,const char **text
,unsigned char *ipv4
,unsigned short int *ipv6
,int *nbits
,const char **next
)
1955 unsigned int value4
, value6
;
1956 unsigned short int addr
[8];
1966 // skip leading spaces and tabs
1967 while (*buf
&& (*buf
==' ' || *buf
=='\t')) buf
++;
1969 // find out the nature of the pattern
1970 ip_size
=0x60 | 0x04;
1981 for (i
=0 ; (unsigned char)buf
[i
]>' ' && buf
[i
]!='/' && buf
[i
]!='?' && (!bracket
|| buf
[i
]!=']') && ip_size
; i
++) {
1982 if (ip_size
& 0x04) {
1983 if (isdigit(buf
[i
])) {
1985 port_num
=port_num
*10+(buf
[i
]-'0');
1986 if (port_num
>65535) ip_size
&=~0x04;
1988 value4
=value4
*10+(buf
[i
]-'0');
1989 if (value4
>0xFFU
) ip_size
&=~0x04;
1991 } else if (buf
[i
]=='.' && addr_len
<4) {
1992 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
1994 } else if (!port
&& buf
[i
]==':') {
2000 if (ip_size
& 0x60) {
2001 if (isdigit(buf
[i
])) {
2002 value6
=(value6
<<4)+(buf
[i
]-'0');
2004 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2005 } else if (toupper(buf
[i
])>='A' && toupper(buf
[i
])<='F') {
2006 value6
=(value6
<<4)+(toupper(buf
[i
])-'A'+10);
2008 if (value6
>0xFFFFU
) ip_size
&=~0x60;
2009 } else if (buf
[i
]==':' && addr_len
<8) {
2010 if (nibble6_len
>0) {
2011 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2015 if (buf
[i
+1]==':') {
2024 if (i
==0) return(0);
2025 if (ip_size
& 0x04) {
2029 addr
[addr_len
++]=(unsigned short)(value4
& 0xFFU
);
2031 if (ip_size
& 0x60) {
2032 if (pad_pos
<0 && addr_len
!=7) {
2034 } else if (pad_pos
>=0 && addr_len
>=7)
2036 else if (nibble6_len
>0)
2037 addr
[addr_len
++]=(unsigned short)(value6
& 0xFFFFU
);
2042 if (bracket
) (*text
)--;
2044 while ((unsigned char)buf
[i
]>' ') i
++;
2045 if (next
) *next
=buf
+i
;
2048 max_mask
=(ip_size
& 0x04) ? 4*8 : 8*16;
2052 while (isdigit(buf
[i
])) i
++;
2053 if (mask
<0 || mask
>max_mask
) mask
=max_mask
;
2056 if (ip_size
& 0x60 && bracket
&& buf
[i
]==']') i
++;
2057 if (next
) *next
=buf
+i
;
2058 if (ip_size
& 0x04) {
2059 if (nbits
) *nbits
=mask
;
2060 for (i
=0 ; i
<addr_len
; i
++)
2061 ipv4
[i
]=(unsigned char)addr
[i
];
2066 if (nbits
) *nbits
=mask
;
2071 ipv6
[j
++]=(unsigned short int)addr
[i
++];
2073 while (j
<pad_pos
+pad_len
)
2077 ipv6
[j
++]=(unsigned short int)addr
[i
++];