/*
**
**	MBXENIX.C - 10/24/87 - System dependent functions.
**
**	Copyright (C) 1988
**	Akira Yamada(JA3JWI)
**	401, 1-18 UchiHiranomachi
**	Higashi-ku   Osaka   City
**
**	Any part of this program may be  reproduced,  transmitted,
**	transcribed, stored in a retrieval system,  or translated
**	into any language or computer language, in any form or by
**	any  means,   electonic,  mecahnical,  magnetic,  optical,
**	chemical, manual or otherwise,  without  the prior witten
**	permission of the author.
**
*/

/*
**	History of Modifiy
**
** 6. Save CPU TIME													88/05/02
** 5. Add xeparse()													87/12/19
** 4. Mask return value of inchr() by 0377							87/12/09
** 3. Add Boud Rate Setting by config.mb file.						87/11/26
** 2. Control charcter print with "^"; ig ^C ^F ^E ^W [outchar()]
** 1. Implement from old Xenix Version								87/11/20
*/

#include "mb.h"
#include "mbexp.h"
#include <time.h>
#include <signal.h>
#include <termio.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <sys/locking.h>
#include <errno.h>

#define  BUFSIZE      256
#define  PORTDIR  "/dev/tty"

#define  CTRL_V     "\026"  /* ^V */
#define  DC1        17      /* ^Q */
#define  DC3        19      /* ^S */
#define  ETX         3      /* ^C */

char l_date[7], l_time[5];
long time();

static int flowon = 0;    /* AY-871126 */

extern int errno;
extern int in_dofilecmd;	/* AY-880418 */
struct termio oldtty, newtty;

unsigned short boud[] =  {
	0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,0,0,0,0,0};

static int path[] = {
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
	-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 };

static int readcount[] =
	{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

static int readcntr[] =
	{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

static char *inputbuf[26];	/* AY-880802 */

/*
**  Initialize the serial I/O system.
**  Ports are initialized by loading driver and then running mbmode.
*/

ioinit()
{
register char *ptr;
char *strrchr(), *malloc();
PORTS *p;
char buf[BUFSIZ];

#if !SEM_NO	/* AY-881005 */
	setup_sem();
#endif

	for (p = porthd;
	p isnt NULL;
	p = p->next) {

		if (!(p->dev & (p_tnc | p_serial)))
			continue;

		if (p->id == 'L') {
			path[p->idn] = 0;
			continue;
		} else {
			ptr = strrchr(p->name, ' ');
			*ptr = '\0';
			strcpy(buf, ++ptr);
		}

		if ((path[p->idn] = open (buf ,O_RDWR)) is -1)
			{ perror(buf); exit(1); }
		else {
			ioctl(path[p->idn], TCGETA, &newtty);
			newtty.c_lflag &= ~(ISIG|ICANON|ECHO);
			newtty.c_lflag &= ~(BRKINT);
			newtty.c_cc[VMIN] = '\0';
			newtty.c_cc[VTIME] = '\01';
			newtty.c_cc[VSWTCH] = -1;
			newtty.c_cflag = 0;
			newtty.c_oflag = 0;
			newtty.c_cflag |= (boud[p->idn] | CS8 | CREAD);
			newtty.c_iflag &= ~(INLCR|ICRNL|IUCLC|ISTRIP);
			newtty.c_iflag &= ~IXON;	/* AY-880506 */
			newtty.c_iflag &= ~IXOFF;	/* AY-880511 */
			if (ioctl(path[p->idn], TCSETAF, &newtty) < 0) {
				fprintf(stderr, "ioctl could not set paremeters for %d\n",
				    p->idn);
				exit(1);
			}
		}

		if ((inputbuf[p->idn] = malloc(BUFSIZ)) == NULL) {
			perror("malloc\n");
			exit(1);
		}
	}
/*
**  Set stdin, stdout RAW mode.
*/
	ioctl(0, TCGETA, &newtty);
	ioctl(0, TCGETA, &oldtty);
	newtty.c_lflag &= ~ICANON;
	newtty.c_lflag &= ~ISIG;
	newtty.c_lflag &= ~ECHO;
	newtty.c_cc[VMIN] = '\01';
	newtty.c_cc[VTIME] = '\0';
	newtty.c_cc[VSWTCH] = -1;
	newtty.c_iflag &= ~(ICRNL|IXON|IXOFF);
	newtty.c_oflag &= ~ONLCR;
	ioctl(0, TCSETA, &newtty);
}

/*
 *  Restore stdin,stdout to it's initial mode.
 */
iooff(sig)
int sig;
{ 
	console_mode(0);
}

/*
 *  Set the current I/O device.
 */

ioport(pp)
PORTS *pp;
{
	port = pp;
}

catchalarm() { signal(SIGALRM, catchalarm); }

/*
 *  Return character from the current port.
 */

unsigned char inchar()
{
unsigned char ch;
register int i;

	if (port->dev is p_console) {
		if (!(ioctl(0, FIORDCHK)))	/* TEST AY-881001 */
			fflush(stdout);

		switch(read(0, &ch, 1)) {
		case 0:
			port->line[0] = '\0'; /* AY-880910 */
			return ('\n');
		case -1:
			port->line[0] = '\0'; /* AY-880910 */
			return ('\0');
		default:
			break;
		}
		if (ch == 10)
			if (!isatty(0)) ch = 13;
	} else {
		if (!(readcount[port->idn] > readcntr[port->idn]))
			while(!instat())
				fflush(stdout);	/* TEST */
		ch = inputbuf[port->idn][readcntr[port->idn]];
		readcntr[port->idn] += 1;
	}

/*
**  Echo the input to the console, if it didn't come from the console.
*/

	if (ch is del) ch = '\b';
	if (port->dev isnt p_console) if (ch isnt ctl_g) {
		printf("%c", ch);
		if (ch == '\r') {
			printf("\n");
			fflush(stdout);
		}
	}

	return (ch & 0377);
}

/*
 *  Return non-zero if a character waits at current input.
 */

/* AY-881013 */
keyinstat() { return(ioctl(0, FIORDCHK)); }

instat()
{
	if (port->dev is p_console)
		return(ioctl(0, FIORDCHK));

	if (readcount[port->idn] > readcntr[port->idn]) {
		return (1);	/* I have some char's, So return with 1 */ 
	} else {		/* No chars there, So we must check port */
		inputbuf[port->idn][0] = '\0';	/* AY-881108 */
		if ((readcount[port->idn] =
				read(path[port->idn],
				inputbuf[port->idn], BUFSIZE)) > 0) {
			readcntr[port->idn] = 0;
			return (1);	/* Ok, Some chars in the buffer */
		} else {		/* No chars in the buffer */
			if (readcount[port->idn] == -1) /* Gee It's ERROR! */
			if (errno != EINTR) {
				perror("Error at instat()");
				fprintf(stderr, "\7\n\r");
			}
			readcount[port->idn] = readcntr[port->idn] = 0;
		}
	}
	fflush(stdout);	/* AY-880919 */
	return (0);	/* Well too sorry, I have no chars in the buffer */
}

/*
 *  Stuff the character out the port.
 */
static int outp(ch)
char ch;
{
	if (write(path[port->idn], &ch, 1) == -1)
		{ perror("outp"); fprintf(stderr, "\r"); }
}

/*
**  Put the character out the current port,
**  echo to console if the current port is not the console.
**  Note special handling of end-of-line character.
*/

outchar(ch)
char ch;
{
	if (ch is '\r') return;
	if (ch is '\n') ch = '\r';

/*
**  Everything goes to the console.
*/
	switch(ch) {
	case  3: /* ^C */
	case  5: /* ^E */
	case  6: /* ^F */
	case 23: /* ^W */
	case 26: /* ^Z */
		putchar((int)('^'));
		putchar((int)(ch + 64));	/* AY-881021 */
		break;
	case 17: /* ^Q */
	case 19: /* ^S */
		putchar((int)('^'));
		putchar((int)(ch + 64));
		return;
	default:
		putchar((int)(ch));
	}
	if (ch is '\r') {
		putchar((int)('\n'));
		fflush(stdout);
	}

/* 
**  It might go out a port, too.
*/

	if (!(port->dev is p_console)) {
		outp(ch);
		if (ch is '\r')
		if (port->dev & p_lf)
			outp('\n'); /* AY-880105 */
	}
}

static int in_flow = 0;

flow_yes()
{
	if (port->dev isnt p_tnc) return (0); /* AY-880801 */
	in_flow = 1;
	return (setflow(port->idn));
}

flow_no()
{
	if (port->dev isnt p_tnc) return (0); /* AY-880801 */
	in_flow = 0;
	return (restore(port->idn));
}

outstr(cp)
char *cp;
{
register char *ptr;
char tmpbuf[BUFSIZ];

	ptr = tmpbuf;
	if (port->dev is p_tnc) {
		alarm((unsigned) port->ctime);	/* AY-880827 */
#if 0	/* TEST AY-881109 */
		if (!in_flow)	/* AY-880714 */
			setflow(port->idn);
#endif
	}

	while(*cp) {
		if (*cp is '\r') { cp++; continue; }

		if (*cp is '\n') {
			cp++; *ptr++ = '\r';
			printf("\n\r");

			if (port->dev & p_lf)
				*ptr++ = '\n';
		} else {
			printf("%c", *cp);
			*ptr++ = *cp++;
		}

		if (ptr >= (tmpbuf + sizeof(tmpbuf))) {
			if (!(port->dev is p_console))
			if (write(path[port->idn], tmpbuf, (unsigned int)(ptr - tmpbuf)) == -1)
				{ perror("outstr"); fprintf(stderr, "\r"); }
			ptr = tmpbuf;

		}
	}

	if (ptr == tmpbuf) {
		if (port->dev is p_tnc) alarm(0);
		return;
	}

	if (!(port->dev is p_console)) {
		if (write(path[port->idn], tmpbuf, (unsigned int)(ptr - tmpbuf)) == -1)
			{ perror("outstr3"); fprintf(stderr, "\r"); }
	}

	fflush(stdout);
	alarm(0);
}

/*
**  Fill the globals "date" and "time" with
**  the current date and time in ASCII by reading the system clock.
*/

/*
**  Check a timer.
*/

chktmr(l)
long l;
{
	long cur;

	time(&cur);
	if (cur > l) return false;
	return true;
}

/*
**  Set a timer.
*/

settmr(l, i)
long *l;
int i;
{
	long cur;

	time(&cur);
	*l = cur + (long)i;
}

/*
**  Set the clock.
**  fld[1] has the date string.
**  fld[2] has the time string.
*/

/*
**  Fill the globals "date" and "time" with
**  the current date and time in ASCII
**  by reading the system clock.
*/

curtim()
{
long t;
struct tm *l, *gmtime(), *localtime();

	t = time(0);

	if (matchn(mean_time, "GMT", 3))	/* AY-880718 */
		l = gmtime(&t);
	else
		l = localtime(&t);

	sprintf(l_time,"%02d%02d", l->tm_hour, l->tm_min);
	sprintf(l_date,"%02d%02d%02d",l->tm_year,++l->tm_mon, l->tm_mday);
}

rename(old,new)
char *old,*new;
{
	char cmd[34];
	sprintf(cmd,"mv %s %s",old,new);
	system(cmd);
}

itoa(n, s)
char s[];
int n;
{
register int i, sign;

	if ((sign = n) < 0)
		n = -n;
	i = 0;
	do {
		s[i++] = n % 10 + '0';
	} while ((n /= 10) > 0);
	if (sign < 0)
		s[i++] = '-';
	s[i] = '\0';
	reverse(s);
}

reverse(s)
char s[];
{
register int c, i, j;

	for (i = 0, j = strlen(s)-1; i < j; i++, j--) {
		c = s[i];
		s[i] = s[j];
		s[j] = c;
	}
}

die(sig)
int sig;
{
	console_mode(0);
	exit(sig);
}

console_mode(cont)
int cont;
{
	if (cont)
		ioctl(0, TCSETAW, &newtty);
	else
		ioctl(0, TCSETAW, &oldtty);
}

allocport() { }
blockport() { }
freeport() { }
/*
#undef tolower
#undef toupper
*/
strlwr(s)
char s[];
{
	for (; *s; s++) if (isupper((int)(*s))) *s = tolower((int)(*s));
	
/*	for(p = s; *p; p++) { *p = (char)tolower(*p); } */
}

strupr(s)
char s[];
{
	for (; *s; s++) if (islower((int)(*s))) *s = toupper((int)(*s));

/*	for (p = s; *p; p++) { *p = (char)toupper(*p); } */
}

#if	!O_NO
shell()
{
	ioctl(0, TCSETA, &oldtty);
	system(shell_name);
	ioctl(0, TCSETA, &newtty);
}
#endif

editor(tname)
char *tname;
{
char buf[BUFSIZ];

	if (*edname) {
		if (!isatty(0)) return(false);	/* AY-880515 */

		ioctl(0, TCSETA, &oldtty);
		unlink(EDTMP);
		sprintf(buf, "%s %s", edname, EDTMP);
		if(system(buf)) { 
			outstr(can_t_do); 
			outstr(buf); 
			outchar('\n');
			return false; 
		}
		copy(EDTMP, tname);
		unlink(EDTMP);
		ioctl(0, TCSETA, &newtty);
		return(true);
	}
	return (false);
}

static struct termio tbufsave;

static setflow(pn)
int pn;
{
struct termio tbuf;

	if (flowon) return (0);

	flowon = 1;

	catchalarm();	/* AY-880821 */
	alarm((unsigned) port->ctime); /* AY-880821 */

	if (ioctl(path[pn], TCGETA, &tbuf) == -1) {
		perror("\7setflow");
		fprintf(stderr, "\r");
		die(1);
	}

	tbufsave = tbuf;
	tbuf.c_iflag |= IXON;
	if (ioctl(path[pn], TCSETAW, &tbuf) == -1) { 
		if (errno != EINTR)	/* AY-880821 */
		{ perror("restore(ioctl)"); fprintf(stderr, "\r"); die(1); }

		ioctl(path[pn], TCFLSH, 2);	/* AY-880821 */
		if (ioctl(path[pn], TCSETAW, &tbuf) == -1) {
			perror("setflow2"); fprintf(stderr, "\r");
			die(1);
		}
	}
	return(alarm(0) == 0);	/* AY-880821 */
}

void flushport(i)					/* AY-880827 */
int i;
{
	if (port->dev isnt p_tnc) return;
	ioctl(path[port->idn], TCXONC, 1);
}

static restore(pn)
int pn;
{
	if (!flowon) return (0);

	catchalarm();	/* AY-880821 */
	alarm((unsigned) port->ctime); /* AY-880821 */

	if (ioctl(path[pn], TCSETAW, &tbufsave) == -1) {
		if (errno != EINTR) { /* AY-880821 */
			perror("restore(ioctl)");
			fprintf(stderr, "\r");
			die(1);
		}

		ioctl(path[pn], TCFLSH, 2);	/* AY-880821 */
		if (ioctl(path[pn], TCSETAW, &tbufsave) == -1) {
			perror("restore"); fprintf(stderr, "\r");
			die(1);
		}
	}
	flowon = 0;
	return (alarm(0) == 0);	/* AY-880821 */
}

mbsleep(s)
int s;
{
	long t;

	settmr(&t, s);
	while(chktmr(t)) ;
}

void xeparse()
{
	register short bl;
	register char *in, *out;
	static char *nullst = "";

	for (port->flds = 0; port->flds < maxflds;)
		port->fld[port->flds++] = nullst;

	in  = port->line;
	out = port->cmd;
	bl  = false;
	port->flds = 0;

	while (*in and (port->flds < maxflds)
		and (out < (port->cmd + cmdlen - 1))) {
		if ((port->flds is 0) && (islower(*in)))
			*out = toupper(*in);
		else
			*out = *in;
		if (bl) { 
			if (*in <= ' ') { 
				bl = false; 
				*out = '\0'; 
			}  
			out++; 
		} else { 
			if (*in > ' ')  { 
				bl = true; 
				port->fld[port->flds++] = out++; 
			}
		}
		in++;
	}
	*out = '\0';

	port->opt1 = *port->fld[0];
	port->opt2 = *(port->fld[0] + 1);
	if (!port->opt2) port->opt2 = ' ';
}

setmfhs()
{
	sync();
	read_rec(mfl, 0, (char *)mfhs);
}

#if !SEM_NO	/* Test for semapho AY-881005 */
extern int mfl_sid, ufl_sid;
db_lock(fid)
int fid;
{
	sync();
	P((fid == mfl) ? mfl_sid : ufl_sid);

	DBGMSG((stderr, "%s - lock\n\r", (fid == mfl) ? "mail.dat" : "user.dat"));
}

db_unlock(fid)
int fid;
{
	sync();
	V((fid == mfl) ? mfl_sid : ufl_sid);
	DBGMSG((stderr, "%s - unlock\n\r", (fid == mfl) ? "mail.dat" : "user.dat"));
}
#else
db_lock(fid)
int fid;
{
	sync();
	if (lseek(fid, 0L, 0) == -1)
		syserr("Database can't seek", errno);
	if (locking(fid, LK_LOCK, 0))
		syserr("Database can't lock", errno);
	DBGMSG((stderr, "%s - lock\n\r", (fid == mfl) ? "mail.dat" : "user.dat"));
}

db_unlock(fid)
int fid;
{
	if (lseek(fid, 0L, 0) == -1)
		syserr("Database can't seek", errno);
	if (locking(fid, LK_UNLCK, 0))
		syserr("Database can't unlock", errno);
	sync();
	DBGMSG((stderr, "%s - unlock\n\r", (fid == mfl) ? "mail.dat" : "user.dat"));
}
#endif
