/* Miscellaneous Internet servers: discard, echo and remote
 * Copyright 1991 Phil Karn, KA9Q
 */
#include "global.h"
#include "netuser.h"
#include "mbuf.h"
#include "socket.h"
#include "proc.h"
#include "remote.h"
#include "smtp.h"
#include "iface.h"
#include "tcp.h"
#include "nr4.h"
#include "commands.h"
#include "hardware.h"
#include "mailbox.h"
#include "cmdparse.h"

#ifdef TRACESERVER
static void traceserv __ARGS((int s,void *unused,void *p));
extern struct cmds DFAR Cmds[];

/* Start up TCP trace server */
int
trace1(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int16 port;

    if(argc < 2)
        port = IPPORT_TRACE;
    else
        port = atoi(argv[1]);
    return start_tcp(port,"Trace Server",traceserv,576);
}

/* Stop trace server */
int
trace0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int16 port;

    if(argc < 2)
        port = IPPORT_TRACE;
    else
        port = atoi(argv[1]);
    return stop_tcp(port);
}

static void
traceserv(s,unused,p)
int s;
void *unused;
void *p;
{
    struct mbuf *bp;
    int len;
#define CMDLINE 80    
    char *cmd;
    
    sockowner(s,Curproc);
    log(s,"open trace");
    
    /* allocate the command buffer */
    cmd = mallocw(CMDLINE+1);
    
    while((len=recvline(s,cmd,CMDLINE)) > 0) {
        if(!strnicmp("trace",cmd, 5))    /* only allow 'trace ...' command ! */
            cmdparse(Cmds,cmd,NULL);
    }
    removetrace();
    log(s,"close trace");
    close_s(s);
}
#endif /* TRACESERVER */

#ifdef DISCARDSERVER
static void discserv __ARGS((int s,void *unused,void *p));

/* Start up TCP discard server */
int
dis1(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int16 port;

    if(argc < 2)
        port = IPPORT_DISCARD;
    else
        port = atoi(argv[1]);
    return start_tcp(port,"Discard Server",discserv,576);
}

/* Stop discard server */
int
dis0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int16 port;

    if(argc < 2)
        port = IPPORT_DISCARD;
    else
        port = atoi(argv[1]);
    return stop_tcp(port);
}

static void
discserv(s,unused,p)
int s;
void *unused;
void *p;
{
    struct mbuf *bp;

    sockowner(s,Curproc);
    log(s,"open discard");
    while(recv_mbuf(s,&bp,0,NULLCHAR,NULL) > 0)
        free_p(bp);
    log(s,"close discard");
    close_s(s);
}
#endif /* DISCARDSERVER */

#ifdef ECHOSERVER
static void echoserv __ARGS((int s,void *unused,void *p));

/* Start up TCP echo server */
int
echo1(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int16 port;

    if(argc < 2)
        port = IPPORT_ECHO;
    else
        port = atoi(argv[1]);
    return start_tcp(port,"Echo Server",echoserv,2048);
}

/* stop echo server */
int
echo0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int16 port;

    if(argc < 2)
        port = IPPORT_ECHO;
    else
        port = atoi(argv[1]);
    return stop_tcp(port);
}

static void
echoserv(s,unused,p)
int s;
void *unused;
void *p;
{
    struct mbuf *bp;

    sockowner(s,Curproc);
    log(s,"open echo");
    while(recv_mbuf(s,&bp,0,NULLCHAR,NULL) > 0)
        send_mbuf(s,bp,0,NULLCHAR,0);

    log(s,"close echo");
    close_s(s);
}
#endif /* ECHOSERVER */

#ifdef REMOTESERVER
char *Rempass = ""; /* Remote access password */

extern void where_outta_here(int resetme, int retcode);
static int chkrpass __ARGS((struct mbuf *bp));

static int Rem = -1;

/* Start remote exit/reboot server */
int
rem1(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    struct sockaddr_in lsocket,fsock;
    int i;
    int command;
    struct mbuf *bp;
    int32 addr;
    char temp[20];

    if(Rem != -1){
        return 0;
    }
    psignal(Curproc,0);
    chname(Curproc,"Remote listener");
    lsocket.sin_family = AF_INET;
    lsocket.sin_addr.s_addr = INADDR_ANY;
    if(argc < 2)
        lsocket.sin_port = IPPORT_REMOTE;
    else
        lsocket.sin_port = atoi(argv[1]);

    Rem = socket(AF_INET,SOCK_DGRAM,0);
    bind(Rem,(char *)&lsocket,sizeof(lsocket));
    for(;;){
        i = sizeof(fsock);
        if(recv_mbuf(Rem,&bp,0,(char *)&fsock,&i) == -1)
            break;
        command = PULLCHAR(&bp);

        switch(command){
#ifdef  MSDOS   /* Only present on PCs running MSDOS */
            case SYS_RESET:
                i = chkrpass(bp);
                log(Rem,"Remote reset %s %s",
                psocket((struct sockaddr *)&fsock),
                i == 0 ? "PASSWORD FAIL" : "" );
                if(i != 0){
                /*Indicate a hardware reset*/
                    where_outta_here(1,0);
                }
                break;
#endif
            case SYS_EXIT:
                i = chkrpass(bp);
                log(Rem,"Remote exit %s %s",
                psocket((struct sockaddr *)&fsock),
                i == 0 ? "PASSWORD FAIL" : "" );
                if(i != 0){
                /*No reset*/
                    where_outta_here(0,100);
                }
                break;
            case KICK_ME:
                if(len_p(bp) >= sizeof(int32))
                    addr = pull32(&bp);
                else
                    addr = fsock.sin_addr.s_addr;

            /* get round strange printf bug */
                strcpy(temp, inet_ntoa(addr));

                log(Rem,"Remote kick by %s for host %s",
                psocket((struct sockaddr *)&fsock), temp);
#ifdef NETROM
                donodetick();       /* g3rra's idea!..hmmm */
#endif /* NETROM */
                kick(addr);
                smtptick((void *)addr);
                break;
        }
        free_p(bp);
    }
    close_s(Rem);
    Rem = -1;
    return 0;
}
/* Check remote password */
static int
chkrpass(bp)
struct mbuf *bp;
{
    char *lbuf;
    int16 len;
    int rval = 0;

    len = len_p(bp);

    if(strlen(Rempass) != len)
        return rval;
    lbuf = mallocw(len);
    pullup(&bp,lbuf,len);
    if(strncmp(Rempass,lbuf,len) == 0)
        rval = 1;
    free(lbuf);
    return rval;
}
int
rem0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    close_s(Rem);
    return 0;
}
#endif /* REMOTESERVER */

#ifdef RSYSOPSERVER
static void
rsysopserver(s,o,p)
int s;
void *o;
void *p;
{
        mbx_incom (s, (void *)RSYSOP_LINK, p);
}

/* Start up RSYSOP server */
int
rsysop1(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int16 port;

    if(argc < 2)
       port = IPPORT_RSYSOP;
    else
       port = atoi(argv[1]);

    return start_tcp(port,"RSYSOP Server",rsysopserver,2048);
}

/* Stop RSYSOP server */
int
rsysop0(argc,argv,p)
int argc;
char *argv[];
void *p;
{
    int16 port;

    if(argc < 2)
       port = IPPORT_RSYSOP;
    else
       port = atoi(argv[1]);
    return stop_tcp(port);
}
#endif
