/* Implements a SUPDUP server for the C-Gateway. */

#include <types.h>
#include <sys.h>
#include <itp.h>
#include "../src/const.h"
#include "../src/param.h"
#include "../src/defs.h"
#include "../src/macs.h"
#include "../src/net.h"
#include "../src/ext.h"
#include "in.h"
#include "tcp.h"

#define SUPDUP_SOCK 95

tcp_Socket sd_conn;
intf sd_open;
dct *sd_devp;			/* Pseudo device to write to to send
				 * to the SUPDUP connection */
iorb *sd_iob;			/* iorb that input is collected in by opcon */
ext int good_password;		/* Cleared when a supdup connection is
				 * opened or closed. */

SUPDUP()
{
    int sd_in();

    sd_open = 0;
    good_password = 0;
    tcp_Listen(&sd_conn, SUPDUP_SOCK, sd_in, 0);
}

/* Transmit initialization routine for the pseudo device.  Remembers
 * the device and sets up the input iorb. */
sd_tup(devp)
dct *devp;
{
    sd_devp = devp;
    sd_iob = (iorb *)mem_alloc(sizeof(iorb) + 128);
    sd_iob->i_addr = (byte *)(sd_iob + 1);
    sd_iob->i_breq = 128;
    sd_iob->i_bxfr = 0;
    sd_iob->i_devp = devp;
}

/* Receives data from the supdup connection. */
sd_in(s, dp, len)
tcp_Socket *s;
byte *dp;
int len;
{
    static char sd_msg[] = "C Gateway SUPDUP server\r\n\210";
    int slen;
    static dct *saved_log_dev;
    ext dct *log_dev;

    if (dp == 0) {
	log_dev = saved_log_dev;
	dolog("SUPDUP connection closed\n");
	SUPDUP();
	if (sd_devp->d_qhd)
	  iocmr(sd_devp);	/* Free the iorb's if any pending output */
	return;
    }

/*    dolog("SUPDUP data, len = %d\n", len); */
    if (sd_open && len > 0) {
	while (len--) {
	    if (*dp == ITP_ESCAPE) {
		int c;

		if (len < 2) break;
		c = ITP_CHAR(dp[1], dp[2]);
		dp += 2;
		len -= 2;
		if (c == ITP_HELP)
		  *dp = '?';
		else {
		    if (c & ITP_CTL)
		      *dp = ASCII_PART(c & ASCII_CTL_MASK);
		    else
		      *dp = ASCII_PART(c);
		}
	    }
	    opcon_input(sd_iob->i_devp, sd_iob, *dp++);
	}
    }
    if (sd_devp->d_qhd) {
	slen = tcp_Write(&sd_conn, sd_devp->d_addr, sd_devp->d_breq);
/*	dolog("SUPDUP wrote %d\n", slen); */
	if (slen < sd_devp->d_breq) {
	    sd_devp->d_breq -= slen;
	    sd_devp->d_addr += slen;
	}
	else {
	    iocmr(sd_devp);
	}
    }

    if (sd_open == 0) {
	tcp_Write(&sd_conn, sd_msg, sizeof(sd_msg) - 1);
	saved_log_dev = log_dev;
	log_dev = sd_devp;
	sd_open = 1;
	good_password = 0;
    }
}

sd_write(devp)
reg dct *devp;
{
    reg byte *cp;
    reg int slen;

    if (!sd_open)
      iocmr(devp);
    for (cp = devp->d_addr, slen = devp->d_breq; slen; slen--, cp++)
      if (*cp == '\n') *cp = TDCRL;

    slen = tcp_Write(&sd_conn, devp->d_addr, devp->d_breq);
    if (slen == devp->d_breq)
      iocmr(devp);
    else {
	devp->d_breq -= slen;
	devp->d_addr += slen;
    }
}
