/*
                   UUTraf - UUCP traffic statistics

	  This  programm  is designed to provide us with the ability
	to  have  an  short overview of our UUCP transmissions, i.e.
	the whole UUCP traffic on our system.

 	Genesis     : Sat Feb 15 14:11:09 1992
 	Last Change : Sun Jun  7 19:02:19 1992

	Developed and debugged with SAS/C Compiler V5.10a
	running under Kickstart 34.5, Workbench 34.20 and ARP 39.1
	on an european PAL-Amiga 2000 B Rev 4.3 with 3MB RAM.

                                       Ralf S. Engelschall
                                       rse@angle.muc.sub.org
																			*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "cus.h"
#include "defines.h"
#include "lbio.h"
#include "proto.h"

#define STATFILE "uuspool:xferstat"
#define LSYSFILE "uulib:l.sys"

#define LASTLN_UNRECOGNICED 0
#define LASTLN_FIRST 1
#define LASTLN_SECOND 2

static struct TotalStat {
	unsigned int Sites;
	unsigned int FilesRecv, FilesSent, Files;
	unsigned int SecondRecv, SecondSent, Second;
	unsigned int BytesRecv, BytesSent, Bytes;
	float AvCpsRecv, AvCpsSent;
} TotalStatStruct;

struct HostStat {
	char Hostname[10];
	unsigned int BytesRecv, BytesSent, Bytes;
	unsigned int SecondRecv, SecondSent;
	float AvCpsRecv, AvCpsSent;
	unsigned int FilesRecv, FilesSent;
};

static struct HostStat *HostStatList[ 50 * sizeof(struct HostStat *) ];

/*  d hostname dd-mm-yy hh:mm:ss > dd-mm-yy hh:mm:ss hh:mm:ss BR_CPS NE_CPS ppp%
    | p option bytes_i  bytes_o    fbytes_i fbytes_o fcnt_i fcnt_o

    < horga    23-10-91 07:38:06 > 23-10-91 07:51:04 (00:12:58)  1401   1169  83%
    | g 3   64  1000935    89605 #   909846        0 #   26    0
*/

static struct CurInput {
	char direction[3], hostname[10], startday[10], starttime[10], nothing1[3],
		 endday[10], endtime[10], xfertime[12], brcps[8], necps[8], ne2br[6];
	char nothing2[3], protocol[3], windows[3], packbytes[6],
		 bytesi[10], byteso[10], nothing3[3], fbytesi[10], fbyteso[10],
		 nothing4[3], fcnti[10], fcnto[10];
} CurInputStruct;

#define CONFIGFILE "uulib:config"
#define LOCALHOSTFIELD "NodeName"

void calchoststat(void)
{
	int i;
	struct HostStat *HostStat;
	struct CurInput *CurInput = &CurInputStruct;

	i = 0;
	while (HostStatList[i] != NULL) {
		if (strcmp(CurInput->hostname, HostStatList[i]->Hostname) == 0) {
			break;
		}
		++i;
	}
	if (HostStatList[i] == NULL) {
		if (!inlsys(LSYSFILE, CurInput->hostname))
			return;
		if ((HostStat = (struct HostStat *)malloc(sizeof(struct HostStat))) == NULL)
			return;
		HostStatList[i] = HostStat;
		HostStatList[i+1] = NULL;
		memset(HostStat, NUL, sizeof(struct HostStat));
		strcpy(HostStat->Hostname, CurInput->hostname);
	}
	HostStat = HostStatList[i];

	HostStat->BytesRecv += atoi(CurInput->fbytesi);
	HostStat->BytesSent += atoi(CurInput->fbyteso);
	HostStat->Bytes = HostStat->BytesRecv + HostStat->BytesSent;

	if (atoi(CurInput->necps) != 0) {
		HostStat->SecondRecv += (int) (atoi(CurInput->fbytesi) / atoi(CurInput->necps));
		HostStat->SecondSent += (int) (atoi(CurInput->fbyteso) / atoi(CurInput->necps));
	}

	if (HostStat->SecondRecv != 0)
		HostStat->AvCpsRecv = (HostStat->BytesRecv / HostStat->SecondRecv);
	if (HostStat->SecondSent != 0)
		HostStat->AvCpsSent = (HostStat->BytesSent / HostStat->SecondSent);

	HostStat->FilesRecv += atoi(CurInput->fcnti);
	HostStat->FilesSent += atoi(CurInput->fcnto);

	return;
}


void calctotalstat(void)
{
	int i;
	struct TotalStat *TotalStat = &TotalStatStruct;

	memset(TotalStat, NUL, sizeof(struct TotalStat));
	i = 0;
	while (HostStatList[i] != NULL) {
		TotalStat->FilesSent  += HostStatList[i]->FilesSent;
		TotalStat->FilesRecv  += HostStatList[i]->FilesRecv;
		TotalStat->Files       = TotalStat->FilesSent + TotalStat->FilesRecv;
		TotalStat->SecondSent += HostStatList[i]->SecondSent;
		TotalStat->SecondRecv += HostStatList[i]->SecondRecv;
		TotalStat->Second      = TotalStat->SecondSent + TotalStat->SecondRecv;
		TotalStat->BytesSent  += HostStatList[i]->BytesSent;
		TotalStat->BytesRecv  += HostStatList[i]->BytesRecv;
		TotalStat->Bytes       = TotalStat->BytesSent + TotalStat->BytesRecv;
		TotalStat->AvCpsSent  += HostStatList[i]->AvCpsSent;
		TotalStat->AvCpsRecv  += HostStatList[i]->AvCpsRecv;
		++i;
	}
	TotalStat->AvCpsSent  = TotalStat->AvCpsSent / i;
	TotalStat->AvCpsRecv  = TotalStat->AvCpsRecv / i;
	TotalStat->Sites = i;

	return;
}


void printhoststat(void)
{
	time_t t;
	struct tm *tm;
	int i = 0;
	char buf[100];
	char buf2[100];
	struct HostStat *HostStat;
	struct TotalStat *TotalStat = &TotalStatStruct;
	char *cpBuf;

	(void)time(&t);
	tm = localtime(&t);

	if ((cpBuf = getfield(CONFIGFILE, LOCALHOSTFIELD, buf)) == NULL)
		cpBuf = "-unknown-";
	else
		truncdomain(cpBuf);
	sprintf(buf2, "%-8s", cpBuf);
	buf2[8] = NUL;
	sprintf(buf, "%s", asctime(tm));
	buf[strlen(buf)-1] = NUL;
	printf(	"\n UUTraf Host Status on %s                      %s\n\n", buf2, buf);

	printf(	" Remote   -----------K-Bytes----------- ----Hours---- --Avg CPS-- ---Files---\n"
			"  Host         Recv      Sent     Total   Recv   Sent  Recv  Sent  Recv  Sent\n"
			" -------- --------- --------- --------- ------ ------ ----- ----- ----- -----\n");
	while (HostStatList[i] != NULL) {
		HostStat = HostStatList[i];
		strncpy(buf, HostStat->Hostname, 9);
		buf[9]='\0';
		printf(" %-9s", buf);
		sprintf(buf, "%5.1f", (double)HostStat->BytesRecv / 1000);
		printf("%9s ", buf);
		sprintf(buf, "%5.1f", (double)HostStat->BytesSent / 1000);
		printf("%9s ", buf);
		sprintf(buf, "%5.1f", (double)HostStat->Bytes / 1000);
		printf("%9s ", buf);
		sprintf(buf, "%5.1f", (double)HostStat->SecondRecv / 3600);
		printf("%6s ", buf);
		sprintf(buf, "%5.1f", (double)HostStat->SecondSent / 3600);
		printf("%6s ", buf);
		sprintf(buf, "%5.0f", HostStat->AvCpsRecv);
		printf("%5s ", buf);
		sprintf(buf, "%5.0f", HostStat->AvCpsSent);
		printf("%5s ", buf);
		printf("%5d ", HostStat->FilesRecv);
		printf("%5d\n", HostStat->FilesSent);
		++i;
	}

	/* not used : TotalStat->Sites
                  (double)TotalStat->Second / 3600
	*/

	printf( " -------- --------- --------- --------- ------ ------ ----- ----- ----- -----\n"
			" Total    " );

	sprintf(buf, "%5.1f", (double)TotalStat->BytesRecv / 1000);
	printf("%9s ", buf);
	sprintf(buf, "%5.1f", (double)TotalStat->BytesSent / 1000);
	printf("%9s ", buf);
	sprintf(buf, "%5.1f", (double)TotalStat->Bytes / 1000);
	printf("%9s ", buf);
	sprintf(buf, "%5.1f", (double)TotalStat->SecondRecv / 3600);
	printf("%6s ", buf);
	sprintf(buf, "%5.1f", (double)TotalStat->SecondSent / 3600);
	printf("%6s ", buf);
	sprintf(buf, "%5.0f", TotalStat->AvCpsRecv);
	printf("%5s ", buf);
	sprintf(buf, "%5.0f", TotalStat->AvCpsSent);
	printf("%5s ", buf);
	printf("%5d ", TotalStat->FilesRecv);
	printf("%5d\n\n", TotalStat->FilesSent);

	return;
}

int uutraf(void)
{
	FILE *fpStat = NULL;
	char *cpStat = STATFILE;
	char *cpStatbuf = NULL;
	int wStat;
	LB *lbStat = NULL;
	int rc;
	char caLn[128];
	int	wLastLn = LASTLN_UNRECOGNICED;
	char *cp;
	struct CurInput *CurInput = &CurInputStruct;

	if ((fpStat = fopen(cpStat, "r")) == NULL)
		CU(FALSE);
	if (fseek(fpStat, 0L, SEEK_END) == -1L)
		CU(FALSE);
	if ((wStat = ftell(fpStat)) == -1L)
		CU(FALSE);
	if (fseek(fpStat, 0L, SEEK_SET) == -1L)
		CU(FALSE);
	if ((cpStatbuf = (char *)malloc(wStat)) == NULL)
		CU(FALSE);
	if ((fread(cpStatbuf, wStat, 1, fpStat) != 1) && ferror(fpStat))
		CU(FALSE);
	if ((lbStat = lbopen(cpStatbuf, cpStatbuf + wStat - 1)) == NULL)
		CU(FALSE);
	if (lbseek(lbStat, 0, LBSEEK_SET) == NULL)
		CU(FALSE);

	HostStatList[0] = NULL;

	do {
		memcpy(caLn, lbStat->lb_cpLnCur, lbStat->lb_wLnCur);
		*(caLn + lbStat->lb_wLnCur) = NUL;

		if (*(lbStat->lb_cpLnCur) == '#')
			continue;

		if (wLastLn == LASTLN_UNRECOGNICED
			 && (	*(lbStat->lb_cpLnCur) == '<'
				||	*(lbStat->lb_cpLnCur) == '>'
				||	*(lbStat->lb_cpLnCur) == '=' ) ) {

			cp = stpblk(caLn);
			cp = stpblk(stptok(cp, CurInput->direction, sizeof(CurInput->direction), " \t"));
			cp = stpblk(stptok(cp, CurInput->hostname , sizeof(CurInput->hostname) , " \t"));
			cp = stpblk(stptok(cp, CurInput->startday , sizeof(CurInput->startday) , " \t"));
			cp = stpblk(stptok(cp, CurInput->starttime, sizeof(CurInput->starttime), " \t"));
			cp = stpblk(stptok(cp, CurInput->nothing1 , sizeof(CurInput->nothing1) , " \t"));
			cp = stpblk(stptok(cp, CurInput->endday   , sizeof(CurInput->endday)   , " \t"));
			cp = stpblk(stptok(cp, CurInput->endtime  , sizeof(CurInput->endtime)  , " \t"));
			cp = stpblk(stptok(cp, CurInput->xfertime , sizeof(CurInput->xfertime) , " \t"));
			cp = stpblk(stptok(cp, CurInput->brcps    , sizeof(CurInput->brcps)    , " \t"));
			cp = stpblk(stptok(cp, CurInput->necps    , sizeof(CurInput->necps)    , " \t"));
			cp = stpblk(stptok(cp, CurInput->ne2br    , sizeof(CurInput->ne2br)    , " \t"));

			wLastLn = LASTLN_FIRST;
			continue;
		}

		if (wLastLn == LASTLN_FIRST && *(lbStat->lb_cpLnCur) == '|') {

			cp = stpblk(caLn);
			cp = stpblk(stptok(cp, CurInput->nothing2 , sizeof(CurInput->nothing2) , " \t"));
			cp = stpblk(stptok(cp, CurInput->protocol , sizeof(CurInput->protocol) , " \t"));
			cp = stpblk(stptok(cp, CurInput->windows  , sizeof(CurInput->windows)  , " \t"));
			cp = stpblk(stptok(cp, CurInput->packbytes, sizeof(CurInput->packbytes), " \t"));
			cp = stpblk(stptok(cp, CurInput->bytesi   , sizeof(CurInput->bytesi)   , " \t"));
			cp = stpblk(stptok(cp, CurInput->byteso   , sizeof(CurInput->byteso)   , " \t"));
			cp = stpblk(stptok(cp, CurInput->nothing3 , sizeof(CurInput->nothing2) , " \t"));
			cp = stpblk(stptok(cp, CurInput->fbytesi  , sizeof(CurInput->fbytesi)  , " \t"));
			cp = stpblk(stptok(cp, CurInput->fbyteso  , sizeof(CurInput->fbyteso)  , " \t"));
			cp = stpblk(stptok(cp, CurInput->nothing4 , sizeof(CurInput->nothing2) , " \t"));
			cp = stpblk(stptok(cp, CurInput->fcnti    , sizeof(CurInput->fcnti)    , " \t"));
			cp = stpblk(stptok(cp, CurInput->fcnto    , sizeof(CurInput->fcnto)    , " \t"));

			(void) calchoststat();
			wLastLn = LASTLN_UNRECOGNICED;
			continue;
		}

		/* printf("\nskipping unrecognized line\n"); */

	} while(lbseek(lbStat, 1, LBSEEK_CUR));

	(void) calctotalstat();
	(void) printhoststat();

	rc = TRUE;

CUS:
	if (lbStat)
		lbfree(lbStat);
	if (cpStat)
		free(cpStatbuf);
	if (fpStat)
		fclose(fpStat);
	return rc;
}


int main(int argc, char **argv)
{
	char opt;
	char *optarg;
	char *optstr;
	int optidx;

	char *cpProgname;
	char *cp;
	int rc = DOSRC_SUCCESS;

	cpProgname = strlwr(argv[0]);
	if (	(cp = strrchr(cpProgname, '/')) != NULL
		 ||	(cp = strrchr(cpProgname, ':')) != NULL	)
		cpProgname = ++cp;

	optidx = 1;
	optstr = "";
	for ( ; (optarg = argopt(argc, argv, optstr, &optidx, &opt)) != NULL; ) {
		switch(opt) {
			case 'v':	giveversioninfo(cpProgname);
						CU(DOSRC_SUCCESS);

			case '?':	giveusage(cpProgname);
						CU(DOSRC_SUCCESS);

			default :	printf("Ignored bad option '%c'", opt);
		}
	}
	for ( ; optidx < argc; optidx++)
		printf("Ignored arg '%s'", argv[optidx]);

	if (uutraf())
		CU(DOSRC_SUCCESS);
	else
		CU(DOSRC_FAIL);

	CUS:
	return rc;
}

