
/* Panteltje occ-4.3 (online cost calculator) */

/* uses only LOGOUT report by dip-uri in /var/adm/messages,
/* logout report must contain the field:   online:121343s
/* uses phone companies rates specified in /root/.occrc
/* compiled with slackware 3.4
*/


#include "sys_head.h"

#define PPP_ON "Serial connection established."
#define PPP_OFF "Exit"


#define MAXENTRIES	20

int debug_flag;

main(int argc, char *argv[])
{
int a, b, c, d, e, i, j;
unsigned long la, lb;
int value;
FILE *infile;
FILE *conffile;

char messages_file_name[80];
char configuration_file_name[80];
long total_seconds;
int logins;
int seconds;
int minutes;
int hours;
char field[80];
float total_money;/* say dollar cents */
long cents;/* say dollar cents */
int units;/* say dollars */

int type;
char type_rate[MAXENTRIES][40];
int srhour[MAXENTRIES];
int srminute[MAXENTRIES];
int srsecond[MAXENTRIES];
int erhour[MAXENTRIES];
int erminute[MAXENTRIES];
int ersecond[MAXENTRIES];
float fixed_per_call[MAXENTRIES];
float cost_unit[MAXENTRIES];
int length_unit[MAXENTRIES];
int entries;

char currency_type[40];
char start_month[20];
float tax_percentage;
char start_day_of_month[20];
int start_flag;
int start_month_flag;

char month_field[40];
char day_field[40];
char time_field[40];

int all_flag;
int dip_only_flag;
int help_flag;
int last_flag;
int pppd_only_flag;
int today_flag;

char weekday[2];
char month[20];
int monthday, hour, minute, second, year;
int lhour, lminute, lsecond;
char input_line[1024];
int line_type;
char login_month[10];
int login_month_num;
int login_month_day;
char login_type_day[20];
long seconds_in_rate;
long seconds_left;
int day_of_week;
int rate_total;
int first_login_found_flag;
char first_login_month[20];
char first_login_day_of_month[20];
int diff;
int pppd_connected_flag;
int pppd_hour, pppd_minute, pppd_second;
int connect_month, disconnect_month;
struct tm *pctm;/* connect time */
struct tm *pdtm;/* disconnect time*/
time_t connecttime, disconnecttime;
char *pa;
long pppd_session_seconds, dip_session_seconds;
int warning_printed_flag;
pctm = (struct tm *) malloc(sizeof(struct tm) );
pdtm = (struct tm *) malloc(sizeof(struct tm) );

fprintf(stdout,\
"\nPanteltje (c) occ-4.3 online cost calculation 1998\n");

sprintf(configuration_file_name, "/root/.occrc");
sprintf(messages_file_name, "/var/adm/messages");
conffile = fopen(configuration_file_name, "r");
if(!conffile)
	{
	fprintf(stdout, "\nCannot open %s for read\n", configuration_file_name);
	exit(0);
	}	
infile = fopen(messages_file_name, "r");
if(! infile)
	{
	fprintf(stdout, "\nCannot open %s for read\n", messages_file_name);
	exit(0);
	}

if(last_flag)all_flag = 1;/* last time could be long time ago,
							/* read all entries */
							
/* process command line flags */
today_flag = 0;
all_flag = 0;
dip_only_flag = 0;
last_flag = 0;
pppd_only_flag = 0;
help_flag = 0;
debug_flag = 0;
if(argc != 1)/* some command line arg */
	{
	for(i = 0; i < argc; i++)
		{
		if(argv[i][0] == '-')
			{
			if(argv[i][1] == 'a')all_flag = 1;
			if(argv[i][1] == 'd')dip_only_flag = 1;
			if(argv[i][1] == 'h')help_flag = 1;
			if(argv[i][1] == 'l')last_flag = 1;
			if(argv[i][1] == 'p')pppd_only_flag = 1;
			if(argv[i][1] == 't')today_flag = 1;
			if(argv[i][1] == 'x')debug_flag = 1;
			}
		}
	}

if(help_flag)
	{
	fprintf(stdout, "\nUsage:occ [-a -d -h -l -p -t -x]\n\n");
	fprintf(stdout, "\n-a all entries in /var/messages used");
	fprintf(stdout, "\n-d use dip's entries only");
	fprintf(stdout, "\n-h this help menu");
	fprintf(stdout, "\n-l last session only");
	fprintf(stdout, "\n-p use pppd's entries only");
	fprintf(stdout, "\n-t today (this date) only");
	fprintf(stdout, "\n-x debug mode, use occ -x -d> debugfile");
	fprintf(stdout,\
	 "\n   if no arguments, start date is read from /root/.occrc");
	fprintf(stdout, "\n\n");
	exit(1);
	}

/* get present date and time */
ogettime(weekday, month, &monthday, &hour, &minute, &second, &year);

/* read .occrc file */
fscanf(conffile, "\nstart_month %s\n", start_month);
fscanf(conffile, "\nstart_day_of_month %s\n", start_day_of_month);
fscanf(conffile, "\ntax_percentage %f\n", &tax_percentage);
fscanf(conffile, "\ncurrency_type %s\n", currency_type);
entries = 0;
while(1)
	{
	fscanf(conffile, "\ntype_rate %s", &type_rate[entries]);
	fscanf(conffile, "\nstart_rate %d:%d:%d",\
	&srhour[entries], &srminute[entries], &srsecond[entries]);
	fscanf(conffile, "\nend_rate %d:%d:%d",\
	&erhour[entries], &erminute[entries], &ersecond[entries]);
	fscanf(conffile, "\nfixed_per_call %f\n", &fixed_per_call[entries]);
	fscanf(conffile, "\ncost_unit %f\n", &cost_unit[entries]);
	a =fscanf(conffile, "\nlength_unit %d\n", &length_unit[entries]);
	if(a == EOF)break;
	entries++;
	if(entries > MAXENTRIES)
		{
		fprintf(stdout, "\nTo many entries in /root/.occrc\n");
		exit(0);
		}
	}
fclose(conffile);

if(today_flag)/* set start data today */
	{
	strcpy(start_month, month);
	sprintf(start_day_of_month, "%d", monthday);
	}

	
/* report values used */
if(debug_flag)
	{
	fprintf(stdout, "\nRead from %s\n", configuration_file_name);
	fprintf(stdout, "\nstart_month %s", start_month);
	fprintf(stdout, "\nstart_day_of_month %s", start_day_of_month);	
	fprintf(stdout, "\ntax_percentage %2.2f", tax_percentage);
	fprintf(stdout, "\ncurrency_type %s", currency_type);
	fprintf(stdout, "\nEntries read %d", entries);	
	for(i = 0; i < entries; i++)
 		{
 		fprintf(stdout, "\nEntry %d", i);
 		fprintf(stdout, "\nType_rate %s", type_rate[i]);
		fprintf(stdout, "\nStart_rate %d:%d:%d",\
		srhour[i], srminute[i], srsecond[i]);
		fprintf(stdout, "\nEnd_rate %d:%d:%d",\
		erhour[i], erminute[i], ersecond[i]);
		fprintf(stdout, "\nfixed_per_call %f", fixed_per_call[i]);
		fprintf(stdout, "\ncost_unit %f", cost_unit[i]);
		fprintf(stdout, "\nlength_unit %d", length_unit[i]);
		fprintf(stdout, "\n");
		}
	}	

pppd_connected_flag = 0;
logins = 0;
total_seconds = 0;
total_money = 0;
start_flag = 0;
start_month_flag = 0;
first_login_found_flag = 0;
if(all_flag)start_flag = 1;
line_type = 0;
warning_printed_flag = 0;
while(1)
	{
	/* read a line from inputfile */
	i = 0;
	while(1)
		{
		a = getc(infile);
		if(a == EOF)
			{
			input_line[i] = 0;/* string terminator */
			line_type = EOF;
			break;
			}
		if(a == 10)
			{
			line_type = 1;
			input_line[i] = 0;/* string terminator */
			break;
			}
		input_line[i] = a;
		i++;
		if(i >= 1024)
			{
			fprintf(stdout,\
			"\nInput line in %s to long\n", messages_file_name);
			exit(0);
			}
		}/* end while all characters in an input line */		
	/* get month day and time from input line */
	sscanf(input_line, "\n%s %s %s", month_field, day_field, time_field);

	if(! first_login_found_flag)
		{
		if( (zindex(input_line, "online:") != -1) ||\
		(zindex(input_line, "Connected...") != -1) )
			{
			strcpy(first_login_month, month_field);		
			strcpy(first_login_day_of_month, day_field);
			first_login_found_flag = 1;
			}
		}
		
		if(first_login_found_flag && !warning_printed_flag)
			{
			diff = month_to_digit(month) -\
			month_to_digit(first_login_month);
			if(diff < 0)diff += 12;/* login was last year */
			if(diff > 8)/* login was more then 8 month ago */
				{
				fprintf(stdout,\
		"\nWARNING, oldest login in %s is %d month old, delete old entries",\
				messages_file_name, diff);
				warning_printed_flag = 1;
				}
			}
		
	if(!start_flag)
		{
		if(line_type == EOF)
			{
			if(today_flag)fprintf(stdout, "\nNo entries found today\n");
			else fprintf(stdout, "\nNo entries found today\n");
			exit(1);	
			}
		if( (zindex(month_field, start_month) == 0) &&\
		 (zindex(day_field, start_day_of_month) == 0) )/* start date found */
			{
			start_flag = 1;
			if(!all_flag)fprintf(stdout, "\nStarted calculation on %s %s",\
					start_month, start_day_of_month); 
			}
		else
			{
			continue;/* try next line */
			}
		}/* end if ! start_flag */

	/* test if pppd connected */
	pppd_session_seconds = 0;
	if( strstr(input_line, "pppd[") && strstr(input_line, PPP_ON) )
		{
		pppd_connected_flag = 1;
		connect_month = month_to_digit(month_field);
		/* parse the time_field */
		sscanf(time_field, "%d:%d:%d", &pppd_hour, &pppd_minute, &pppd_second);

		pctm -> tm_sec = pppd_second;
		pctm -> tm_min = pppd_minute;
		pctm -> tm_hour = pppd_hour;
		pctm -> tm_mday = atoi(day_field);
		pctm -> tm_mon = connect_month - 1;
		pctm -> tm_year = year % 100;/* for the moment */
		pctm -> tm_isdst = -1;/* daylight savings time n.a. */
		/* the following are not implemented (see /usr/include/time.h) */
		/* pctm -> tm_gmtoff = 0;*/
		/* strcp(pctm -> tm_zone, "");/* time zone 3 letters */
		connecttime = mktime(( struct tm *) pctm);
		if(debug_flag)
			{
			fprintf(stdout, "\npppd connect time time_t seconds=%lu %d\n",\
			(long)connecttime, (int)connecttime);
			}
		} 

	if(pppd_connected_flag)
		{
		if( strstr(input_line, "pppd[") && strstr(input_line, PPP_OFF) )
			{
			pppd_connected_flag = 0;
			disconnect_month = month_to_digit(month_field);
			/* parse the time_field */
			sscanf(time_field, "%d:%d:%d",\
			&pppd_hour, &pppd_minute, &pppd_second);
			pdtm -> tm_sec = pppd_second;
			pdtm -> tm_min = pppd_minute;
			pdtm -> tm_hour = pppd_hour;
			pdtm -> tm_mday = atoi(day_field);
			pdtm -> tm_mon = disconnect_month - 1;
			pdtm -> tm_year = year % 100;
			pdtm -> tm_isdst = -1;/* daylight savings time n.a. */
			/* the following are not implemented (see /usr/include/time.h) */
			/* pdtm -> tm_gmtoff = 0;*/
			/* strcp(pdtm -> tm_zone, "");/* time zone 3 letters */
			disconnecttime = mktime(( struct tm *) pdtm);

			if(debug_flag)
				{
				fprintf(stdout,\
				"pppd disconnect time time_t seconds=%lu %d\n",\
				disconnecttime, (int) disconnecttime);
				}
			if(disconnect_month < connect_month)
				{
				/* correct the start time for one year earlier */
				pctm -> tm_year -= 1;

				connecttime = mktime(pctm);
				if(debug_flag)
					{
					fprintf(stdout,\
			"pppd corrected for login was last year time_t seconds=%lu %d\n",\
					connecttime, (int) connecttime);
					}
				}
			pppd_session_seconds = disconnecttime - connecttime;

			if(debug_flag)
				{
				fprintf(stdout, "pppd session time=%lu",\
				pppd_session_seconds);
				}
			}/* end if "Connection terminated" string found */
		}/* end if pppd_connected_flag */		

	/* test if this was a line from dip reporting seconds online,
	/* dip writes 3 lines, first start date, then end date, then report */
	dip_session_seconds = 0;
	a = zindex(input_line, "online:");
			/* a holds position in input line where "online:121212s" is */
	/* pppd_session_seconds used as a flag indicating it was a pppd session */
	if(a != -1)
		{
		/* scan the input line*/
		if(debug_flag)
			{
			printf("\ninputline=%s", input_line);
			printf("\na=%d", a);
			}
		/* copy the field thats holds "online:121212s" to field */
		for(i = 0; i < 1024; i++)
			{
			b = input_line[i + a];
			if(b == ' ')
				{
				b = 0;/* string terminator */
				field[i] = 0;
				break;
				}
			field[i] = b;
			}
		if(debug_flag)
			{
			printf("\nfield=%s", field);
			printf("\ntime_field=%s", time_field);
			}
		/* get the seconds form the "online:121212s" field */								
		sscanf(field, "online:%ds", &dip_session_seconds);
		seconds_left = dip_session_seconds;
		if(debug_flag)
			{
			fprintf(stdout, "\ndip_session_seconds=%lu", dip_session_seconds);
			}
		}/* end a != -1  a dip session */

	seconds_left = pppd_session_seconds + dip_session_seconds;
	if(! (pppd_only_flag && dip_only_flag) )
		{
		if(pppd_only_flag) seconds_left = pppd_session_seconds;
		if(dip_only_flag) seconds_left = dip_session_seconds;
		}
	/* either or both are 0 */

	if(seconds_left)
		{
		if(last_flag)
			{
			logins = 0;
			total_seconds = 0;
			total_money = 0;
			}

		/* now we know what month day and year it was,
		/* can now calculate the day of week.

		/* get report month and day of month from input line,
		/* note that this is the END of the login */
		sscanf(input_line, "%s %d", login_month, &login_month_day);

		/* calculate the day of week */
		day_of_week =\
		get_day_of_week(login_month, login_month_day, year, month);
								/* using present year and month from pc */

		/* parse the time_field */
		sscanf(time_field, "%d:%d:%d", &lhour, &lminute, &lsecond);

		/* analyse_login_date */
		/* the following loop moves BACK in time from the logout moment,
		trough all time rates until no seconds are left */
		while(1)
			{
			/* want to know if weekend or weekday rate. */
			if( (day_of_week == 1) || (day_of_week == 7) )/* sun sat */
				{
				strcpy(login_type_day, "weekend");
				}
			else strcpy(login_type_day, "weekday");
			if(debug_flag)
				{
				printf("\nweekday=%d login_month=%s, day=%d, year=%d",\
							day_of_week, login_month, login_month_day, year);
				}
			/*test for the login_type_day in the entries obtained from occrc */
			type = -1;
			for(i = 0; i < entries; i++)/* for all entries read from occrc */
				{
				if(strcmp(type_rate[i], login_type_day) == 0)
					{
					/* test if in right time slot */
					if(  (lhour > srhour[i])  ||\
					( (lhour == srhour[i]) && (lminute > srminute[i]) ) ||\
					( (lhour == srhour[i]) && (lminute == srminute[i]) &&\
					(lsecond >= srsecond[i]) )  )
						{
						if( (lhour < erhour[i]) ||\
						( (lhour == erhour[i]) && (lminute < erminute[i]) ) ||\
						( (lhour == erhour[i]) && (lminute == erminute[i]) &&\
						(lsecond <= ersecond[i]) )  )
							{
							type = i;
							if(debug_flag)
								{
								printf(\
								"\nTime lhour=%d lminute=%d lsecond=%d",\
								lhour, lminute, lsecond);
								printf("\ntype day = %s type=%d",\
								login_type_day, type);
								}
							break;/* in time slot */
							}
						}/* end testing if in time slot */
					}/* end same type of day */
				}/* end for all entries in occrc */
			if(type == -1)
				{
				fprintf(stdout,\
				"\nNo valid entry found in .occrc for this login:\n %s\n",\
				input_line);
				exit(0);
				}
		
			/* now want to know how may seconds in this rate type */
			/* seconds in this rate = login time - end time of this rate */
			/* however if session_seconds < then this, it is session_seconds */
			if(debug_flag)
				{		
				printf("\nlhour=%d lminute=%d lsecond=%d ",\
						 lhour, lminute, lsecond);
				printf("srhour[type]=%d srminute[type]=%d srsecond[type]=%d",\
						 srhour[type], srminute[type], srsecond[type]);
				}

/*			/* calculate total seconds of this rate */
/*			rate_total =\
/*			(erhour[type] * 3600 + erminute[type] * 60 + ersecond[type]) -\
/*			(srhour[type] * 3600 + srminute[type] * 60 + srsecond[type]) + 1;
/*
/*			if(debug_flag)printf("\nrate_total=%d", rate_total);		
*/

			/* calculate seconds in this rate */		
			seconds_in_rate = (lhour - srhour[type]) * 3600 +\
			(lminute - srminute[type])  * 60 +\
			(lsecond - srsecond[type]);
			if(seconds_left < seconds_in_rate)seconds_in_rate = seconds_left;
		
		
			if(debug_flag)printf("\nseconds_in_rate=%d", seconds_in_rate); 

			/* calulate the cost for this rate */
			total_seconds += seconds_in_rate;
			total_money +=\
			 (seconds_in_rate / length_unit[type]) * cost_unit[type];

			seconds_left -= seconds_in_rate;/* could be zero */
	
			if(debug_flag)printf("\nseconds_left=%ld\n", seconds_left);

			if(seconds_left > 0)/* there was more in a previous rate */
								/* calculate new start */
				{
				lsecond = srsecond[type] - 1;/* jump into previous rate */
				if(lsecond < 0)
					{
					lsecond = 59;
					lminute = srminute[type] - 1;
					}				
				if(lminute < 0)
					{
					lminute = 59;
					lhour = srhour[type] - 1;
					}
				if(lhour < 0)
					{
					lhour = 23;
					day_of_week--;
					}
				if(day_of_week == 0)day_of_week = 7;/* cyclic */
				if(debug_flag)
					{
					printf("\
\nLooping new day of week=%d new hour=%d new minute=%d new second=%d",\
					day_of_week, lhour, lminute, lsecond);
					printf("\nseconds left=%ld\n", seconds_left);
					}
				}/* end seconds left > 0 */
			else break;/* seconds_left <= 0 */
			}/* end while moving back in time */
		total_money += fixed_per_call[type];
		logins++;
		}/* end if seconds_left */
	if(line_type == EOF)break;
	}/* end while all fields in infile */

/* add any taxes */
total_money *= 1.0 + (tax_percentage / 100.0);

hours = total_seconds / 3600;
a = total_seconds - hours * 3600;
minutes = a / 60;
seconds = a - minutes * 60;

/* report */
if(debug_flag)
	{
	printf("\nFirst login was %s %s",\
	first_login_month, first_login_day_of_month);
	}
if(last_flag)
	{
	fprintf(stdout, "\nlast login was %s %d", login_month, login_month_day);
	fprintf(stdout,\
	"\nTotal hours=%d minutes=%d seconds=%d cost=%s %02.2f\n\n",\
	hours, minutes, seconds, currency_type, total_money);
	}
else if(today_flag)
	{
	if(logins == 0)fprintf(stdout, "\nNo logins today");
	else fprintf(stdout, "\nTodays logins");
	fprintf(stdout,\
 	"\nLogins=%d  Total hours=%d minutes=%d seconds=%d cost=%s %02.2f\n\n",\
	logins, hours, minutes, seconds, currency_type, total_money);
	}
else if(all_flag)
	{
	fprintf(stdout, "\nUsing all entries in %s (first login ended %s %s)",\
	messages_file_name, first_login_month, first_login_day_of_month);
	fprintf(stdout,\
	 "\nLogins=%d  Total hours=%d minutes=%d seconds=%d cost=%s %02.2f\n\n",\
	logins, hours, minutes, seconds, currency_type, total_money);
	}
else
	{
	fprintf(stdout,\
	 "\nLogins=%d  Total hours=%d minutes=%d seconds=%d cost=%s %02.2f\n\n",\
	logins, hours, minutes, seconds, currency_type, total_money);
	}
if(debug_flag)fprintf(stdout, "\nTotal seconds=%ld", total_seconds);

fclose(infile);
exit(1);
}


int get_day_of_week(\
char login_month[], int login_day, int present_year, char present_month[])
{
/*  weekday  get day of week corresponding to login_month and login_day,
/* taking into account the present_month and the present_year */
int lday;
int lmonth;
int lyear;

lyear = present_year;
lyear %= 100;
lmonth = month_to_digit(login_month);
lday = login_day;
if(month_to_digit(present_month) < lmonth)
/* cross new year boundary,
/* for example: present month is Jul (7) and login month is november (10) */
	{
	lyear -= 1;/* the login was not this year, but 1 year before */
	}
lmonth -= 2;
if (lmonth <= 0)
	{
	lmonth += 12;
	lyear--;
	}
if(debug_flag)
	{
	printf(\
	"\nget_day_of_week: login_month=%s login_day=%d login_year=%d",\
	login_month, lday, lyear);
	printf(
	"\npresent_month=%s present_year=%d", present_month, present_year);
	}
return ( ( (lday + (26 * lmonth - 2) / 10 + lyear + lyear / 4 - 34) % 7) + 1);
}

month_to_digit(char *login_month)
{
int month;
if(strcmp(login_month,"Jan") == 0) month = 1; 
if(strcmp(login_month,"Feb") == 0) month = 2;
if(strcmp(login_month,"Mar") == 0) month = 3; 
if(strcmp(login_month,"Apr") == 0) month = 4; 
if(strcmp(login_month,"May") == 0) month = 5; 
if(strcmp(login_month,"Jun") == 0) month = 6; 
if(strcmp(login_month,"Jul") == 0) month = 7; 
if(strcmp(login_month,"Aug") == 0) month = 8; 
if(strcmp(login_month,"Sep") == 0) month = 9; 
if(strcmp(login_month,"Oct") == 0) month = 10;
if(strcmp(login_month,"Nov") == 0) month = 11;
if(strcmp(login_month,"Dec") == 0) month = 12;
return(month);
}


get_days_in_year_untill_now(\
char *month_field, char *day_field, int year, int *days_in_year_untill_now)
{
int a, i;

a = month_to_digit(month_field);
*days_in_year_untill_now = 0;
for(i= 1; i < a; i++)/* dont count present month */
	{
	if(i == 1) *days_in_year_untill_now += 31;
	if(i == 2)
		{
		if(year % 4 == 0) *days_in_year_untill_now += 29;
		else *days_in_year_untill_now += 28;
		}
	if(i == 3) *days_in_year_untill_now += 31;
	if(i == 4) *days_in_year_untill_now += 30;
	if(i == 5) *days_in_year_untill_now += 31;
	if(i == 6) *days_in_year_untill_now += 30;
	if(i == 7) *days_in_year_untill_now += 31;
	if(i == 8) *days_in_year_untill_now += 31;
	if(i == 9) *days_in_year_untill_now += 30;
	if(i == 10) *days_in_year_untill_now += 31;
	if(i == 11) *days_in_year_untill_now += 30;
	if(i == 12) *days_in_year_untill_now += 31;
	}
*days_in_year_untill_now += atoi(day_field);
/*
fprintf(stdout, "DAYS=%d\n", *days_in_year_untill_now);
*/
}
