#include	"hsubs.h"
#include	"actrecs.h"
#include	"stdio.h"

char *logname(), *getn();

char *namlst[256];
char ibuf[10752];
char *actfil = DFILE;

short nacct, ngrp, priv, class, prof, nnam, dflg, iflg, gflg, af, laf, mygid;
short mfd = -1;
long co, sc, uc, di, oco, osc, ocu, odi;

struct tab {
	short t_uid;
	short t_gid;
	char  t_acct[8];
	char  t_name[8];
} tab[500];

struct gtab {
	short g_gid;
	char  g_gname[8];
} gtab[64];

struct	a360 {
	char accn[10];
	char edat[10];
	float amnt;
} a360[500];

main(argc, argv)
char **argv;
{
	register char *s;
	register short i, j;
	short cg, cu;

	priv = chkpriv();

	if((priv || prof) && argc > 1){
		while(--argc){
			argv++;
			if(**argv != '-')
				namlst[nnam++] = *argv;
			else	switch(*++(*argv)){
	case 'd':
			dflg++;
			break;

	case 'i':
			iflg++;
			break;

	case 'g':
			gflg++;
			break;

	case 'f':
			if(!prof && argc > 1){
				argc--;
				actfil = *++argv;
			}
			break;

	default:
			fprintf(stderr, "Illegal option -%c\n", **argv);
			exit(3);
			}
		}
	}
	if(prof && nnam > 1){
		fprintf(stderr, "Protection violation -- too many accounts\n");
		exit(9);
	}
	if(gflg){
		if(nnam == 0){
			fprintf(stderr, "You must supply a group name/id with -g\n");
			exit(1);
		}
		readgrp();
	}
	else {
		if(nnam == 0){
			namlst[nnam++] = logname();
			prof = 0;
		}
		readin();
	}

	if((af = open(actfil, 0)) == -1){
		fprintf(stderr, "Can't open %s\n", actfil);
		exit(4);
	}
	if(!class && !gflg && (laf = open("/accting/lastacct", 0)) == -1){
		fprintf(stderr, "Can't open /accting/lastacct\n");
		exit(5);
	}

	if(dflg){
		fprintf(stdout, "Username [Gid, User]  Con Un   Systics   ");
		fprintf(stdout, "Usrtics   Disk\n");
	} else {
		fprintf(stdout, "Username [Gid, User]  Conn $   Syscpu$   ");
		fprintf(stdout, "Usrcpu$  Disk$   Total $\n");
	}
	fprintf(stdout, "-------- ----------- -------  --------  ");
	fprintf(stdout, "--------  -----");
	if(dflg)
		putc('\n', stdout);
	else	fprintf(stdout, "   -------\n");

	for(i = 0; i < nnam; i++){
		if(gflg){
			for(j = 0; j < ngrp; j++)
				if(strncmp(namlst[i], gtab[j].g_gname, 8) == 0)
					break;
			if(j == ngrp){
				if((cg = num(namlst[i])) == -1){
					fprintf(stderr, "Group %s not found\n",
						namlst[i]);
					continue;
				}
				sprintf(namlst[i] = &ibuf[10700], "Gid %3d", cg);
			} else
				cg = gtab[j].g_gid;
			if(prof && cg != mygid){
				fprintf(stderr, "Protection violation on group\n");
				exit(10);
			}
			j = cu = -1;
		}
		else	{
			if(prof){
				fprintf(stderr, "Protection violation\n");
				exit(11);
			}
			for(j = 0; j < nacct; j++)
				if(strncmp(namlst[i], tab[j].t_name, 8) == 0)
					break;
			if(j == nacct){
				if(ngetent(HFILE_NM, namlst[i], ibuf)){
					fprintf(stderr, "%s: No account\n",
						namlst[i]);
					continue;
				}
				j = -1;
				s = ibuf;
				while(*s++ != ':');
				while(*s++ != ':');
				cu = num(s);
				while(*s++ != ':');
				if(!iflg)
					cg = num(s);
				else	cg = -1;
			}
			else {
				cu = tab[j].t_uid;
				cg = tab[j].t_gid;
			}
		}
		co = sc = uc = di = oco = osc = ocu = odi = 0L;
		if(cu >= 0)
			fixuids(cu, cg);
		else	fixgids(cg, cu);
		if(iflg){
			fprintf(stdout, "-----------------------------------");
			fprintf(stdout, "%s--------------------\n",
				dflg ? "" : "----------");
		}
		printe(co, sc, uc, di, namlst[i], cg, cu);
		if(j != -1)
			lookup(tab[j].t_acct);
	}
	close(af);
	close(laf);
	clhash();
	exit(0);
}


fixuids(u, g)
register short u;
{
	register struct acctrec *pa, *pl;
	long sa;
	short r;
	char err;

	err = 0;
	sa = (long)(akey(u))*AREAD;
#ifdef	DEBUG
	fprintf(stderr, "\nU:%d --- Seek ad:%D\n", u, sa);
#endif
	lseek(af, sa, 0);

lp:
	while((r = read(af, ibuf, 200)) > 0){
		pl = &ibuf[r];
		for(pa = ibuf; pa < pl; pa++){
#ifdef	DEBUG
			fprintf(stderr, "U:%5d  G:%3d  pa->u:%5d  pa->g:%5d\n",
				u, g, pa->a_uid, pa->a_gid);
#endif
			if(pa->a_uid == u && (g == -1 || g == pa->a_gid)){
				co += pa->a_connect;
				sc += pa->a_syscpu;
				uc += pa->a_usrcpu;
				di += pa->a_diskblks;
				if(!class && !gflg)
					diffit(pa, sa, u, pa->a_gid);
				if(iflg)
					printe(pa->a_connect, pa->a_syscpu,
						pa->a_usrcpu, pa->a_diskblks,
						0, pa->a_gid, pa->a_uid);
			}
			if(pa->a_uid == 0 && pa->a_gid == 0)
				return;
		}
	}
	if(err++)
		fprintf(stderr, "Money: Read error on %s\n", actfil);
	else	{
		lseek(af, 0L, 0);
		goto lp;
	}
}

diffit(pa, sa, u, g)
long sa;
struct acctrec *pa;
short u,g;
{
	register struct acctrec *pg, *pl;
	char err;
	short r;

	err = 0;
	lseek(laf, sa, 0);

lp:
	while((r = read(laf, &ibuf[10240], 200)) > 0){
		pl = &ibuf[10240+r];
		for(pg = &ibuf[10240]; pg < pl; pg++){
			if(pg->a_uid == u && pg->a_gid == g){
#ifdef	DEBUG
				printf("diffit: u=%d g=%d : matched\n", u, g);
				printf("\tconn=%D\tucpu=%D\tscpu=%D\tdsk=%D\n",
					pg->a_connect,
					pg->a_usrcpu,
					pg->a_syscpu,
					pg->a_diskblks);
#endif
				oco += (pa->a_connect - pg->a_connect);
				osc += (pa->a_syscpu - pg->a_syscpu);
				ocu += (pa->a_usrcpu - pg->a_usrcpu);
				odi += (pa->a_diskblks - pg->a_diskblks);
				return;
			}
			if(pg->a_uid == 0 && pg->a_gid == 0)
				return;
		}
	}
	if(err++)
		fprintf(stderr, "Read error in Last file\n");
	else	{
		lseek(laf, 0L, 0);
		goto lp;
	}
}

fixgids(g, u)
register short g;
{
	register struct acctrec *pa, *pl;
	short r;

	lseek(af, 0L, 0);
	while((r = read(af, ibuf, 10240)) > 0)
		for(pa = ibuf, pl = &ibuf[r]; pa < pl; pa++)
			if(pa->a_gid == g && (u == pa->a_uid || u == -1)){
				co += pa->a_connect;
				sc += pa->a_syscpu;
				uc += pa->a_usrcpu;
				di += pa->a_diskblks;
				if(!class && !gflg){
#ifdef	DEBUG
					printf("fixuids: u=%d g=%d\n", pa->a_uid, g);
#endif
					diffit(pa, (long)(akey(pa->a_uid))*
						AREAD, pa->a_uid, g);
				}
				if((pa->a_gid || pa->a_uid) && iflg)
					printe(pa->a_connect, pa->a_syscpu,
						pa->a_usrcpu, pa->a_diskblks,
						getn(pa->a_uid), g, pa->a_uid);
			}
}

char *
getn(u)
register u;
{
	register char *s;
	static char nbuf[128];

	if(ugetent(HFILE_UD, u, nbuf))
		return("--------");
	s = nbuf;
	while(*s && *s != ':')s++;
	if(*s)*s = 0;
	else	return("--------");
	return(nbuf);
}

readgrp()
{
	short n;
	register char *s, *t, *l;
	short fd, r;

	if((fd = open("/etc/group", 0)) == -1){
		return;
	}

	t = &ibuf[10000];
	n = 0;
	while((r = read(fd, ibuf, 5120)) > 0)
		for(s = ibuf, l = &ibuf[r]; s < l;){
			if((*t++ = *s++) != '\n')continue;
			*t = 0;
			*--t = 0;
			tr(gtab[n].g_gname, t = &ibuf[10000]);
			while(*t && *t != ':')t++;
			t++;
			while(*t && *t != ':')t++;
			if(*t++ == 0){
				fprintf(stderr, "Money: Bad /etc/group entry\n");
				exit(2);
			}
			gtab[n++].g_gid = num(t);
			t = &ibuf[10000];
		}
	close(fd);
	ngrp = n;
	putc('\n', stdout);
}

chkpriv()
{
	register short g, u;

	g = mygid = getgid();
	u = getuid();
	class = g > 99;
	prof = ((u - (g*100)) == 0);
	if(g == 0 || g == 2 || g == 3 || g == 5)
		return(1);
	if(u)return(0);
	return(1);
}

tr(s, t)
register char *s, *t;
{
	register short i;

	for(i = 0; i < 8; i++){
		*s = *t++;
		if(*s == ' ' || *s == ':'){
			*s = 0;
			return;
		}
		if(*s >= 'A' && *s <= 'Z')
			*s |= 040;
		s++;
	}
}

num(s)
register char *s;
{
	register short i;

	i = 0;
	if(*s < '0' || *s > '9')
		return(-1);
	while(*s >= '0' && *s <= '9')
		i = i * 10 + (*s++) - '0';
	return(i);
}


readin()
{
	register struct ibment *ip, *lp;
	short fd, r;
	register n;

	if((fd = open(IBMFILE, 0)) == -1)
		return;

	n = 0;
	while((r = read(fd, ibuf, 10752))%IREAD == 0 && r)
		for(ip = ibuf, lp = &ibuf[r]; ip < lp; ip++){
			tab[n].t_uid = num(ip->uid);
			tab[n].t_gid = num(ip->gid);
			tr(tab[n].t_name, ip->name);
			strncpy(tab[n].t_acct, ip->acct, 8);
			n++;
		}
	close(fd);
	nacct = n;
	putc('\n', stdout);
}


printe(cn, sp, up, ds, nm, g, u)
long cn, sp, up, ds;
char *nm;
short g, u;
{
	float tot, dol;
	long lt;

	if(nm == NULL)
		nm = "--------";
	fprintf(stdout, "%-8.8s [", nm);
	if(g < 0)
		fprintf(stdout, "***,");
	else	fprintf(stdout, "%3d,", g);
	if(u < 0)
		fprintf(stdout, "*****]");
	else	fprintf(stdout, "%-5d]", u);

	if(dflg){
		lt = cn/36;
		if(cn % 36 > 17)lt++;
		tot = (float)(lt)/100.0;
		fprintf(stdout, "%8.2f%10D%10D%7D\n", tot, sp, up, ds);
	}
	else	{
		lt = cn/36;
		if(cn%36 > 17)lt++;
		tot = ((float)(lt)/100.0) * CONRATE;
		fprintf(stdout, "%8.2f", tot);
		lt = sp/2160;
		if(sp%2160 > 1079)lt++;
		dol = ((float)(lt)/100.0) * TICRATE;
		fprintf(stdout, "%10.2f", dol);
		tot += dol;
		lt = up/2160;
		if(up%2160 > 1079)lt++;
		dol = ((float)(lt)/100.0) * TICRATE;
		fprintf(stdout, "%10.2f", dol);
		tot += dol;
		lt = ds/10;
		if(ds%10 > 4)lt++;
		dol = ((float)(lt)/100.0) * DISKRATE;
		fprintf(stdout, "%7.2f", dol);
		tot += dol;
		fprintf(stdout, "%10.2f\n", tot);
	}
}

lookup(s)
register char *s;
{
	float total();

	register struct a360 *pa;

	if(mfd < 1){
		if((mfd = open("/accting/acctmoney", 0)) == -1)return;
		if(read(mfd, &a360, 12000) != 12000){
			fprintf(stdout, "money: Read error on 4341 money file\n");
			exit(1);
		}
		close(mfd);
	}
	for(pa = &a360[0]; pa->accn[0]; pa++)
		if(strncmp(pa->accn, s, 8) == 0){
			if(priv){
				fprintf(stdout, "4341 allocation: $%.2f", pa->amnt);
				fprintf(stdout, "    Outstanding: $%.2f     ", total());
			}
			else	
				fprintf(stdout, "4341 allocation: $%.2f     ", 
					pa->amnt - total());
			fprintf(stdout, "  Expiration: %8.8s\n", pa->edat);
			return;
		}
		fprintf(stdout, "??\n");
}



float
total(){
	long lt , lc;
	float tot;

	lt = oco/36;
	if(oco%36 > 17)lt++;
	tot = ((float)(lt)/100.0) * CONRATE;
	lt = osc/2160;
	if(osc%2160 > 1079)lt++;
	tot += ((float)(lt)/100.0) * TICRATE;
	lt = ocu/2160;
	if(ocu%2160 > 1079)lt++;
	tot += ((float)(lt)/100.0) * TICRATE;
	lt = odi/10;
	if(odi%10 > 4)lt++;
	return(tot + (lt/100.0) * DISKRATE);
}

