summaryrefslogtreecommitdiff
path: root/sys/src/cmd/ip/telnet.h
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/cmd/ip/telnet.h387
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;
+}