
/*
 *  CLITERM.C
 *
 *  DNET (c)Copyright 1988-1989, Matthew Dillon, All Rights Reserved.
 *
 *  FTERM [-Nnet] [port]
 */

#include "defs.h"

typedef struct IORequest RIO;


#ifndef DEVICES_CONUNIT_H
typedef struct ConUnit	    CONUNIT;
typedef struct IOStdReq     IOCON;
#endif

short IgnoreNS = 0;

TA Ta = { (ubyte *)"topaz", 8 };

ITEXT IText[] = {
    { 0, 1, JAM2, 0, 0, &Ta, (ubyte *)"Flush"          }
};

ITEM Item[] = {
    { NULL    , 0, 0, 100, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[0], NULL, 'o' }
};

MENU Menu[] = {
    { NULL    , 0, 0, 100, 20, MENUENABLED, "Control", &Item[0] }
};

char Title[80];

NW Nw = {
    0, 12, 640, 60, -1, -1,
    NEWSIZE|CLOSEWINDOW|MENUPICK,
    WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|ACTIVATE,
    NULL, NULL, (ubyte *)Title, NULL, NULL,
    32, 32, -1, -1, WBENCHSCREEN
};

WIN *Win;

extern int Enable_Abort;
char Buf[512];
char Term[64] = { "FTERM (UNNAMED SHELL)" };
char Cc;

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
IOCON *iocr, *iocw;

void OpenConsole ARGS((WIN *, IOCON **, IOCON **));
void HandleIoctl ARGS((short, short, char, WIN *, IOCON *));
void CloseConsole ARGS((IOCON *, IOCON *));
void setsize ARGS((IOCON *, void *, WIN *));
void localecho ARGS((int));

void main ARGS((int, char **));

int
brk()
{
    return(0);
}

void
main(ac,av)
char *av[];
{
    void *chan;
    long imask, conmask, dmask, mask;
    char notdone = 1;
    char portspec = 0;
    char *host = NULL;
    uword port = PORT_AMIGASHELL;
    int i;
    int bp = 0;
    char inputbuf[256];

    onbreak(brk);
    sprintf(Title, "CLITerm V%s%s opening, wait..", VERSION, CLITERM_VERSION);
    {
	short i;
	for (i = 1; i < ac; ++i) {
	    if (strncmp(av[i], "-N", 2) == 0) {
		host = av[i] + 2;
		continue;
	    }
	    portspec = 1;
	    port = atoi(av[i]);
	}
    }
    if (portspec)
	printf("Using port %ld\n", port);
#ifndef LATTICE
    Enable_Abort = 0;
#endif
    IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0);
    GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0);
    Win = OpenWindow(&Nw);
    if (Win == NULL)
	goto e1;
    OpenConsole(Win, &iocr, &iocw);
    if (iocr == NULL || iocw == NULL)
	goto e3;

    /*
     *	We delay here to allow DNET to go through its RESTART sequence
     *	(when DNET automatically runs FTERM, it does so to quickly).
     *	Such a hack!
     */

    Delay(50 * 4);
    chan = DOpen(host, port, 20, 15);

    if (!chan) {
	puts("Unable to connect");
	goto e3;
    }
    DQueue(chan, 32);
    SetMenuStrip(Win, Menu);
    SetWindowTitles(Win, Term, (char *)-1);
    imask   = 1 << Win->UserPort->mp_SigBit;
    dmask   = 1 << ((PORT *)chan)->mp_SigBit;
    conmask = 1 << iocr->io_Message.mn_ReplyPort->mp_SigBit;
    iocr->io_Data = (APTR)&Cc;
    iocr->io_Length = 1;
    SendIO((RIO *)iocr);

    setsize(iocw, chan, Win);

    while (notdone) {
	mask = Wait(imask|dmask|conmask);
	if (mask & imask) {
	    IMESS *im;
	    while (im = (IMESS *)GetMsg(Win->UserPort)) {
		switch(im->Class) {
		case NEWSIZE:
		    if (IgnoreNS) {
			--IgnoreNS;
			setsize(iocw, NULL, Win);
		    } else {
			setsize(iocw, chan, Win);
		    }
		    break;
		case CLOSEWINDOW:
		    notdone = 0;
		    break;
		case MENUPICK:
		    switch((uword)((MENUNUM(im->Code)<<8)|ITEMNUM(im->Code))) {
		    case 0x0000:    /*	menu 0 item 0	*/
			DIoctl(chan, CIO_FLUSH, 0, 0);
			break;
		    case 0x0001:    /*	menu 0 item 1	*/
		    case 0x0002:    /*	menu 0 item 2	*/
		    case 0x0100:    /*	menu 1 item 0	*/
			break;
		    }
		    break;
		default:
		    break;
		}
		ReplyMsg((MSG *)im);
	    }
	}
	if (mask & dmask) {
	    char buf[256];
	    int n;
	    if ((n = DNRead(chan, buf, 256)) > 0) {
		for (i = 0; i < n; i++) {
		    if (buf[i] == '\n') {
			movmem(&buf[i], &buf[i + 1], n - i);
			buf[i] = '\r';
			i++;
			n++;
		    }
		}
		iocw->io_Data = (APTR)buf;
		iocw->io_Length = n;
		DoIO((RIO *)iocw);
	    }
	    if (n == -2) {
		short val;
		short cmd;
		char aux;

		cmd = DGetIoctl(chan, &val, &aux);
		HandleIoctl(cmd, val, aux, Win, iocw);
		/*
		if (cmd == CIO_MODE) {
		    if (val)
			SetWindowTitles(Win, "(Cooked)", (char *)-1);
		    else
			SetWindowTitles(Win, "(Raw)", (char *)-1);
		}
		*/
	    } else if (n < 0)
		notdone = 0;
	}
	if (mask & conmask) {
	    if (CheckIO((RIO *)iocr)) {
		WaitIO((RIO *)iocr);

		if (Cc == '\r')
			Cc = '\n';
		inputbuf[bp++] = Cc;

		if (Cc == 0x08) {
		    if (bp <= 1) {
			bp = 0;
		    } else {
			localecho(0x08);
			localecho(0x20);
			localecho(0x08);
			bp -= 2;
		    }
		} else if (Cc == 0x18) {
		    while (--bp > 0) {
			localecho(0x08);
			localecho(0x20);
			localecho(0x08);
		    }
		} else if (Cc == '\n') {
		    localecho('\n');
		    localecho('\r');
		    DWrite(chan, inputbuf, bp);
		    bp = 0;
		} else {
		    localecho(Cc);
		}

		iocr->io_Data = (APTR)&Cc;
		iocr->io_Length = 1;
		SendIO((RIO *)iocr);
/*
		if (Cc == '\r') {
		    Cc = '\n';
		    DWrite(chan, &Cc, 1);
		    iocr->io_Data = (APTR)&Cc;
		    iocr->io_Length = 1;
		    SendIO(iocr);
		}
*/
	    }
	}
    }
    AbortIO((RIO *)iocr);
    WaitIO((RIO *)iocr);
    SetWindowTitles(Win, "Closing...", (char *)-1);
    DClose(chan);
e3: CloseConsole(iocr,iocw);
    CloseWindow(Win);
e1: CloseLibrary((LIB *)IntuitionBase);
    CloseLibrary((LIB *)GfxBase);
}

void
localecho(c)
int c;
{
    char cc;

    cc = c;
    iocw->io_Data = (APTR)&cc;
    iocw->io_Length = 1;
    DoIO((RIO *)iocw);
}

void
OpenConsole(win, piocr, piocw)
IOCON **piocr, **piocw;
WIN *win;
{
    PORT *port;
    static IOCON iocr, iocw;
    int error;

    port = CreatePort(NULL, 0);
    iocr.io_Command = CMD_READ;
    iocr.io_Data = (APTR)win;
    iocr.io_Message.mn_Node.ln_Type = NT_MESSAGE;
    iocr.io_Message.mn_ReplyPort = port;
    error = OpenDevice("console.device", 0, (RIO *)&iocr, 0);
    if (!error) {
	iocw = iocr;
	iocw.io_Command = CMD_WRITE;
	*piocr = &iocr;
	*piocw = &iocw;
    } else {
	*piocr = *piocw = NULL;
    }
}

void
CloseConsole(iocr, iocw)
IOCON *iocr;
IOCON *iocw;
{
    IOCON *tmp = (iocr) ? iocr : iocw;
    if (tmp) {
	CloseDevice((RIO *)tmp);
	DeletePort(tmp->io_Message.mn_ReplyPort);
    }
}

void
setsize(iocw, chan, win)
IOCON *iocw;
void *chan;
WIN *win;
{
    struct ConUnit *cu = (struct ConUnit *)iocw->io_Unit;
    static char IStr[] = { "\033c\23320l\233t\233u" };

    /*
    if (Cooked & 4)
	IStr[5] = 'h';
    else
	IStr[5] = 'l';
    */
    iocw->io_Data = (APTR)IStr;
    iocw->io_Length = sizeof(IStr) - 1;
    DoIO((RIO *)iocw);
    if (chan) {
	DIoctl(chan, CIO_SETROWS, (uword)(cu->cu_YMax+1), 0);
	DIoctl(chan, CIO_SETCOLS, (uword)(cu->cu_XMax+1), 0);
    }
    sprintf(Term, "FTERM   %ld x %ld", cu->cu_YMax+1, cu->cu_XMax+1);
    SetWindowTitles(win, Term, (char *)-1);
}

void
HandleIoctl(cmd, val, aux, win, iocw)
short cmd, val;
char aux;
WIN *win;
IOCON *iocw;
{
    static short saverows;
    short height, width;
    short dx, dy;

    switch(cmd) {
    case CIO_MODE:
	/*
	Cooked = val;
	*/
	break;
    case CIO_SETROWS:
	saverows = val;
	break;
    case CIO_SETCOLS:
	width = val * win->RPort->TxWidth + win->BorderLeft + win->BorderRight;
	height= saverows * win->RPort->TxHeight + win->BorderTop + win->BorderBottom;

	dx = win->WScreen->Width - (win->LeftEdge + width);
	if (dx > 0)
	    dx = 0;
	if (-dx > win->LeftEdge) {
	    dx = -win->LeftEdge;
	    width = win->WScreen->Width;
	}

	dy = win->WScreen->Height - (win->TopEdge + height);
	if (dy > 0)
	    dy = 0;
	if (-dy > win->TopEdge) {
	    dy = -win->TopEdge;
	    height = win->WScreen->Height;
	}

	if (dx || dy) {
	    MoveWindow(win, dx, dy);
	}
	if (win->Width != width || win->Height != height) {
	    SizeWindow(win, width - win->Width, height - win->Height);
	    ++IgnoreNS;
	}
	break;
    }
}

