6 int ctl = -1; /* control fd (for break's) */
7 int consctl = -1; /* consctl fd */
9 int ttypid; /* pid's if the 2 processes (used to kill them) */
17 typedef struct Comm Comm;
27 int menu(Biobuf*, int);
28 void notifyf(void*, char*);
32 char* system(int, char*);
33 int echochange(Biobuf*, int);
34 int termsub(Biobuf*, uchar*, int);
35 int xlocsub(Biobuf*, uchar*, int);
38 static int islikeatty(int);
43 fatal("usage: telnet [-Cdnr] [-s srv] net!host[!service]", 0, 0);
47 main(int argc, char *argv[])
75 /* options we need routines for */
76 opt[Echo].change = echochange;
77 opt[Term].sub = termsub;
78 opt[Xloc].sub = xlocsub;
80 comm = share(sizeof(comm));
81 comm->returns = returns;
83 telnet(dodial(argv[0]));
87 * dial and return a data connection
94 char devdir[NETPATHLEN];
96 name = netmkaddr(dest, "tcp", "telnet");
97 data = dial(name, 0, devdir, 0);
99 fatal("%s: %r", name, 0);
100 fprint(2, "connected to %s on %s\n", name, devdir);
105 post(char *srv, int fd)
110 f = create(srv, OWRITE, 0666);
112 sysfatal("create %s: %r", srv);
113 snprint(buf, sizeof buf, "%d", fd);
114 if(write(f, buf, strlen(buf)) != strlen(buf))
115 sysfatal("write %s: %r", srv);
120 * two processes pass bytes back and forth between the
121 * terminal and the network.
134 sysfatal("pipe: %r");
136 svc = smprint("/srv/%s", srv);
143 /* pipe is now std in & out */
146 switch(pid = rfork(RFPROC|RFFDG|RFMEM)){
156 sendnote(ttypid, "die");
167 sendnote(netpid, "die");
173 * Read the keyboard and write it to the network. '^\' gets us into
183 Binit(&ib, 0, OREAD);
184 Binit(&ob, net, OWRITE);
186 likeatty = islikeatty(0);
192 * with raw off, all ^D's get turned into Eof's.
194 * 10 in a row implies that the terminal is really gone so
207 * if not in binary mode, look for the ^\ escape to menu.
208 * also turn \n into \r\n
210 if(likeatty || !opt[Binary].local){
211 if(c == 0034){ /* CTRL \ */
214 if(menu(&ib, net) < 0)
219 if(!opt[Binary].local){
222 * This is a very strange use of the SGA option.
223 * I did this because some systems that don't
224 * announce a willingness to supress-go-ahead
225 * need the \r\n sequence to recognize input.
226 * If someone can explain this to me, please
227 * send me mail. - presotto
232 if(Bputc(&ob, '\r') < 0)
237 if(Bputc(&ob, c) < 0)
239 if(Bbuffered(&ib) == 0)
246 * Read from the network and write to the screen. If 'stopped' is set
247 * spin and don't read. Filter out spurious carriage returns.
253 int crnls = 0, freenl = 0, eofs;
256 Binit(&ib, net, OREAD);
257 Binit(&ob, 1, OWRITE);
260 if(Bbuffered(&ib) == 0)
264 send2(net, Iac, Interrupt);
274 case '\n': /* skip nl after string of cr's */
275 if(!opt[Binary].local && !comm->returns){
283 case '\r': /* first cr becomes nl, remainder dropped */
284 if(!opt[Binary].local && !comm->returns){
293 case 0: /* remove nulls from crnl string */
306 if(control(&ib, c) < 0)
315 if(Bputc(&ob, c) < 0)
321 * turn keyboard raw mode on
327 fprint(2, "rawon\n");
329 consctl = open("/dev/consctl", OWRITE);
331 fprint(2, "can't open consctl: %r\n");
334 write(consctl, "rawon", 5);
338 * turn keyboard raw mode off
344 fprint(2, "rawoff\n");
346 consctl = open("/dev/consctl", OWRITE);
348 fprint(2, "can't open consctl: %r\n");
351 write(consctl, "rawoff", 6);
357 #define STDHELP "\t(b)reak, (i)nterrupt, (q)uit, (r)eturns, (!cmd), (.)continue\n"
360 menu(Biobuf *bp, int net)
369 for(done = 0; !done; ){
370 cp = Brdline(bp, '\n');
375 cp[Blinelen(bp)-1] = 0;
378 system(Bfildes(bp), cp+1);
390 send3(net, Iac, Do, atoi(cp+2));
393 send3(net, Iac, Will, atoi(cp+2));
398 comm->returns = !comm->returns;
402 send2(net, Iac, Interrupt);
405 send2(net, Iac, Break);
424 notifyf(void *a, char *msg)
427 if(strcmp(msg, "interrupt") == 0){
431 if(strcmp(msg, "hangup") == 0)
437 * run a command with the network connection as standard IO
440 system(int fd, char *cmd)
446 if((pid = fork()) == -1){
448 return "fork failed";
455 execl("/bin/rc", "rc", "-c", cmd, nil);
457 execl("/bin/rc", "rc", nil);
461 for(p = waitpid(); p >= 0; p = waitpid()){
469 * suppress local echo if the remote side is doing it
472 echochange(Biobuf *bp, int cmd)
488 * send terminal type to the other side
491 termsub(Biobuf *bp, uchar *sub, int n)
502 *p++ = opt[Term].code;
504 term = getenv("TERM");
505 if(term == 0 || *term == 0)
507 strncpy(p, term, sizeof(buf) - (p - buf) - 2);
508 buf[sizeof(buf)-2] = 0;
512 return iwrite(Bfildes(bp), buf, p-buf);
518 * send an x display location to the other side
521 xlocsub(Biobuf *bp, uchar *sub, int n)
532 *p++ = opt[Xloc].code;
534 term = getenv("XDISP");
535 if(term == 0 || *term == 0)
537 strncpy(p, term, p - buf - 2);
541 return iwrite(Bfildes(bp), buf, p-buf);
551 if(fd2path(fd, buf, sizeof buf) != 0)
554 /* might be /mnt/term/dev/cons */
555 return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
559 * create a shared segment. Make is start 2 meg higher than the current
560 * end of process memory.
568 if(vastart == (void*)-1)
570 vastart += 2*1024*1024;
572 if(segattach(0, "shared", vastart, len) == (void*)-1)