/* Citadel/UX call log stats program
 * version 1.3
 */
#include <fcntl.h>
#include <time.h>

#ifdef USE_NCURSES
#include <ncurses/curses.h>
#else
#include <curses.h>
#endif

#include "citadel.h"

struct caller {
	struct caller *next;
	char Cname[30];
	int Ctimescalled;
	};

long lseek();
char *malloc();
struct config config;


void progress(text,curr,cmax)
char *text;
long curr;
long cmax; {
	static long dots_printed;
	long a;

	if (curr==0) {
		clear();	
		move(5,0);
		for (a=0; a<((80-strlen(text))/2); ++a) addch(' ');
		printw("%s\n",text);
		move(10,0);
		addch(ACS_ULCORNER);
		for (a=0; a<78; ++a) addch(ACS_HLINE);
		addch(ACS_URCORNER);
		move(11,0);
		addch(ACS_VLINE);
		move(11,79);
		addch(ACS_VLINE);
		move(12,0);
		addch(ACS_LLCORNER);
		for (a=0; a<78; ++a) addch(ACS_HLINE);
		addch(ACS_LRCORNER);
		refresh();
		dots_printed = 0;
		move(11,1);
		}
	else if (curr==cmax) {
		clear();
		refresh();
		}
	else {
		a=(curr * 100) / cmax;
		a=a*78; a=a/100;
		while (dots_printed < a) {
			addch(ACS_BLOCK);
			++dots_printed;
			refresh();
			}
		}
	}




halfhour(time)	/* Returns half-hour time period of time */
long time; {
	int a;
	struct tm *tm;
	tm=(struct tm *)localtime(&time);
	a=(tm->tm_hour)*2;
	if ((tm->tm_min)>29) ++a;
	return(a);
	}
	
main() {
	struct calllog calllog;
	struct usersupp usersupp;
	int file,pos,a,b;
	float p,q;
	long timeon[48];
	long timeup[48];
	char dname[30];
	long cftime,cttime,aa;
	int calls,calls300,calls1200,calls2400,console,logins,newusers;
	int badpws,terms,drops,sleeps;
	long from,to,tottime;
	int days,hours,minutes;
	char aaa[100];
	struct tm *tm;
	char *tstring;
	struct caller *callers = NULL;
	struct caller *callptr = NULL;
	FILE *fp,*sortpipe;

	get_config();
	initscr();
	raw();
	noecho();
	clear();
	move(10,20);
/*
	standout();
	addstr("Scanning call log, please wait...");
	standend();
	refresh();
*/

	file=open("calllog.pos",O_RDONLY);
	read(file,&pos,2);
	close(file);
	from=0L; to=0L;
	for (a=0; a<48; ++a) { timeon[a]=0L; timeup[a]=0L; }
	cftime=0L; cttime=0L;

	calls=0; calls300=0; calls1200=0; console=0; logins=0; newusers=0;
	badpws=0; terms=0; drops=0; sleeps=0;
	file=open("calllog",O_RDONLY);
	lseek(file,(long)(pos*sizeof(struct calllog)),0);
	for (a=0; a<CALLLOG; ++a) {
		progress("Scanning call log, please wait...",
			(long)a,
			(long)CALLLOG-1
			);
		if ((a+pos)==CALLLOG) lseek(file,0L,0);
		read(file,&calllog,sizeof(struct calllog));
	if (calllog.CLflags!=0) {
		if ((calllog.CLtime<from)||(from==0L)) from=calllog.CLtime;
		if ((calllog.CLtime>to)||(to==0L)) to=calllog.CLtime;
		strcpy(aaa,"");
if (calllog.CLflags&CL_IN300)	{ ++calls; ++calls300; cftime=calllog.CLtime; 
				  strcpy(dname,calllog.CLfullname); }
if (calllog.CLflags&CL_IN1200)	{ ++calls; ++calls1200; cftime=calllog.CLtime;
				  strcpy(dname,calllog.CLfullname); }
if (calllog.CLflags&CL_IN2400)	{ ++calls; ++calls2400; cftime=calllog.CLtime;
				  strcpy(dname,calllog.CLfullname); }
if (calllog.CLflags&CL_INOTHER)	{ ++calls; ++console; cftime=calllog.CLtime;
				  strcpy(dname,calllog.CLfullname); }
if (calllog.CLflags&CL_LOGIN)	{
	++logins;
	b=0;
	for (callptr=callers; callptr!=NULL; callptr=callptr->next) {
		if (!strcmp(callptr->Cname,calllog.CLfullname)) {
			++b;
			++callptr->Ctimescalled;
			}
		}
	if (b==0) {
		callptr = (struct caller *)malloc(sizeof(struct caller));
		callptr->next = callers;
		callers = callptr;
		strcpy(callers->Cname,calllog.CLfullname);
		callers->Ctimescalled = 1;
		}
	}
if (calllog.CLflags&CL_NEWUSER)	++newusers;
if (calllog.CLflags&CL_BADPW)	++badpws;
if (calllog.CLflags&CL_TERMINATE) { ++terms; cttime=calllog.CLtime; 
	if ((cftime!=0L)&&(cttime!=0L)&&(!strcmp(dname,calllog.CLfullname)))
		for (aa=cftime; aa<=cttime; aa=aa+300L)
			timeon[halfhour(aa)]=timeon[halfhour(aa)]+5L;
	cftime=0L; cttime=0L;
}
if (calllog.CLflags&CL_DROPCARR) { ++drops; cttime=calllog.CLtime; 
	if ((cftime!=0L)&&(cttime!=0L)&&(!strcmp(dname,calllog.CLfullname)))
		for (aa=cftime; aa<=cttime; aa=aa+300L)
			timeon[halfhour(aa)]=timeon[halfhour(aa)]+5L;
	cftime=0L; cttime=0L;
}
if (calllog.CLflags&CL_SLEEPING) { ++sleeps; cttime=calllog.CLtime;
	if ((cftime!=0L)&&(cttime!=0L)&&(!strcmp(dname,calllog.CLfullname)))
		for (aa=cftime; aa<=cttime; aa=aa+300L)
			timeon[halfhour(aa)]=timeon[halfhour(aa)]+5L;
	cftime=0L; cttime=0L;
}


		}
		}
	close(file);
	tottime=to-from;
	days=(int)(tottime/86400L);
	hours=(int)((tottime%86400L)/3600L);
	minutes=(int)((tottime%3600L)/60L);

	clear();
	move(3,3);	addstr("300 bps calls:");
	move(4,2);	addstr("1200 bps calls:");
	move(5,2);	addstr("2400 bps calls:");
	move(6,0);	addstr("High Speed calls:");
	move(7,10);	addstr("Logins:");
	move(8,7);	addstr("New users:");
	move(9,1);	addstr("Bad pw attempts:");
	move(10,2);	addstr("Proper logoffs:");
	move(11,3);	addstr("Carrier drops:");
	move(12,2);	addstr("Sleeping drops:");
	move(13,5);	addstr("TOTAL CALLS:");
	refresh();
	move(2,43);	addstr("Total");
	move(2,33);	addstr("Avg/Day");
	move(2,23);	addstr("Avg/Call");
	move(18,19);	addstr("From:");
	move(19,21);	addstr("To:");
	move(20,6);	addstr("Total report time:");
	move(21,12);	addstr("Total calls:");
	refresh();

	move(21,25);	printw("%d",calls);
	move(3,41);	printw("%9d",calls300);
	move(4,41);	printw("%9d",calls1200);
	move(5,41);	printw("%9d",calls2400);
	move(6,41);	printw("%9d",console);
	move(7,41);	printw("%9d",logins);
	move(8,41);	printw("%9d",newusers);
	move(9,41);	printw("%9d",badpws);
	move(10,41);	printw("%9d",terms);
	move(11,41);	printw("%9d",drops);
	move(12,41);	printw("%9d",sleeps);
	move(13,41);	printw("%9d",calls);
	refresh();

	move(3,31);	printw("%9.1f",(float)calls300/days);
	move(4,31);	printw("%9.1f",(float)calls1200/days);
	move(5,31);	printw("%9.1f",(float)calls2400/days);
	move(6,31);	printw("%9.1f",(float)console/days);
	move(7,31);	printw("%9.1f",(float)logins/days);
	move(8,31);	printw("%9.1f",(float)newusers/days);
	move(9,31);	printw("%9.1f",(float)badpws/days);
	move(10,31);	printw("%9.1f",(float)terms/days);
	move(11,31);	printw("%9.1f",(float)drops/days);
	move(12,31);	printw("%9.1f",(float)sleeps/days);
	move(13,31);	printw("%9.1f",(float)calls/days);
	refresh();

	move(3,21);	printw("%9.1f",(float)calls300/calls);
	move(4,21);	printw("%9.1f",(float)calls1200/calls);
	move(5,21);	printw("%9.1f",(float)calls2400/calls);
	move(6,21);	printw("%9.1f",(float)console/calls);
	move(7,21);	printw("%9.1f",(float)logins/calls);
	move(8,21);	printw("%9.1f",(float)newusers/calls);
	move(9,21);	printw("%9.1f",(float)badpws/calls);
	move(10,21);	printw("%9.1f",(float)terms/calls);
	move(11,21);	printw("%9.1f",(float)drops/calls);
	move(12,21);	printw("%9.1f",(float)sleeps/calls);
	move(13,21);	printw("%9.1f",(float)calls/calls);
	refresh();

	tm=(struct tm *)localtime(&from);
	tstring=(char *)asctime(tm);
	move(18,25);	addstr(tstring);
	tm=(struct tm *)localtime(&to);
	tstring=(char *)asctime(tm);
	move(19,25);	addstr(tstring);
	move(20,25);	printw("%d days, %d hours, %d minutes",
				days,hours,minutes);
	refresh();

	move(23,0);
	addstr("(please wait)");
	refresh();
	for (aa=from; aa<=to; aa=aa+1800L)
			timeup[halfhour(aa)]=timeup[halfhour(aa)]+30L;
	move(23,0);
	addstr("Press return to continue...\n");
	move(0,0);
	refresh();
	a=getc(stdin);
	
	clear();
	move(21,6);
	addstr("0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2");
	move(22,6);
	addstr("0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3");
	for (a=0; a<21; ++a) {
		move(a,4);
		addch('%');
		}
	for (a=0; a<=20; ++a) {
		move(20-a,1);
		printw("%3d",a*5);
		}
	refresh();
	for (b=0; b<48; ++b) {
		for (a=0; a<=20; ++a) {
			p=((float)timeon[b])/((float)timeup[b])*20;
			q=(float)a;
			if (p>=q) {
				move(20-a,6+b);
#ifdef ACS_BLOCK
				addch(ACS_BLOCK);
#else
				addch('#');
#endif
				}
			}
		}
	move(23,0);
	addstr("Press return to continue...");
	move(0,0);
	refresh();
	a=getc(stdin);
	clear();
	refresh();
	endwin();

	printf("Top 20 Callers (sorted by total number of logins)\n");
	printf("Calls Avg/Day Username\n");
	printf("----- ------- ------------------------------\n");
	fflush(stdout);
	sortpipe = (FILE *)popen("sort |tail -20 |sort -r","w");
	for (callptr=callers; callptr!=NULL; callptr=callptr->next) {
		fprintf(sortpipe,"%5d %7.2f %-30s\n",
			callptr->Ctimescalled,
			(((float)callptr->Ctimescalled) / ((float)days)),
			callptr->Cname);
		}
	pclose(sortpipe);
	while(callers!=NULL) {
		callptr = callers->next;
		free(callers);
		callers = callptr;
		}
	printf("Press RETURN to continue...\n");
	a=getc(stdin);

	initscr();
	clear();
	refresh();
	endwin();
	printf("Top 20 Contributing Users (post to call ratio)\n");
	printf("P/C Ratio Username\n");
	printf("--------- ------------------------------\n");
	fflush(stdout);
	sortpipe = (FILE *)popen("sort |tail -20 |sort -r","w");
	fp=fopen("usersupp","r");
	while ((fp!=NULL)
	      &&(fread((char *)&usersupp,sizeof(struct usersupp),1,fp)>0)) {
		fprintf(sortpipe,"%9.2f %-30s\n",
			((float)usersupp.posted / (float)usersupp.timescalled ),
			usersupp.fullname);
		}
	fclose(fp);
	pclose(sortpipe);
	exit(0);
	}
