
/*
 *  S_TERM.C
 *
 *  DNET (c)Copyright 1988, Matthew Dillon, All Rights Reserved.
 *
 *  Terminal window server.
 *	-Echo what is received in the window.
 *	-Transmit stuff typed on keyboard, echoing locally.
 *
 *  Use FTERM on the other Amiga to connect.
 */


#include <stdio.h>
#include <fcntl.h>
#include "servers.h"
#include "/include/typedefs.h"

int Enable_Abort;
int NHandlers;

long IntuitionBase;
long GfxBase;

extern struct MsgPort *DListen();
extern struct MsgPort *DAccept();
extern struct Window *OpenWindow();
extern void *GetMsg(), *CreatePort(), *AllocMem();
extern PROC *FindTask();

struct MsgPort *HdPort;
struct MsgPort *LisPort;
short HandShakeSig;

_main()
{
    struct Message *msg;
    long mask, pmask, hdmask;
    PROC *proc = FindTask(NULL);

    Enable_Abort = 0;
    LisPort= DListen(PORT_IALPHATERM);
    WaitPort(&proc->pr_MsgPort);
    ReplyMsg(GetMsg(&proc->pr_MsgPort));
    if (!LisPort)
	exit(1);
    HdPort = CreatePort(NULL, 0);
    HandShakeSig = AllocSignal(-1);
    pmask = 1 << LisPort->mp_SigBit;
    hdmask= 1 << HdPort->mp_SigBit;

    IntuitionBase   = OpenLibrary("intuition.library", 0);
    GfxBase	    = OpenLibrary("graphics.library", 0);
    while (mask = Wait(SIGBREAKF_CTRL_C|pmask|hdmask)) {
	if (mask & SIGBREAKF_CTRL_C)
	    break;
	if (mask & hdmask) {
	    while (msg = GetMsg(HdPort)) {
		--NHandlers;
		FreeMem(msg, sizeof(*msg));
	    }
	}
	if (mask & pmask) {
	    while (spawn_handler())
		;
	}
    }
    DUnListen(LisPort);
    while (NHandlers) {
	WaitPort(HdPort);
	msg = GetMsg(HdPort);
	FreeMem(msg, sizeof(*msg));
	--NHandlers;
    }
    DeletePort(HdPort);
    CloseLibrary(IntuitionBase);
    CloseLibrary(GfxBase);
}

/*
 *  Spawn a handler to accept the new connection, if any.  Task sends
 *  a message to HdPort when through.
 */

spawn_handler()
{
    extern void term_task();
    long oldhan = NHandlers;

    CreateTask("Term.channel", 0, term_task, 2048);
    Wait(1 << HandShakeSig);
    return (oldhan != NHandlers);
}

static NW Nw = {
    64, 64, 400, 100, -1, -1,
    VANILLAKEY|CLOSEWINDOW,
    WINDOWSIZING|WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|ACTIVATE|NOCAREREFRESH,
    NULL, NULL, (unsigned char *)"DNET-Term", NULL, NULL, 32, 32, -1, -1,
    WBENCHSCREEN
};

void
term_task()
{
    struct MsgPort *chan;   /*	actually only the front end is a msgport */
    IMESS *im;
    long n;
    long imask, cmask;
    struct Message *msg;
    struct Window *win;
    char notdone = 1;
    char buf[32];
    IOCON ioc;

    geta4();
    chan = (struct MsgPort *)DAccept(LisPort);
    if (chan) {
	DQueue(chan, 32);
	++NHandlers;
	Signal(HdPort->mp_SigTask, 1 << HandShakeSig);
	if (win = OpenWindow(&Nw)) {
	    ioc.io_Command = CMD_WRITE;
	    ioc.io_Data = (APTR)win;
	    ioc.io_Message.mn_Node.ln_Type = NT_MESSAGE;
	    ioc.io_Message.mn_ReplyPort = win->UserPort;
	    OpenDevice("console.device", 0, &ioc, 0);
	    imask = 1 << win->UserPort->mp_SigBit;
	    cmask = 1 << chan->mp_SigBit;
	    while (notdone) {
		Wait(imask|cmask);
		while (im = (IMESS *)GetMsg(win->UserPort)) {
		    switch(im->Class) {
		    case VANILLAKEY:
			n = 1;
			buf[0] = im->Code;
			if (buf[0] == 13) {
			    buf[1] = 10;
			    ++n;
			}
			DWrite(chan, buf, n);
			ioc.io_Data = (APTR)buf;
			ioc.io_Length = n;
			DoIO(&ioc);
			break;
		    case CLOSEWINDOW:
			notdone = 0;
			break;
		    }
		    ReplyMsg(im);
		}
		while (n = DNRead(chan, buf, sizeof(buf))) {
		    if (n < 0) {
			notdone = 0;
			break;
		    }
		    DWrite(chan, buf, n);   /* echo back */
		    if (buf[0] == 3)        /*  remote ^C -- done   */
			notdone = 0;
		    ioc.io_Data = (APTR)buf;
		    ioc.io_Length = n;
		    DoIO(&ioc);
		}
	    }
	    CloseDevice(&ioc);
	    CloseWindow(win);
	}
	DClose(chan);
	msg = AllocMem(sizeof(*msg), MEMF_PUBLIC);
	Forbid();
	PutMsg(HdPort, msg);
    } else {
	Forbid();
	Signal(HdPort->mp_SigTask, 1 << HandShakeSig);
    }
    RemTask(NULL);
}

