
/*
 *  FTERM.C
 *
 *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 *
 *  FTERM [-Nnet] [port] [-wcapturefile] [-c#]
 *
 *  -c# = cooked mode.	i.e. -c7    bit 0   convert CR's to LF's keyboard->remote
 *				    bit 1   echo chars locally (half duplex)
 *				    bit 2   received LF->CRLF
 */

#include "defs.h"
#include <local/deemu.h>

short Deemu[] = {
    DMSTRT, 0, 0,
    DMNW  , 0,10, 11, 11, -37, -28, 0xFFFF,
    DMTEXT, 0,30, 'FO','NT','\0t','op','az','.f','on','t.','8\0',0,0,0,0,0,0,
    DMEND , 0, 0
};

#define DMNWOFF     4
#define DMFONTSTR   17

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

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

ITEM Item[] = {
    { &Item[1], 0, 0, 100, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[0], NULL, 'o' },
    { &Item[2], 0,10, 100, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[1], NULL, 'a' },
    { &Item[3], 0,20, 100, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[2], NULL, 'n' },
    { &Item[4], 0,30, 100, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[3], NULL, 'c' },
    { NULL    , 0,40, 100, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[4], NULL, 'p' }
};

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

ubyte Title[80];

NW Nw = {
    0, 0, 640, 200, -1, -1,
    NEWSIZE|CLOSEWINDOW|MENUPICK,
    WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|ACTIVATE,
    NULL, NULL, Title, NULL, NULL,
    32, 32, -1, -1, WBENCHSCREEN
};

WIN *Win;

extern int Enable_Abort;
char Buf[512];
char Term[64];
char Cc;
char Cooked;	/*  bit 0 = cooked,  bit 1 = local echo */
char IgnoreNS;



struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

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 main ARGS((int, char **));

int
brk()
{
    return(0);
}

void
main(ac, av)
char *av[];
{
    void *chan;
    long imask, conmask, dmask, mask;
    IOCON *iocr, *iocw;
    char notdone = 1;
    char portspec = 0;
    char *host = NULL;
    char *capfile = NULL;
    FILE *capfi = NULL;
    uword port = PORT_IALPHATERM;
    FONT *font = NULL;

    onbreak(brk);
    sprintf(Title, "FTerm V%s%s", VERSION, FTERM_VERSION);
    strcpy(Term, Title);
    strcat(Title, " opening, wait ...");

    {
	char *str = av[0];
	for (str = str + strlen(str); str >= av[0]; --str) {
	    if (*str == '/' || *str == ':')
		break;
	}
	++str;
	if ((*str | 0x20) == 'b')   /*  bbsterm instead of fterm    */
	    port = PORT_BBS;
    }

    {
	short i;
	for (i = 1; i < ac; ++i) {
	    char *ptr = av[i];
	    if (*ptr == '-') {
		while (*++ptr) {
		    switch(*ptr) {
		    case 'N':
			host = ptr + 1;
			ptr = "\0";
			break;
		    case 'w':
			capfile = ptr + 1;
			ptr = "\0";
			break;
		    case 'c':
			Cooked = atoi(ptr + 1);
			ptr = "\0";
			break;
		    default:
			printf("Unknown option: '%c'\n", *ptr);
			break;
		    }
		}
	    } else {
		portspec = 1;
		port = atoi(ptr);
	    }
	}
    }
    if (capfile)
	capfi = fopen(capfile, "a");
    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);

    InitDeemuNW(Deemu+DMNWOFF, &Nw);
    {
	char *p1, *p2;
	p1 = (char *)(Deemu+DMFONTSTR) + strlen((char *)(Deemu+DMFONTSTR)) + 1;
	for (p2 = p1 + strlen(p1); p2 != p1 && *p2 != '.'; --p2);
	if (*p2 == '.') {
	    *p2 = 0;
	    font = (FONT *)GetFont(p1, (short)atoi(p2+1));
	}
    }

    Win = OpenWindow(&Nw);
    if (Win == NULL)
	goto e1;
    if (font) {
	SetFont(Win->RPort, font);
	SetRast(Win->RPort, 0);
	RefreshWindowFrame(Win);
    }
    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(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	*/
			if (capfi)
			    fclose(capfi);
			capfi = fopen("ram:capture", "a");
			break;
		    case 0x0002:
			if (capfi)
			    fclose(capfi);
			capfi = fopen("ram:capture", "w");
			break;
		    case 0x0003:    /*	menu 0 item 2	*/
			if (capfi)
			    fclose(capfi);
			capfi = NULL;
			break;
		    case 0x0004:    /*	menu 0 item 3	*/
			{
			    FILE *fi;
			    long n;
			    if (fi = fopen("ram:paste", "r")) {
				while ((n = fread(Buf, 1, sizeof(Buf), fi)) > 0) {
				    DWrite(chan, Buf, n);
				}
				fclose(fi);
			    }
			}
			break;
		    case 0x0100:    /*	menu 1 item 0	*/
			break;
		    }
		}
		ReplyMsg((MSG *)im);
	    }
	}
	if (mask & dmask) {
	    int n;
	    if ((n = DNRead(chan, Buf, sizeof(Buf))) > 0) {
		iocw->io_Data = (APTR)Buf;
		iocw->io_Length = n;
		DoIO(iocw);
		if (capfi)
		    fwrite(Buf, n, 1, capfi);
	    } else 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(iocr)) {
		WaitIO(iocr);
		if (Cooked & 2) {       /*  Local Echo  */
		    iocw->io_Data = (APTR)&Cc;
		    iocw->io_Length = 1;
		    DoIO(iocw);
		}
		if ((Cooked & 1) && Cc == 13) {
		    Cc = 10;
		    iocw->io_Data = (APTR)&Cc;
		    iocw->io_Length = 1;
		    DoIO(iocw);
		}
		DWrite(chan, &Cc, 1);
		iocr->io_Data = (APTR)&Cc;
		iocr->io_Length = 1;
		SendIO(iocr);
	    }
	}
    }
    AbortIO(iocr);
    WaitIO(iocr);
    SetWindowTitles(Win, "Closing...", (char *)-1);
    DClose(chan);
e3: CloseConsole(iocr,iocw);
    if (font) {
	SetFont(Win->RPort, Win->WScreen->RastPort.Font);
	CloseFont(font);
    }
    CloseWindow(Win);
e1: CloseLibrary((LIB *)IntuitionBase);
    CloseLibrary((LIB *)GfxBase);
    if (capfi)
	fclose(capfi);
}

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, &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(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(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;
    }
}


