diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/ip/telnet.h |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/ip/telnet.h')
-rwxr-xr-x | sys/src/cmd/ip/telnet.h | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/sys/src/cmd/ip/telnet.h b/sys/src/cmd/ip/telnet.h new file mode 100755 index 000000000..ddc5b5d90 --- /dev/null +++ b/sys/src/cmd/ip/telnet.h @@ -0,0 +1,387 @@ +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; +} |