/* Main network program - provides both client and server functions */

#define HOSTNAMELEN 32		/* changed from 16 by Bdale 860812 */

extern char startup[];		/* File to read startup commands from */

#include <stdio.h>
#include "config.h"
#include "global.h"
#include "mbuf.h"
#include "netuser.h"
#include "timer.h"
#include "icmp.h"
#include "iface.h"
#include "ip.h"
#include "tcp.h"
#include "ax25.h"
#include "remote.h"
#include "netrom.h"
#include "ftp.h"
#include "telnet.h"
#include "session.h"
#include "cmdparse.h"

#ifdef UNIX		/* BSD or SYS5 */
#include "unix.h"
#endif

#ifdef AMIGA
#include "amiga.h"
#endif

#ifdef MAC
#include "mac.h"
#endif

#ifdef MSDOS
#include "pc.h"
#endif

#ifdef ATARI_ST
#include "st.h"
#endif

#ifdef LATTICE
extern long _MNEED;		/* reserve memory for child process (shell) */
long _MNEED = 100000;		/* plucked out of thin air */
extern long _32K;
long _32K = 0x8000;		/* keep GST Linker happy */
#endif

#ifdef	MWC
long	_stksize = 0x40000L;	/* 256K oughta be enough... */
#endif

#ifdef	TRACE
#include "trace.h"
/* Dummy structure for loopback tracing */
struct interface loopback = { NULLIF, "loopback" };
#endif

extern struct interface *ifaces;
extern char version[];
extern char implementation[];	/* DG2KK */
extern struct mbuf *loopq;

int ttyflow;			/* NEW!!!!!!!! DG2KK */
int mode;
FILE *logfp;
char badhost[] = "Unknown host %s\n";
char hostname[HOSTNAMELEN];	
unsigned nsessions = NSESSIONS;
int32 resolve();
int16 lport = 1001;
char prompt[] = "net> ";
char nospace[] = "No space!!\n";	/* Generic malloc fail message */


#if	(!MSDOS && !ATARI_ST)		/* PC/Atari uses F-10 key always */
static char escape = 0x1d;		/* default escape character is ^] */
#endif

/* Command lookup and branch table */
int go(),doax25(),cmdmode(),doconnect(),dotelnet(),doexit(),doclose(),
	dohostname(),doreset(),dotcp(),dotrace(),doescape(),dohelp(),
	doroute(),doecho(),dolog(),doip(),doetherstat(),
	memstat(),doarp(),dosession(),doftp(),dostart(),dostop(),doattach(),
	dosmtp(),doudp(),doparam(),doeol(),dohapnstat(),doremote(),
	doegstat(),dodump(),dorecord(),doupload(),dokick(),domode(),doshell(),
	dodir(),docd(),doatstat(),doping(),donetrom(),donrstat(),dotype();

static struct cmds cmds[] = {
	/* The "go" command must be first */
	"",		go,		0, NULLCHAR,	NULLCHAR,
	"!",		doshell,	0, NULLCHAR,	NULLCHAR,
#if	(MAC && APPLETALK)
	"applestat",	doatstat,	0, NULLCHAR,	NULLCHAR,
#endif
#if	(AX25 || ETHER || APPLETALK)
	"arp",		doarp,		0, NULLCHAR,	NULLCHAR,
#endif
#ifdef	AX25
	"ax25", 	doax25, 	0, NULLCHAR,	NULLCHAR,
#endif	
	"attach",	doattach,	2,
		"attach <hardware> <hw specific options>", NULLCHAR,
/* This one is out of alpabetical order to allow abbreviation to "c" */
#ifdef	AX25
	"connect",	doconnect,	3,"connect interface callsign [digipeaters]",
		NULLCHAR,
#endif
#ifndef UNIX	/* BSD or SYS5 */
	"cd",		docd,		0, NULLCHAR,	NULLCHAR,
#endif
	"close",	doclose,	0, NULLCHAR,	NULLCHAR,
	"disconnect",	doclose,	0, NULLCHAR,	NULLCHAR,
	"dir",		dodir,		0, NULLCHAR,	NULLCHAR,
#ifdef	EAGLE
	"eaglestat",	doegstat,	0, NULLCHAR,	NULLCHAR,
#endif
	"echo", 	doecho, 	0, NULLCHAR,	"echo [refuse|accept]",
	"eol",		doeol,		0, NULLCHAR,
		"eol options: unix, standard",
#if	(!MSDOS && !ATARI_ST)
	"escape",	doescape,	0, NULLCHAR,	NULLCHAR,   
#endif
#ifdef	PC_EC
	"etherstat",	doetherstat,	0, NULLCHAR,	NULLCHAR,
#endif	PC_EC
	"exit", 	doexit, 	0, NULLCHAR,	NULLCHAR,
	"ftp",		doftp,		2, "ftp <address>",	NULLCHAR,
#ifdef HAPN
	"hapnstat",	dohapnstat,	0, NULLCHAR,	NULLCHAR,
#endif HAPN
	"help", 	dohelp, 	0, NULLCHAR,	NULLCHAR,
	"hostname",	dohostname,	0, NULLCHAR,	NULLCHAR,
	"kick", 	dokick, 	0, NULLCHAR,	NULLCHAR,
	"log",		dolog,		0, NULLCHAR,	NULLCHAR,
	"ip",		doip,		0, NULLCHAR,	NULLCHAR,
	"memstat",	memstat,	0, NULLCHAR,	NULLCHAR,
#ifdef	AX25
	"mode", 	domode, 	2, "mode <interface>",	NULLCHAR,
	"netrom",	donetrom,	0, NULLCHAR,	NULLCHAR,
	"nrstat",	donrstat,	0, NULLCHAR,	NULLCHAR,
#endif
	"param",	doparam,	2, "param <interface>", NULLCHAR,
	"ping", 	doping, 	0, NULLCHAR,	NULLCHAR,
#ifndef UNIX /* BSD or SYS5 */
	"pwd",		docd,		0, NULLCHAR,	NULLCHAR,
#endif
	"record",	dorecord,	0, NULLCHAR,	NULLCHAR,
	"remote",	doremote,	4, "remote <address> <port> <command>",
							NULLCHAR,
	"reset",	doreset,	0, NULLCHAR,	NULLCHAR,
	"route",	doroute,	0, NULLCHAR,	NULLCHAR,
	"session",	dosession,	0, NULLCHAR,	NULLCHAR,
	"shell",	doshell,	0, NULLCHAR,	NULLCHAR,
	"smtp", 	dosmtp, 	0, NULLCHAR,	NULLCHAR,
#ifdef	SERVERS
	"start",	dostart,	2, "start <servername>",NULLCHAR,
	"stop", 	dostop, 	2, "stop <servername>", NULLCHAR,
#endif
	"tcp",		dotcp,		0, NULLCHAR,	NULLCHAR,
	"telnet",	dotelnet,	2, "telnet <address>",	NULLCHAR,
#ifdef	TRACE
	"trace",	dotrace,	0, NULLCHAR,	NULLCHAR,
#endif
	"type",		dotype,		0, NULLCHAR,	NULLCHAR,
	"udp",		doudp,		0, NULLCHAR,	NULLCHAR,
	"upload",	doupload,	0, NULLCHAR,	NULLCHAR,
	"?",		dohelp, 	0, NULLCHAR,	NULLCHAR,
	NULLCHAR,	NULLFP, 	0,
	"Unknown command; type \"?\" for list",   NULLCHAR, 
};

#ifdef	SERVERS
/* "start" and "stop" subcommands */
int ftp_start(),smtp_start(),discard_start(),echo_start(),telnet_start();
int tnc_start(), rem_start();
static struct cmds startcmds[] = {
	"discard",	discard_start,	0, NULLCHAR, NULLCHAR,
	"echo", 	echo_start,	0, NULLCHAR, NULLCHAR,
	"ftp",		ftp_start,	0, NULLCHAR, NULLCHAR,
	"remote",	rem_start,	0, NULLCHAR, NULLCHAR,
	"smtp", 	smtp_start,	0, NULLCHAR, NULLCHAR,
	"telnet",	telnet_start,	0, NULLCHAR, NULLCHAR,
	NULLCHAR,	NULLFP, 	0,
		"start options: discard, echo, ftp, remote, smtp, telnet",
		 NULLCHAR,
};
int ftp_stop(),smtp_stop(),echo_stop(),discard_stop(),telnet_stop(),
	rem_stop();
static struct cmds stopcmds[] = {
	"discard",	discard_stop,	0, NULLCHAR, NULLCHAR,
	"echo", 	echo_stop,	0, NULLCHAR, NULLCHAR,
	"ftp",		ftp_stop,	0, NULLCHAR, NULLCHAR,
	"remote",	rem_stop,	0, NULLCHAR, NULLCHAR,
	"smtp", 	smtp_stop,	0, NULLCHAR, NULLCHAR,
	"telnet",	telnet_stop,	0, NULLCHAR, NULLCHAR,
	NULLCHAR,	NULLFP, 	0,
		"stop options: discard, echo, ftp, remote, smtp, telnet",
		 NULLCHAR,
};
#endif

void
keep_things_going()
{
	void check_time();
	struct interface *ifp;
	struct mbuf *bp;

	/* Service the loopback queue */
	if((bp = dequeue(&loopq)) != NULLBUF){
		/* struct ip ip; */
#ifdef	TRACE
		dump(&loopback,IF_TRACE_IN,TRACE_IP,bp);
#endif
		/* Extract IP header */
		/* ntohip(&ip,&bp);
		   ip_recv(&ip,bp,0); */
		ip_recv(bp,0);
	}
	/* Service the interfaces */
	for(ifp = ifaces; ifp != NULLIF; ifp = ifp->next){
		if(ifp->recv != NULLFP)
			(*ifp->recv)(ifp);
	}

	/* Service the clock if it has ticked */
	check_time();

#ifdef	MSDOS
	/* Tell Doubledos to let the other task run for awhile.
	 * If Doubledos isn't active, this is a no-op.
	 */
	giveup();
#else
	/* Wait until interrupt, then do it all over again */
	eihalt();
#endif
}

main(argc,argv)
int argc;
char *argv[];
{
	static char inbuf[BUFSIZ];	/* keep it off the stack */
	int c;
	char *ttybuf,*fgets();
	int16 cnt;
	int ttydriv();
	int cmdparse();
	void check_time();
	FILE *fp;

	ioinit();
#if	(!UNIX && !AMIGA && !MAC && !ATARI_ST)
	chktasker();
#endif
#ifdef	MSDOS
	printf("KA9Q Internet Protocol Package, v%s DS = %x\n",version,
		getds());
#else
	printf("KA9Q Internet Protocol Package, v%s\n",version);
#endif
/*	printf("%s\n",implementation);	*/	/* DG2KK */
	printf("Copyright 1988 by Phil Karn, KA9Q\n");
	sessions = (struct session *)calloc(nsessions,sizeof(struct session));
	if(argc > 1){
		/* Read startup file named on command line */
		fp = fopen(argv[1],"r");
	} else {
		fp = fopen(startup,"r");
	}
	if(fp != NULLFILE){
		while(fgets(inbuf,BUFSIZ,fp) != NULLCHAR){
			cmdparse(cmds,inbuf);
		}
		fclose(fp);
	}		
	cmdmode();

	/* Main commutator loop */
	for(;;){
		/* Process any keyboard input */
		while((c = kbread()) != -1){
#if  (MSDOS || ATARI_ST)
			/* c == -2 means the command escape key (F10) */
			if(c == -2){
				if(mode != CMD_MODE){
					printf("\n");
					cmdmode();
				}
				continue;
			}
#endif
#ifdef SYS5
			if(c == escape && escape != 0){
				if(mode != CMD_MODE){
					printf("\r\n");
					cmdmode();
				}
				continue;
			}
#endif	 /* SYS5 */
/* ----------------------------(DG2KK)------------------------------- */
#ifndef FLOW
			if((cnt = ttydriv(c,&ttybuf)) == 0)
				continue;
#else
			cnt = ttydriv(c,&ttybuf);
			if (cnt == 0) {		/* should be != 0 */
				ttyflow = 0;	/* stop output to screen */
			} else {
				ttyflow = 1;	/* restart output */
				if(mode != CMD_MODE)
					go();	/* display pending chars */
			}
			if (cnt == 0)
				continue;
#endif FLOW
/* ------------------------------------------------------------------ */
			switch(mode){
			case CMD_MODE:
				(void)cmdparse(cmds,ttybuf);
				fflush(stdout);
				break;
			case CONV_MODE:
#if	(!MSDOS && !ATARI_ST)
				if(ttybuf[0] == escape && escape != 0){
					printf("\n");
					cmdmode();
				} else
#endif
					if(current->parse != NULLFP)
						(*current->parse)(ttybuf,cnt);

				break;
			}
			if(mode == CMD_MODE){
				printf(prompt);
				fflush(stdout);
			}
		}
		keep_things_going();
	}
}
/* Standard commands called from main */

/* Enter command mode */
int
cmdmode()
{
	if(mode != CMD_MODE){
		mode = CMD_MODE;
		cooked();
		printf(prompt);
		fflush(stdout);
		echo();
	}
	return 0;
}
static
doexit()
{
	if(logfp != NULLFILE)
		fclose(logfp);
	iostop();
	exit(0);
}
static
dohostname(argc,argv)
int argc;
char *argv[];
{
	char *strncpy();

	if(argc < 2)
		printf("%s\n",hostname);
	else 
		strncpy(hostname,argv[1],HOSTNAMELEN);
	return 0;
}
static
int
dolog(argc,argv)
int argc;
char *argv[];
{
	char *strncpy();

	static char logname[15];
	if(argc < 2){
		if(logfp)
			printf("Logging to %s\n",logname);
		else
			printf("Logging off\n");
		return 0;
	}
	if(logfp){
		fclose(logfp);
		logfp = NULLFILE;
	}
	if(strcmp(argv[1],"stop") != 0){
		strncpy(logname,argv[1],15);
		logfp = fopen(logname,"a+");
	}
	return 0;
}
static
int
dohelp()
{
	register struct cmds *cmdp;
	int i,j;

	printf("Main commands:\n");
	for(i=0,cmdp = cmds;cmdp->name != NULL;cmdp++,i++){
		printf("%s",cmdp->name);
		if((i % 4) == 3)
			printf("\n");
		else {
			for(j=strlen(cmdp->name);j < 16; j++)
				putchar(' ');
		}
	}
	if((i % 4) != 0)
		printf("\n");
	return 0;
}

doecho(argc,argv)
int argc;
char *argv[];
{
	extern int refuse_echo;

	if(argc < 2){
		if(refuse_echo)
			printf("Refuse\n");
		else
			printf("Accept\n");
	} else {
		if(argv[1][0] == 'r')
			refuse_echo = 1;
		else if(argv[1][0] == 'a')
			refuse_echo = 0;
		else
			return -1;
	}
	return 0;
}
/* set for unix end of line for remote echo mode telnet */
doeol(argc,argv)
int argc;
char *argv[];
{
	extern int unix_line_mode;

	if(argc < 2){
		if(unix_line_mode)
			printf("Unix\n");
		else
			printf("Standard\n");
	} else {
		if(strcmp(argv[1],"unix") == 0)
			unix_line_mode = 1;
		else if(strcmp(argv[1],"standard") == 0)
			unix_line_mode = 0;
		else {
			return -1;
		}
	}
	return 0;
}
/* Attach an interface
 * Syntax: attach <hw type> <I/O address> <vector> <mode> <label> <bufsize> [<speed>]
 */
doattach(argc,argv)
int argc;
char *argv[];
{
	extern struct cmds attab[];

	return subcmd(attab,argc,argv);
}
/* Manipulate I/O device parameters */
doparam(argc,argv)
int argc;
char *argv[];
{
	register struct interface *ifp;

	for(ifp=ifaces;ifp != NULLIF;ifp = ifp->next){
		if(strcmp(argv[1],ifp->name) == 0)
			break;
	}
	if(ifp == NULLIF){
		printf("Interface \"%s\" unknown\n",argv[1]);
		return 1;
	}
	if(ifp->ioctl == NULLFP){
		printf("Not supported\n");
		return 1;
	}
	/* Pass rest of args to device-specific code */
	return (*ifp->ioctl)(ifp,argc-2,argv+2);
}

/* -------------------------------------------------------- */
/* Log messages of the form
 * Tue Jan 31 00:00:00 1987 44.64.0.7:1003 open FTP
 */
/*VARARGS2*/
log(tcb,fmt,arg1,arg2,arg3,arg4)
struct tcb *tcb;
char *fmt;
int arg1,arg2,arg3,arg4;
{
	char *cp;
	long t;
	int fd;

	if(logfp == NULLFILE)
		return;
	time(&t);
	cp = ctime(&t);
	rip(cp);
	/* log events which don't have an IP address (AX.25 connects etc) */
	if (tcb != NULLTCB) {
		fprintf(logfp,"%s %s - ",cp,psocket(&tcb->conn.remote));
	} else {
		fprintf(logfp,"%s - ",cp);
	}
	fprintf(logfp,fmt,arg1,arg2,arg3,arg4);
	fprintf(logfp,"\n");
	fflush(logfp);
#if ( MSDOS || ATARI_ST )
	/* MS-DOS doesn't really flush files until they're closed */
	fd = fileno(logfp);
	if((fd = dup(fd)) != -1)
		close(fd);
#endif
}
/* ------------------------------------------------------------------ */

/* Configuration-dependent code */

/* List of supported hardware devices */
int ec_attach(),asy_attach(),pc_attach(),eg_attach(),hapn_attach(),at_attach(),
	nr_attach();

struct cmds attab[] = {
#ifdef	PC_EC
	/* 3-Com Ethernet interface */
	"3c500", ec_attach, 7, 
	"attach 3c500 <address> <vector> arpa <label> <buffers> <mtu>",
	"Could not attach 3c500",
#endif
#ifdef	SLIP
	/* Ordinary PC asynchronous adaptor */
	"asy", asy_attach, 8, 
#ifndef	SLFP
	"attach asy <address> <vector> slip|ax25 <label> <buffers> <mtu> <speed>",
#else
	"attach asy <address> <vector> slip|ax25|slfp <label> <buffers> <mtu> <speed>",
#endif
	"Could not attach asy",
#endif
#ifdef	PC100
	/* PACCOMM PC-100 8530 HDLC adaptor */
	"pc100", pc_attach, 8, 
	"attach pc100 <address> <vector> ax25 <label> <buffers> <mtu> <speed>",
	"Could not attach pc100",
#endif
#ifdef	EAGLE
	/* EAGLE RS-232C 8530 HDLC adaptor */
	"eagle", eg_attach, 8,
	"attach eagle <address> <vector> ax25 <label> <buffers> <mtu> <speed>",
	"Could not attach eagle",
#endif
#ifdef	HAPN
	/* Hamilton Area Packet Radio (HAPN) 8273 HDLC adaptor */
	"hapn", hapn_attach, 8,
	"attach hapn <address> <vector> ax25 <label> <rx bufsize> <mtu> csma|full",
	"Could not attach hapn",
#endif
#ifdef	APPLETALK
	/* Macintosh AppleTalk */
	"0", at_attach, 7,
	"attach 0 <protocol type> <device> arpa <label> <rx bufsize> <mtu>",
	"Could not attach Appletalk",
#endif
#ifdef AX25
	/* Fake NET/ROM interface */
	"netrom", nr_attach, 1,
	"attach netrom",
	"Could not attach netrom",
#endif
	NULLCHAR, NULLFP, 0,
	"Unknown device",
	NULLCHAR,
};

/* Protocol tracing function pointers */
#ifdef	TRACE
int ax25_dump(),ether_dump(),ip_dump(),at_dump(),slfp_dump();

int (*tracef[])() = {
#ifdef	AX25
	ax25_dump,
#else
	NULLFP,
#endif

#ifdef	ETHER
	ether_dump,
#else
	NULLFP,
#endif
	ip_dump,

#ifdef	APPLETALK
	at_dump,
#else
	NULLFP,
#endif

#ifdef	SLFP
	slfp_dump,
#else
	NULLFP,
#endif
};
#else
int (*tracef[])() = { NULLFP }; /* No tracing at all */
dump(interface,direction,type,bp)
struct interface *interface;
int direction;
unsigned type;
struct mbuf *bp;
{
}
#endif

#ifdef	AX25
/* Set up a SLIP link to use AX.25 */
kiss_attach(if_asy,srecv)
struct interface *if_asy;
int (**srecv)();
{
	int kiss_ioctl(),ax_send(),ax_output(),kiss_raw(),kiss_recv();

	axarp();
	if(mycall.call[0] == '\0'){
		printf("set mycall first\n");
		free((char *)if_asy);
		return -1;
	}
	if_asy->ioctl = kiss_ioctl;
	if_asy->send = ax_send;
	if_asy->output = ax_output;
	if_asy->raw = kiss_raw;
	if(if_asy->hwaddr == NULLCHAR)
		if_asy->hwaddr = malloc(sizeof(mycall));
	memcpy(if_asy->hwaddr,(char *)&mycall,sizeof(mycall));
	*srecv = kiss_recv;
	return 0;
}



/* Set up a net/rom serial interface */
nrs_attach(if_asy,call)
struct interface *if_asy;
char *call ;
{
	struct ax25_addr addr ;
	int ax_send(),ax_output(),nrs_raw(),nrs_recv(),asy_ioctl();

	if (call == NULLCHAR) {				/* no call supplied? */
		if(mycall.call[0] == '\0'){		/* try to use default */
			printf("set mycall first or specify in attach statement\n");
			return -1;
		}
		else
			addr = mycall ;
	}
	else {				/* callsign supplied on attach line */
		if (setcall(&addr,call) == -1) {
			printf ("bad callsign on attach line\n") ;
			return -1 ;
		}
	}

	if_asy->flags |= CONNECT_MODE;		/* DG2KK: was: IF_AX25 */
	if_asy->recv = nrs_recv ;
	if_asy->ioctl = asy_ioctl ;
	if_asy->send = ax_send;
	if_asy->output = ax_output;
	if_asy->raw = nrs_raw;
	if(if_asy->hwaddr == NULLCHAR)
		if_asy->hwaddr = malloc(sizeof(addr));
	memcpy(if_asy->hwaddr,(char *)&addr,sizeof(addr));
	return 0;
}


/* Display or set IP interface control flags */
domode(argc,argv)
int argc;
char *argv[];
{
	register struct interface *ifp;

	for(ifp=ifaces;ifp != NULLIF;ifp = ifp->next){
		if(strcmp(argv[1],ifp->name) == 0)
			break;
	}
	if(ifp == NULLIF){
		printf("Interface \"%s\" unknown\n",argv[1]);
		return 1;
	}
	if(argc < 3){
		printf("%s: %s\n",ifp->name,
		 (ifp->flags & CONNECT_MODE) ? "VC mode" : "Datagram mode");
		return 0;
	}
	switch(argv[2][0]){
	case 'v':
	case 'c':
	case 'V':
	case 'C':
		ifp->flags = CONNECT_MODE;
		break;
	case 'd':
	case 'D':
		ifp->flags = DATAGRAM_MODE;
		break;
	default:
		printf("Usage: %s [vc | datagram]\n",argv[0]);
		return 1;
	}
	return 0;
}
#endif

#ifdef SERVERS
dostart(argc,argv)
int argc;
char *argv[];
{
	return subcmd(startcmds,argc,argv);
}
dostop(argc,argv)
int argc;
char *argv[];
{
	return subcmd(stopcmds,argc,argv);
}
#endif SERVERS

#ifdef	TRACE
static
int
dotrace(argc,argv)
int argc;
char *argv[];
{
	struct interface *ifp;

	if(argc < 2){
		showtrace(&loopback);
		for(ifp = ifaces; ifp != NULLIF; ifp = ifp->next)
			showtrace(ifp);
		return 0;
	}
	if(strcmp("loopback",argv[1]) == 0)
		ifp = &loopback;
	else 
		for(ifp = ifaces; ifp != NULLIF; ifp = ifp->next)
			if(strcmp(ifp->name,argv[1]) == 0)
				break;

	if(ifp == NULLIF){
		printf("Interface %s unknown\n",argv[1]);
		return 1;
	}
	if(argc >= 3)
		ifp->trace = htoi(argv[2]);

	showtrace(ifp);
	return 0;
}
/* Display the trace flags for a particular interface */
static
showtrace(ifp)
register struct interface *ifp;
{
	if(ifp == NULLIF)
		return;
	printf("%s:",ifp->name);
	if(ifp->trace & (IF_TRACE_IN | IF_TRACE_OUT)){
		if(ifp->trace & IF_TRACE_IN)
			printf(" input");
		if(ifp->trace & IF_TRACE_OUT)
			printf(" output");

		if(ifp->trace & IF_TRACE_HEX)
			printf(" (Hex/ASCII dump)");
		else if(ifp->trace & IF_TRACE_ASCII)
			printf(" (ASCII dump)");
		else
			printf(" (headers only)");
		printf("\n");
	} else
		printf(" tracing off\n");
	fflush(stdout);
}
#endif

#if	(!MSDOS && !ATARI_ST)
static
int
doescape(argc,argv)
int argc;
char *argv[];
{
	if(argc < 2)
		printf("0x%x\n",escape);
	else 
		escape = *argv[1];
	return 0;
}
#endif

static
doremote(argc,argv)
int argc;
char *argv[];
{
	struct socket fsock,lsock;
	struct mbuf *bp;

	lsock.address = ip_addr;
	fsock.address = resolve(argv[1]);
	lsock.port = fsock.port = atoi(argv[2]);
	bp = alloc_mbuf(1);
	if(strcmp(argv[3],"reset") == 0){
		*bp->data = SYS_RESET;
	} else if(strcmp(argv[3],"exit") == 0){
		*bp->data = SYS_EXIT;
	} else {
		printf("Unknown command %s\n",argv[3]);
		return 1;
	}
	bp->cnt = 1;
	send_udp(&lsock,&fsock,0,0,bp,0,0,0);
	return 0;
}
