/*
 * getty -- adapt to terminal speed on dialup, and call login
 */

#include "sys/types.h"
#include "utmp.h"
#include <signal.h>
#include "ttystab.h"

char	name[20];
int	crmod;
int	upper;
int	lower;

char partab[] = {
	0001,0201,0201,0001,0201,0001,0001,0201,
	0202,0004,0003,0205,0005,0206,0201,0001,
	0201,0001,0001,0201,0001,0201,0201,0001,
	0001,0201,0201,0001,0201,0001,0001,0201,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0200,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0200,0000,0000,0200,0000,0200,0200,0000,
	0000,0200,0200,0000,0200,0000,0000,0201
};

struct	utmp	wtmp;
char	utmp[]		"/etc/utmp";
struct	ttab	*etabp;
void	mtimeout();
char	dflg = 0;

char firstflg = 0;
main(argc, argv)
char **argv;
{
	register struct ttab *tabp;
	short ufd, tslot;
	int tname;

	tname = '0';
	if (argc > 1)
		tname = argv[1][0];
	signal(SIGQUIT, SIG_IGN);
	if((tslot = ttyslot(0)) >= 0 && (ufd = open(utmp, 2)) >= 0){
		lseek(ufd, (long)(tslot)*(sizeof wtmp), 0);
		if(read(ufd, &wtmp, sizeof wtmp) == sizeof wtmp){
			wtmp.ut_type = LOGIN_PROCESS;
			time(&wtmp.ut_time);
			lseek(ufd, -(long)(sizeof wtmp), 1);
			write(ufd, &wtmp, sizeof wtmp);
		}
		close(ufd);
	}
	for (;;) {
		for(tabp = gtab; tabp < &gtab[NGTAB]; tabp++)
			if(tabp->tname == tname)
				break;
		if(tabp >= &gtab[NGTAB])
			tabp = gtab;
		ioctl(0, TCSETA, &(tabp->imode));
		puts(tabp->message);
		if((tabp->fmode.c_cflag & CLOCAL) == 0){
			signal(14, mtimeout);
			dflg = 1;
		}
		else	dflg = 0;
		switch(getname()) {
		case 1:
			if(crmod){
				tabp->fmode.c_iflag |= ICRNL;
				tabp->fmode.c_oflag |= ONLCR;
			}
			if(upper){
				tabp->fmode.c_iflag |= IUCLC;
				tabp->fmode.c_oflag |= OLCUC;
				tabp->fmode.c_lflag |= XCASE;
			}
			if(lower){
				tabp->fmode.c_iflag &= ~IUCLC;
				tabp->fmode.c_oflag &= ~OLCUC;
				tabp->fmode.c_lflag &= ~XCASE;
			}
			ioctl(0, TCSETA, &(tabp->fmode));
			putchr('\n');
			execl("/bin/login", "login", name, 0);
			exit(1);
			break;

		case 2:
			break;

		default:
			tname = tabp->nname;
			break;
		}
	}
}

getname()
{
	register char *np;
	register c, bflg;
	char cs;

	bflg = 0;
	crmod = 0;
	upper = 0;
	lower = 0;
	np = name;
	for (;;) {
		if(dflg)
			if(firstflg++)
				alarm(30);
		if (read(0, &cs, 1) <= 0)
			exit(0);
		if(dflg)
			alarm(0);
		if ((c = cs & 0177) == 0 || c == CINTR)
			return(0);
		if (c==CEOF)
			exit(1);
		if (c=='\r' || c=='\n' || np >= &name[20])
			break;
		if (c == CSTART || c == CSTOP)
			continue;
		if((etabp->imode.c_lflag & ECHO) == 0)
			putchr(cs);
		if (c>='a' && c <='z')
			lower++;
		else if (c>='A' && c<='Z') {
			upper++;
			if(!lower && bflg == 0)
				c += 'a'-'A';
		} else if (c==CERASE && bflg == 0) {
			if (np > name){
				np--;
				if(c == '\b'){
					putchr(' ');
					putchr(CERASE);
				}
			}
			continue;
		} else if (c==CKILL && bflg == 0) {
			putchr('\r');
			putchr('\n');
			np = name;
			continue;
		}	else if(c == '\\' && bflg == 0) {
				bflg++;
				continue;
			}
		*np++ = c;
		bflg = 0;
	}
	*np = 0;
	if (c == '\r')
		crmod++;
	if(np == name)
		return(2);
	return(1);
}

puts(as)
char *as;
{
	register char *s;

	s = as;
	while (*s)
		putchr(*s++);
}

putchr(cc)
{
	char c;
	c = cc;
	c |= (partab[c & 0177] & 0200);
	write(1, &c, 1);
}

void
mtimeout()
{
	exit(77);
}
