#include	<stdio.h>
#include	"quotas.h"
#include	"hsubs.h"


char	grptab[256][16];
char	buf[512];

struct qent	q;
char	*QFILE;
float	pct = 10.0;	/* default nearness, 10% */

#define	MFLAG	01
#define	BFLAG	02
#define	FFLAG	04
#define	ALLFLAG	(MFLAG|BFLAG|FFLAG)
#define	LCNT	037
#define	WARN	0100
#define	NONOTF	040
#define	FLAGSHIFT	5
int	oflg = 0;
int	aflg = 0;

int	gflg = 0;
int	sflg = 0;
int	peasant = 0;
char	*arglist[4];
char	*groupp;
int	group;

main(argc, argv)
char **argv;
{
	register g;

	QFILE = QUOFILE;
	if((g = getgid()) && g != 2 && g != 3 && g != 5){
		argv = arglist;
		argv++;
		*argv = logname();
		peasant++;
		argv[1] = 0;
		argc = 1;
		goto skipit;
	}
	while(--argc){
		argv++;
		if(**argv != '-')break;
		else	switch(*++*argv){

	case 's':
		sflg++;
		break;

	case 'f':
		if(argc > 1){
			argc--;
			QFILE = *++argv;
		}
		break;

	case 'g':
		if(argc > 1){
			gflg++;
			groupp = *++argv;
			if(*groupp >= '0' && *groupp <= '9'){
				group = atoi(groupp) & 0377;
				groupp = NULL;
			}
			argc--;
		}
		break;

	case 'p':
		pct = atoi(++*argv);
		if(pct <= 0 || pct >=100){
			fprintf(stderr, "Bad value for -p\n");
			exit(1);
		}
		pct = 100.0/pct;
		break;

	case 'o':
		oflg = getopt(++*argv);
		break;

	case 'a':
		oflg = getopt(++*argv);
		aflg = oflg;
		break;

	case 'n':
		aflg = getopt(++*argv);
		break;

	default:
		fprintf(stderr, "Illegal option - %c\n", **argv);
		fflush(stderr);
		exit(1);
		}
	}

skipit:
	getgrp();
	if(gflg && groupp){
		for(g = 0; g < 256; g++)
			if(strcmp(grptab[g], groupp) == 0){
				group = g;
				break;
			}
		if(g > 255){
			fprintf(stderr, "Group \"%s\" not found in /etc/group\n", groupp);
			exit(7);
		}
	}
	printout(argc,argv);
	exit(0);
}

getopt(s)
char	*s;
{
	int	flags = 0;

	if(*s == 0)
		return(ALLFLAG);
	while(*s) switch(*s++){
	case 'm':
		flags |= MFLAG; break;

	case 'b':
		flags |= BFLAG; break;

	case 'f':
		flags |= FFLAG; break;

	default:
		fprintf(stderr, "Invalid modifier, must be one of [mbf]\n");
		exit(1);
	}
	return(flags);
}

printout(cnt, args)
char **args;
{
	register struct qent *pq, *pl;
	short qfd;
	register int i;

	if((qfd = open(QFILE, 0)) == -1){
		printf("Can not open quofile %s\n", QFILE);
		exit(5);
	}
	pq = &q;
	if(cnt){
		while(cnt--){
			if(getqent(qfd, pq, *args) == 0)
				printf("%s: Not in %s\n", *args, QFILE);
			else	outq(pq);
			args++;
		}
	} else
		while((i = read(qfd, buf, 512)) > 0)
			for(pq = buf, pl = &buf[i]; pq < pl; pq++){
				if(pq->q_ln[0] == 0 ||
					(gflg && pq->q_gid != group))continue;
				outq(pq);
			}
	fflush(stdout);
	close(qfd);
	return(0);
}

outq(pq)
register struct qent *pq;
{
	if(aflg){
		if( !((oflg && over(pq)) || near(pq)))
			return;
	} else if(oflg && !over(pq))
		return;
	if(peasant || sflg){
		fprintf(stdout, "%-8.8s", pq->q_ln);
		if(pq->q_mquo)
			fprintf(stdout, "%4d dollars left", ((short)(pq->q_mquo - pq->q_mused)) / 10);
		fprintf(stdout, "%5u/%5u blocks   %3u/%3u files   %d used logins\n",
			pq->q_dused, pq->q_dquo, pq->q_fused,
			pq->q_fquo, pq->q_flg & 037);
	} else {
		fprintf(stdout, "%-8.8s [%-8.8s,%5d]",
			pq->q_ln, grptab[pq->q_gid & 0377], pq->q_uid);
		if(pq->q_mquo){
			fprintf(stdout, "%4u.%02d/%4u(%2d)",
				pq->q_mused/10, (pq->q_mused%10)*10, pq->q_mquo/10,
				pq->q_inc);
		} else
			fprintf(stdout, "                ");
		fprintf(stdout, "%5u/%5u %4u/%4u /%-6.6s %2.2s %o\n",
			pq->q_dused, pq->q_dquo, pq->q_fused,
			pq->q_fquo, pq->q_fs,
			flagstr(pq->q_flg), pq->q_flg & LCNT);
	}
}

near(pq)
register struct qent *pq;
{
	if( ((aflg&BFLAG) && ((pq->q_dquo - pq->q_dused) < pq->q_dquo/pct))
	 || ((aflg&FFLAG) && ((pq->q_fquo - pq->q_fused) < pq->q_fquo/pct))
	 || ((aflg&MFLAG) && pq->q_mquo && ((pq->q_mquo - pq->q_mused) < pq->q_mquo/pct)))
		return(1);
	return(0);
}

over(pq)
register struct qent *pq;
{
	if( ((oflg&BFLAG) && (pq->q_dused > pq->q_dquo))
	 || ((oflg&FFLAG) && (pq->q_fused > pq->q_fquo))
	 || ((oflg&MFLAG) && pq->q_mquo && (pq->q_mused > pq->q_mquo)))
		return(1);
	return(0);
}

getgrp()
{
	register char *s, *t, *p;
	char ibuf[514], lbuf[128];
	int grid, fd, r;

	if((fd = open("/etc/group", 0)) == -1){
		fprintf(stderr, "\nCan not open group files to print list\n\n");
		fflush(stderr);
		return;
	}
	s = grptab[255];
	t = "ALL";
	while(*s++ = *t++);

	t = lbuf;
	while((r = read(fd, s = ibuf, 512)) >= 1) {
		s[r] = 0;
		while(*s) {
			if((*t++ = *s++) != '\n')continue;
			*t = 0;
			p = lbuf;
			while(*p && *p != ':')p++;
			t = p;
			if(*p++ == 0){
badlne:
				fprintf(stderr, "Bad line in /etc/group\n\n");
				fflush(stderr);
				continue;
			}
			*t = 0;
			while(*p && *p != ':')p++;
			if(*p++ == 0)goto badlne;
			grid = 0;
			while(*p && *p >= '0' && *p <= '9')
				grid = grid*10 + *p++ - '0';
			p = grptab[grid];
			t = lbuf;
			while(*p++ = *t++);
			t = lbuf;
		}
	}
	close(fd);
	return;
}

flagstr(f)
register unsigned f;
{
	f >>= FLAGSHIFT;
	f &= 03;
	return(&"   N WWN"[f << 1]);
}
