/*
SRG - Squid Report Generator
Copyright 2003 University of Waikato
This file is part of SRG.
SRG is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SRG is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SRG; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "srg.h"
#include "config.h"
#include "prototypes.h"
/* Compares two date strings of the format YYYYMMMDD-YYYYMMDD. Returns true if
* date1 is less than date2.
* Dates are compared on the start date first and then the end date if
* necessary
*/
int compare_datename(const char *date1, const char *date2)
{
int rv=0;
char tmp1[10];
char tmp2[10];
/* Exit Immediately if we weren't passed valid dates */
if(date1==NULL || date2==NULL)
return -1;
if (strlen(date1) != 19 || strlen(date2) != 19)
return -1;
/* Extract the start dates */
strncpy(tmp1, date1, 9);
strncpy(tmp2, date2, 9);
tmp1[9] = tmp2[9] = '\0';
rv = compare_datepart(tmp1, tmp2);
/* If start dates were identical, compare end dates */
if (rv==0) {
strncpy(tmp1, date1+10, 9);
strncpy(tmp2, date2+10, 9);
tmp1[9] = tmp2[9] = '\0';
rv = compare_datepart(tmp1, tmp2);
}
/* Convert greater than to false */
if (rv==-1)
rv=0;
return rv;
}
/* Compares two date strings of the format YYYYMMMDD. Returns true if date1 is
* less than date2 false if they are equal or -1 if date1 is greater than
* date2.
*/
int compare_datepart(const char *date1, const char *date2) {
char year1[5], year2[5];
char month1[4], month2[4];
char day1[3], day2[3];
/* Exit Immediately if we weren't passed valid dates */
if(date1==NULL || date2==NULL)
return -1;
if (strlen(date1) != 9 || strlen(date2) != 9)
return -1;
/* Break the start dates out into their components */
strncpy(year1, date1, 4);
year1[4] = '\0';
strncpy(month1, date1+4, 3);
month1[3] = '\0';
strncpy(day1, date1+7, 2);
day1[2] = '\0';
strncpy(year2, date2, 4);
year2[4] = '\0';
strncpy(month2, date2+4, 3);
month2[3] = '\0';
strncpy(day2, date2+7, 2);
day2[2] = '\0';
/* Compare Years */
if (atoi(year1) < atoi(year2))
return 1;
else if (atoi(year1) > atoi(year2))
return -1;
/* Compare Months */
if (getMonthByName(month1) < getMonthByName(month2))
return 1;
else if (getMonthByName(month1) > getMonthByName(month2))
return -1;
/* Compare Days */
if (atoi(day1) < atoi(day2))
return 1;
else if (atoi(day1) > atoi(day2))
return -1;
/* Greater than or Equal */
return 0;
}
/* Generates a suitable date string from the specified start and end times.
* The generated string will be in the format YYYYMMMDD-YYYYMMDD and will be
* asprintf'd in to the supplied char*
*
* Returns 0 on success, > 0 on failure
*/
char *generate_datename(const time_t start, const time_t end) {
if (start < 1 || end < 1)
return NULL;
char *outstr = NULL;
char sday[3];
char eday[3];
sprintf(sday, "%02d", localtime(&start)->tm_mday);
sprintf(eday, "%02d", localtime(&end)->tm_mday);
asprintf(&outstr, "%d%s%s-%d%s%s", localtime(&start)->tm_year+1900,
month_names[localtime(&start)->tm_mon], sday,
localtime(&end)->tm_year+1900,
month_names[localtime(&end)->tm_mon], eday);
return outstr;
}
/* Write the HTML header */
void html_header(FILE *outfile, const char *rootpath) {
/* rootpath is used when the user is generating a stock standard
report with no outputURL set. Each report sends through a string
like ../../ that provides a path from the directory that this
file will reside in to the top level output directory. This string
is only used if srg.outputURL is not set
*/
char *base="";
if (strlen(srg.outputURL)==0 && strlen(rootpath)>0)
base = strdup(rootpath);
/* Header & Title */
if (srg.usephp && srg.phpheader!=NULL) {
/* Include the specified PHP header */
fprintf(outfile, "\n",
srg.phpheader);
if (srg.authenticate) {
fprintf(outfile, "\n\t");
}
} else {
/* Output a static HTML Header */
fprintf(outfile, "\n");
fprintf(outfile, "\n
\n\n", srg.title);
}
if (strlen(base)>0)
free(base);
}
/* Write the HTML footer */
void html_footer(FILE *outfile, const char *rootpath) {
/* rootpath is used when the user is generating a stock standard
report with no outputURL set. Each report sends through a string
like ../../ that provides a path from the directory that this
file will reside in to the top level output directory. This string
is only used if srg.outputURL is not set
*/
char *base="";
if (strlen(srg.outputURL)==0 && strlen(rootpath)>0)
base = strdup(rootpath);
fprintf(outfile, "\n\n", HOME_URL, version);
if (srg.usephp && srg.phpfooter!=NULL) {
/* Include the specified PHP footer */
fprintf(outfile, "\n");
if (srg.usejs) {
fprintf(outfile, "\n", base, srg.jsfile);
}
fprintf(outfile, "\n");
}
if (strlen(base)>0)
free(base);
}
/* Determines whether the specified Cache Result Code is a cache hit */
bool is_cache_hit(const char * inputCode) {
// Extract the result code from the status code
bool hit=false;
char *resultCode;
char *tmp = strdup(inputCode);
break_string(tmp, '/');
resultCode = tmp;
if (!resultCode) {
fprintf(stderr, "Incorrect result code! %s\n", inputCode);
exit(1);
}
if (srg.debug)
fprintf(stderr, "Checking if %s is a cache hit\n",
inputCode);
if (strcasecmp(resultCode, "TCP_HIT")==0)
hit = true;
else if (strcasecmp(resultCode, "TCP_REFRESH_HIT")==0)
hit = true;
else if (strcasecmp(resultCode, "TCP_REF_FAIL_HIT")==0)
hit = true;
else if (strcasecmp(resultCode, "TCP_IMS_HIT")==0)
hit = true;
else if (strcasecmp(resultCode, "TCP_NEGATIVE_HIT")==0)
hit = true;
else if (strcasecmp(resultCode, "TCP_MEM_HIT")==0)
hit = true;
else if (strcasecmp(resultCode, "TCP_OFFLINE_HIT")==0)
hit = true;
else if (strcasecmp(resultCode, "UDP_HIT")==0)
hit = true;
resultCode = NULL;
free(tmp);
return hit;
}
/* Determines whether the specified Cache Result Code was a deny */
bool is_cache_denied(const char * inputCode) {
// Extract the result code from the status code
bool denied=false;
char *resultCode;
char *tmp = strdup(inputCode);
break_string(tmp, '/');
resultCode = tmp;
if (!resultCode) {
fprintf(stderr, "Incorrect result code! %s\n", inputCode);
exit(1);
}
if (srg.debug)
fprintf(stderr, "Checking if %s is a cache denied\n",
inputCode);
if (strcasecmp(resultCode, "TCP_DENIED")==0)
denied = true;
else if (strcasecmp(resultCode, "UDP_DENIED")==0)
denied = true;
resultCode = NULL;
free(tmp);
return denied;
}
/* Converts a short 3-char month abbreviation into it's numerical equivalent */
int getMonthByName(const char *month_name) {
if (strcasecmp(month_name,"Jan")==0)
return 0;
else if (strcasecmp(month_name,"Feb")==0)
return 1;
else if (strcasecmp(month_name,"Mar")==0)
return 2;
else if (strcasecmp(month_name,"Apr")==0)
return 3;
else if (strcasecmp(month_name,"May")==0)
return 4;
else if (strcasecmp(month_name,"Jun")==0)
return 5;
else if (strcasecmp(month_name,"Jul")==0)
return 6;
else if (strcasecmp(month_name,"Aug")==0)
return 7;
else if (strcasecmp(month_name,"Sep")==0)
return 8;
else if (strcasecmp(month_name,"Oct")==0)
return 9;
else if (strcasecmp(month_name,"Nov")==0)
return 10;
else if (strcasecmp(month_name,"Dec")==0)
return 11;
assert(0);
return -1;
}
unsigned int getNumericalIP(const char *IPAddress) {
unsigned int address=0;
/* Get the four components of the IP Address */
unsigned int o1, o2, o3, o4;
if (sscanf(IPAddress, "%i.%i.%i.%i", &o1, &o2, &o3, &o4) != 4) {
fprintf(stderr, "Invalid IP Address: %s\n", IPAddress);
exit(1);
}
assert(o1<256 && o2 <256 && o3<256 && o4<256);
/* Convert it to decimal */
address = (o1<<24)&(o2<<16)&(o3<<8)&(o4);
return address;
}
char *getStringIP(const unsigned int IPAddress) {
char *address;
asprintf(&address, "%i.%i.%i.%i", (IPAddress>>24)&0xff,
(IPAddress>>16)&0xff, (IPAddress>>8)&0xff, (IPAddress)&0xff);
return address;
}
void getNetworkAddress(const in_addr clientAddress,
const in_addr netmask, in_addr *network) {
network->s_addr = ((clientAddress.s_addr|(~netmask.s_addr))&
netmask.s_addr);
}
char * cleanseStr(char * dirty) {
for (unsigned int i = 0; i < strlen(dirty); i++) {
if (dirty[i] == ' ' || dirty[i] == '\t' || dirty[i] == '\n') {
dirty[i] = '_';
} else {
switch(dirty[i]) {
case '/': dirty[i] = '^'; break;
case '.': dirty[i] = '_'; break;
case '?': dirty[i] = '^'; break;
case '|': dirty[i] = '^'; break;
case '&': dirty[i] = '^'; break;
case ';': dirty[i] = '^'; break;
case '(': dirty[i] = '^'; break;
case ')': dirty[i] = '^'; break;
case '*': dirty[i] = '^'; break;
case '@': dirty[i] = '^'; break;
case '$': dirty[i] = '^'; break;
case '`': dirty[i] = '^'; break;
case '"': dirty[i] = '^'; break;
case '#': dirty[i] = '^'; break;
case '!': dirty[i] = '^'; break;
case '[': dirty[i] = '^'; break;
case ']': dirty[i] = '^'; break;
//dirty.insert(i-1, "\\"); break; <- no good
}
}
}
return dirty;
}
char * FormatOutput(unsigned long long num) {
int SrcLen;
int ExtLen;
int c;
int d;
int grp;
int group = 3;
char sep_char = ',';
char buf[50];
sprintf(buf, "%llu", num);
SrcLen = strlen(buf)-1;
ExtLen = SrcLen+(SrcLen/group);
char *Work = (char *)malloc(ExtLen+2);
grp = 0;
c = ExtLen;
d = SrcLen;
if (c > grp) {
while (c >= 0) {
if (grp == group) {
Work[c]= sep_char;
--c;
grp = 0;
}
Work[c] = buf[d];
--c;
--d;
++grp;
}
Work[ExtLen+1] = '\0';
} else {
free(Work);
Work = strdup(buf);
}
return Work;
}
/* Return the MD5 Hash of the specified string */
char *md5this(const char plaintextstr[])
{
md5_state_t hash_state;
md5_byte_t digest[16];
char hex_output[64];
int di;
md5_init(&hash_state);
md5_append(&hash_state, (const md5_byte_t *) plaintextstr,
strlen(plaintextstr));
md5_finish(&hash_state, digest);
for (di = 0; di < 16; ++di) {
sprintf(hex_output + di*2, "%02x", digest[di]);
}
return strdup(hex_output);
}
/* Replaces the first occurence of delim with a null character and returns a
* pointer to the next character after it or NULL if there is no more string
* left. */
char *break_string(char *string, char delim)
{
unsigned int i=0;
bool delimfound=false;
while (string[i] != '\0') {
if (string[i] == delim) {
string[i] = '\0';
delimfound = true;
}
i++;
if (delimfound) {
return &string[i];
}
}
return NULL;
}