/*
 * Line-printer daemon
 */

#include <sys/types.h>
#include <stdio.h>
#include <dir.h>
#include <signal.h>
#include <stat.h>
#include <sgtty.h>

char	line[128];
char	banbuf[64];
int	linel;
FILE	*dfb;
char	dfname[26] = "/usr/spool/lpd/";
int	waittm	= 60;
struct	dir dbuf;
int	onalrm();

main(argc, argv)
{
	register char *p1, *p2;
	register int df;
	register FILE *dp;
	struct stat stb;

	signal(SIGHUP, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGQUIT, SIG_IGN);
	signal(SIGTERM, SIG_IGN);
/*
 * Close all files, open root as 0, 1, 2
 * to assure standard environment
 */
	for (df=0; df<=15; df++)
		close(df);
	open("/", 0);
	dup(0);
	dup(0);
	if (stat("/usr/spool/lpd/lock", &stb) >= 0)
		exit(0);
	if ((df=creat("/usr/spool/lpd/lock", 0)) < 0)
		exit(0);
	close(df);
	if (fork())
		exit(0);
again:
	dp = fopen("/usr/spool/lpd", "r");
	do {
		if (fread(&dbuf, sizeof dbuf, 1, dp) != 1) {
			feedpage();
			unlink("/usr/spool/lpd/lock");
			exit(0);
		}
	} while (dbuf.d_ino==0 || dbuf.d_name[0]!='d' || dbuf.d_name[1]!='f');
	fclose(dp);
	strcpy(dfname, "/usr/spool/lpd/");
	strcatn(dfname, dbuf.d_name, DIRSIZ);
	if (trysend(dfname) == 0)
		goto again;
	sleep(waittm);
	goto again;
}

trysend(file)
	char *file;
{
	register char *p1, *p2;
	register int i;
	extern int badexit();

	dfb = fopen(file, "r");
	if (dfb == NULL)
		return(0);
	banbuf[0] = 0;
	while (getline()) switch (line[0]) {
	case 'L':
		p1 = line+1;
		p2 = banbuf;
		while (*p2++ = *p1++);
		continue;

	case 'F':
		if (send())
			return(1);
		continue;

	case 'U':
		continue;

	case 'M':
		continue;
	}
/*
 * Second pass.
 * Unlink files and send mail.
 */
	fseek(dfb, 0L, 0);
	while (getline()) switch (line[0]) {

	default:
		continue;

	case 'U':
		unlink(&line[1]);
		continue;

	case 'M':
		sendmail();
		continue;
	}
	fclose(dfb);
	unlink(file);
}

sendmail()
{
	static int p[2];
	register i;
	int stat;

	pipe(p);
	if (fork()==0) {
		alarm(0);
		if (p[0] != 0) {
			close(0);
			dup(p[0]);
			close(p[0]);
		}
		close(p[1]);
		for (i=3; i<=15; i++)
			close(i);
		execl("/bin/mail", "mail", &line[1], 0);
		exit(0);
	}
	write(p[1], "Your printer job is done\n", 25);
	close(p[0]);
	close(p[1]);
	wait(&stat);
}

getline()
{
	register char *lp;
	register int c;

	lp = line;
	linel = 0;
	while ((c = getc(dfb)) != '\n') {
		if (c<0)
			return(0);
		if (c=='\t') {
			do {
				*lp++ = ' ';
				linel++;
			} while ((linel & 07) != 0);
			continue;
		}
		*lp++ = c;
		linel++;
	}
	*lp++ = 0;
	return(1);
}

int	pid;

send()
{
	int p;

	if (pid = fork()) {
		if (pid == -1)
			return(1);
		setexit();
		signal(SIGALRM, onalrm);
		alarm(30);
		wait(&p);
		alarm(0);
		return(p);
	}
	if (banbuf[0]) {
		execl("/usr/lib/lpf", "lpf", "-b", banbuf, line+1, 0);
		return(1);
	}
	execl("/usr/lib/lpf", "lpf", line, 0);
	return(1);
}

onalrm()
{
	struct stat stb;

	signal(SIGALRM, onalrm);
	if (stat(dfname, &stb) < 0)
		kill(pid, SIGEMT);
	reset();
}

struct	sgttyb ttyb = {
	B9600, B9600,
	0, 0,
	XTABS|ANYP|CBREAK
};

FILE	*out;
int	lpack;

feedpage()
{
	register int i = 66;
	FILE *lp;
	int retry = 0;

	out = fopen("/dev/lp", "w");
	if (out == NULL)
		return;
	lpack = open("/dev/lp", 0);
	if (lpack < 0) {
		fclose(lp);
		return;
	}
	stty(fileno(out), &ttyb);
	putc(2, out);
	putc('\f', out);
	putc(3, out);
	ack();
	fclose(out);
	close(lpack);
}

#define	ACK	06
#define	NAK	025
#define	STX	2
#define	ETX	3

nothing()
{
	;
}

ack()
{
	char	buf[256];

	int i = STX;
	write(fileno(out), &i, 1);
	putc('\r', out);
	putc(ETX, out);
	fflush(out);
	alarm(5);
	signal(SIGALRM, nothing);
	i = read(lpack, buf, 256);
	if (buf[0] == NAK)
		sleep(1);
	return (buf[0] == ACK);
}
