Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

typedef struct Opt      Opt;

int debug;
#define DPRINT if(debug)fprint

enum
{
        /* control characters */
        Se=             240,            /* end subnegotiation */
        NOP=            241,
        Mark=           242,            /* data mark */
        Break=          243,
        Interrupt=      244,
        Abort=          245,            /* TENEX ^O */
        AreYouThere=    246,
        Erasechar=      247,            /* erase last character */
        Eraseline=      248,            /* erase line */
        GoAhead=        249,            /* half duplex clear to send */
        Sb=             250,            /* start subnegotiation */
        Will=           251,
        Wont=           252,
        Do=             253,
        Dont=           254,
        Iac=            255,

        /* options */
        Binary=         0,
        Echo,
        SGA,
        Stat,
        Timing,
        Det,
        Term,
        EOR,
        Uid,
        Outmark,
        Ttyloc,
        M3270,
        Padx3,
        Window,
        Speed,
        Flow,
        Line,
        Xloc,
        Extend,
};

struct Opt
{
        char    *name;
        int     code;
        char    noway;  
        int     (*change)(Biobuf*, int);        /* routine for status change */
        int     (*sub)(Biobuf*, uchar*, int n); /* routine for subnegotiation */
        char    remote;                         /* remote value */
        char    local;                          /* local value */
};

Opt opt[] =
{
[Binary]        { "binary",             0,  0, },
[Echo]          { "echo",               1,  0, },
[SGA]           { "suppress Go Ahead",  3,  0, },
[Stat]          { "status",             5,  1, },
[Timing]        { "timing",             6,  1, },
[Det]           { "det",                20, 1, },
[Term]          { "terminal",           24, 0, },
[EOR]           { "end of record",      25, 1, },
[Uid]           { "uid",                26, 1, },
[Outmark]       { "outmark",            27, 1, },
[Ttyloc]        { "ttyloc",             28, 1, },
[M3270]         { "3270 mode",          29, 1, },
[Padx3]         { "pad x.3",            30, 1, },
[Window]        { "window size",        31, 1, },
[Speed]         { "speed",              32, 1, },
[Flow]          { "flow control",       33, 1, },
[Line]          { "line mode",          34, 1, },
[Xloc]          { "X display loc",      35, 0, },
[Extend]        { "Extended",           255, 1, },
};

int     control(Biobuf*, int);
Opt*    findopt(int);
int     will(Biobuf*);
int     wont(Biobuf*);
int     doit(Biobuf*);
int     dont(Biobuf*);
int     sub(Biobuf*);
int     send2(int, int, int);
int     send3(int, int, int, int);
int     sendnote(int, char*);
void    fatal(char*, void*, void*);
char*   syserr(void);
int     wasintr(void);
long    iread(int, void*, int);
long    iwrite(int, void*, int);
void    binit(Biobuf*, int);
void    berase(Biobuf*);
void    bkill(Biobuf*);

/*
 *  parse telnet control messages
 */
int
control(Biobuf *bp, int c)
{
        if(c < 0)
                return -1;
        switch(c){
        case AreYouThere:
                fprint(Bfildes(bp), "Plan 9 telnet, version 1\r\n");
                break;
        case Sb:
                return sub(bp);
        case Will:
                return will(bp);
        case Wont:
                return wont(bp);
        case Do:
                return doit(bp);
        case Dont:
                return dont(bp);
        case Se:
                fprint(2, "telnet: SE without an SB\n");
                break;
        default:
                break;
        }
        return 0;
}

Opt*
findopt(int c)
{
        Opt *o;

        for(o = opt; o <= &opt[Extend]; o++)
                if(o->code == c)
                        return o;
        return 0;
}

int
will(Biobuf *bp)
{
        Opt *o;
        int c;
        int rv = 0;

        c = Bgetc(bp);
        if(c < 0)
                return -1;
        DPRINT(2, "will %d\n", c);
        o = findopt(c);
        if(o == 0){
                send3(Bfildes(bp), Iac, Dont, c);
                return 0;
        }
        if(o->noway)
                send3(Bfildes(bp), Iac, Dont, c);
        else if(o->remote == 0)
                rv |= send3(Bfildes(bp), Iac, Do, c);
        if(o->remote == 0){
                if(o->change)
                        rv |= (*o->change)(bp, Will);
        }
        o->remote = 1;
        return rv;
}

int
wont(Biobuf *bp)
{
        Opt *o;
        int c;
        int rv = 0;

        c = Bgetc(bp);
        if(c < 0)
                return -1;
        DPRINT(2, "wont %d\n", c);
        o = findopt(c);
        if(o == 0)
                return 0;
        if(o->remote){
                if(o->change)
                        rv |= (*o->change)(bp, Wont);
                rv |= send3(Bfildes(bp), Iac, Dont, c);
        }
        o->remote = 0;
        return rv;
}

int
doit(Biobuf *bp)
{
        Opt *o;
        int c;
        int rv = 0;

        c = Bgetc(bp);
        if(c < 0)
                return -1;
        DPRINT(2, "do %d\n", c);
        o = findopt(c);
        if(o == 0 || o->noway){
                send3(Bfildes(bp), Iac, Wont, c);
                return 0;
        }
        if(o->noway)
                return 0;
        if(o->local == 0){
                if(o->change)
                        rv |= (*o->change)(bp, Do);
                rv |= send3(Bfildes(bp), Iac, Will, c);
        }
        o->local = 1;
        return rv;
}

int
dont(Biobuf *bp)
{
        Opt *o;
        int c;
        int rv = 0;

        c = Bgetc(bp);
        if(c < 0)
                return -1;
        DPRINT(2, "dont %d\n", c);
        o = findopt(c);
        if(o == 0)
                return 0;
        if(o->noway)
                return 0;
        if(o->local){
                o->local = 0;
                if(o->change)
                        rv |= (*o->change)(bp, Dont);
                rv |= send3(Bfildes(bp), Iac, Wont, c);
        }
        o->local = 0;
        return rv;
}

/* read in a subnegotiation message and pass it to a routine for that option */
int
sub(Biobuf *bp)
{
        uchar subneg[128];
        uchar *p;
        Opt *o;
        int c;

        p = subneg;
        for(;;){
                c = Bgetc(bp);
                if(c == Iac){
                        c = Bgetc(bp);
                        if(c == Se)
                                break;
                        if(p < &subneg[sizeof(subneg)])
                                *p++ = Iac;
                }
                if(c < 0)
                        return -1;
                if(p < &subneg[sizeof(subneg)])
                        *p++ = c;
        }
        if(p == subneg)
                return 0;
        DPRINT(2, "sub %d %d n = %d\n", subneg[0], subneg[1], (int)(p - subneg - 1));
        o = findopt(subneg[0]);
        if(o == 0 || o->sub == 0)
                return 0;
        return (*o->sub)(bp, subneg+1, p - subneg - 1);
}

void
sendd(int c0, int c1)
{
        char *t = 0;

        switch(c0){
        case Will:
                t = "Will";
                break;
        case Wont:
                t = "Wont";
                break;
        case Do:
                t = "Do";
                break;
        case Dont:
                t = "Dont";
                break;
        }
        if(t)
                DPRINT(2, "r %s %d\n", t, c1);
}

int
send2(int f, int c0, int c1)
{
        uchar buf[2];

        buf[0] = c0;
        buf[1] = c1;
        return iwrite(f, buf, 2) == 2 ? 0 : -1;
}

int
send3(int f, int c0, int c1, int c2)
{
        uchar buf[3];

        buf[0] = c0;
        buf[1] = c1;
        buf[2] = c2;
        sendd(c1, c2);
        return iwrite(f, buf, 3) == 3 ? 0 : -1;
}

int
sendnote(int pid, char *msg)
{
        int fd;
        char name[128];

        sprint(name, "/proc/%d/note", pid);
        fd = open(name, OWRITE);
        if(fd < 0)
                return -1;
        if(write(fd, msg, strlen(msg))!=strlen(msg))
                return -1;
        return close(fd);
}

void
fatal(char *fmt, void *a0, void *a1)
{
        char buf[128];

        sprint(buf, fmt, a0, a1);
        fprint(2, "%s: %s\n", argv0, buf);
        exits(buf);
}

char*
syserr(void)
{
        static char err[ERRMAX];

        errstr(err, sizeof err);
        return err;
}

int
wasintr(void)
{
        return strcmp(syserr(), "interrupted") == 0;
}

long
iread(int f, void *a, int n)
{
        long m;

        for(;;){
                m = read(f, a, n);
                if(m >= 0 || !wasintr())
                        break;
        }
        return m;
}

long
iwrite(int f, void *a, int n)
{
        long m;

        m = write(f, a, n);
        if(m < 0 && wasintr())
                return n;
        return m;
}