
/*
 * WINDOW.C
 *
 *	DNET interactive terminal window.
 */

#include "dnet.h"
#include <stdio.h>

#include "/server/servers.h"

typedef struct IOStdReq     IOCON;
typedef struct TextAttr     TA;
typedef struct IntuiText    ITEXT;
typedef struct MenuItem     ITEM;
typedef struct Menu	    MENU;
extern void *OpenWindow();

long	IntuitionBase;
long	GfxBase;

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

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

ITEM Item[] = {
    { &Item[1], 0, 0, 120, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[0], NULL, 'b' },
    { &Item[2], 0,10, 120, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[1], NULL, 's' },
    { NULL    , 0,20, 120, 10, ITEMTEXT|COMMSEQ|ITEMENABLED|HIGHCOMP, 0, (APTR)&IText[2], NULL, 'q' }
};

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

do_dnetwindow()
{
    static struct NewWindow Nw = {
	50, 50, 320, 100, -1, -1,
	CLOSEWINDOW|MENUPICK,
	WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|NOCAREREFRESH|ACTIVATE,
	NULL, NULL, (UBYTE *)"DNET V1.10", NULL, NULL,
	32, 32, -1, -1, WBENCHSCREEN
    };
    struct Window *win;
    char RcvBuf[128];
    char Cc;
    char RSync = 0;
    long imask, smask, conmask, mask, dnet_mask;
    IOCON *iocr, *iocw;
    char notdone = 1;
    int returncode = -1;

    setparity(0xFF, 0x00, 0);
    IntuitionBase = OpenLibrary("intuition.library", 0);
    GfxBase = OpenLibrary("graphics.library", 0);
    if (IntuitionBase == NULL || GfxBase == NULL)
	goto e1;
    win = OpenWindow(&Nw);
    if (win == NULL)
	goto e1;
    SetMenuStrip(win, Menu);
    OpenConsole(win, &iocr, &iocw);
    if (iocr == NULL)
	goto e3;
    if (Wto_act) {
	AbortIO(&Wto);
	WaitIO(&Wto);
	Wto_act = 0;
    }
    AbortIO(RNet);
    WaitIO(RNet);
    RNet->io_Data = (APTR)RcvBuf;
    RNet->io_Length = 1;
    SendIO(RNet);
    iocr->io_Data = (APTR)&Cc;
    iocr->io_Length = 1;
    SendIO(iocr);

    NetWrite("\rAT\r", 4, 0);     /*  cause modem to reset baud rate */

    imask   = 1 << win->UserPort->mp_SigBit;
    smask   = 1 << RNet->io_Message.mn_ReplyPort->mp_SigBit;
    conmask = 1 << iocr->io_Message.mn_ReplyPort->mp_SigBit;
    dnet_mask = 1 << DNetPort->mp_SigBit;

    while (notdone) {
	mask = Wait(imask|smask|conmask|dnet_mask);
	if (mask & dnet_mask) {
	    register IOR *ior;
	    while (ior = (IOR *)GetMsg(DNetPort)) {
		switch(ior->io_Command) {
		default:
		case DNCMD_WRITE:
		case DNCMD_EOF:
		case DNCMD_IOCTL:
		case DNCMD_QUIT:
		case DNCMD_OPEN:
		    ior->io_Error = 1;
		    break;
		case DNCMD_CLOSE:
		    Chan[(ulong)ior->io_Unit].state = CHAN_FREE;
		    break;
		case DNCMD_SOPEN:
		    {
			uword chan = (ulong)ior->io_Unit;
			Chan[chan].state = CHAN_FREE;
			if (!ior->io_Error) {
			    Chan[chan].state = CHAN_CLOSE;
			    Chan[chan].port  = (PORT *)ior->io_Offset;
			    Chan[chan].flags = CHANF_RCLOSE;
			    WritePort(Chan[chan].port, DNCMD_CLOSE, NULL, 0, PKT_REQ, chan);
			}
			if (ior->io_Length)
			    FreeMem(ior->io_Data, ior->io_Length);
			FreeMem(ior, sizeof(IOR));
			ior = NULL;
		    }
		    break;
		}
		if (ior)
		    ReplyMsg(ior);
	    }
	}
	if (mask & imask) {
	    struct IntuiMessage *im;
	    while (im = GetMsg(win->UserPort)) {
		switch(im->Class) {
		case CLOSEWINDOW:
		    notdone = 0;
		    returncode = -1;
		    break;
		case MENUPICK:
		    switch((uword)((MENUNUM(im->Code)<<8)|ITEMNUM(im->Code))) {
		    case 0x0000:    /*	menu 0 item 0	*/
			NetBreak();
			break;
		    case 0x0001:    /*	menu 0 item 1	*/
			notdone = 0;
			returncode = 1;
			break;
		    case 0x0002:    /*	menu 0 item 2	*/
			notdone = 0;
			returncode = -1;
			break;
		    case 0x0100:    /*	menu 1 item 0	*/
			break;
		    }
		    break;
		}
		ReplyMsg(im);
	    }
	}
	if (mask & smask) {
	    if (CheckIO(RNet)) {
		int n;
		ubyte dummy;

		WaitIO(RNet);
		if (RNet->io_Actual > 0) {
		    ubyte c = *(ubyte *)RNet->io_Data;
		    if (RSync && c == PKCMD_RESTART) {
			returncode = 1;
			notdone = 0;
		    }
		    RSync = (c == SYNC);
		    for (n = 0; n < RNet->io_Actual; ++n)
			((char *)RNet->io_Data)[n] &= 0x7F;
		    iocw->io_Data   = RNet->io_Data;
		    iocw->io_Length = RNet->io_Actual;
		    DoIO(iocw);
		}
		if ((n = NetReady(RNet, &dummy)) > sizeof(RcvBuf))
		    n = sizeof(RcvBuf);
		if (n <= 0)
		    n = 1;
		RNet->io_Data  = (APTR)RcvBuf;
		RNet->io_Length= n;
		SendIO(RNet);
	    }
	}
	if (mask & conmask) {
	    if (CheckIO(iocr)) {
		WaitIO(iocr);
		addparity(iocr->io_Data, iocr->io_Actual);
		NetWrite(iocr->io_Data, iocr->io_Actual, 0);
		NetWrite(NULL, 0, 0);
		iocr->io_Data = (APTR)&Cc;
		iocr->io_Length = 1;
		SendIO(iocr);
	    }
	}
    }

    AbortIO(RNet);
    WaitIO(RNet);
    RNet->io_Data   = (APTR)&Raux->sync; /*  Startup the network read    */
    RNet->io_Length = 3;
    SendIO(RNet);

    AbortIO(iocr);
    WaitIO(iocr);
    CloseConsole(iocr, iocw);
e3:
    CloseWindow(win);
e1:
    if (IntuitionBase)  CloseLibrary(IntuitionBase);
    if (GfxBase)        CloseLibrary(GfxBase);
    if (returncode > 0)
	puts("DNET RUNNING");
    else
	puts("DNET EXITING");
    return(returncode);
}

/*
 *  PARITY ROUTINES
 */

static ubyte Party[256/8];

setparity(pand, por, podd)
{
    register short i, j, k, l;
    bzero(Party, sizeof(Party));
    for (i = 0; i < 128; ++i) {
	for (j = (~i & 127), k = 0; j; j >>= 1) {   /*  k = count # of 0's */
	    if (j & 1)
		++k;
	}
	k ^= podd;
	l = (((k & 1) ? 0x01 : 0) | por) & pand;
	Party[i >> 3] |= l << (i & 7);
    }
}

addparity(buf, bytes)
register ubyte *buf;
{
    register short i;
    for (i = bytes - 1; i >= 0; --i) {
	if (Party[buf[i]>>3] & (1 << (buf[i]&7)))
	    buf[i] |= 0x80;
    }
}

OpenConsole(win, piocr, piocw)
IOCON **piocr, **piocw;
struct Window *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;
    }
}

CloseConsole(iocr, iocw)
IOCON *iocr;
IOCON *iocw;
{
    CloseDevice(iocr);
    DeletePort(iocr->io_Message.mn_ReplyPort);
}


