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) */
22 int menu(Biobuf*, int);
23 void notifyf(void*, char*);
27 char* system(int, char*);
28 int echochange(Biobuf*, int);
29 int termsub(Biobuf*, uchar*, int);
30 int xlocsub(Biobuf*, uchar*, int);
32 static int islikeatty(int);
37 fatal("usage: telnet [-Cdnr] [-s srv] net!host[!service]", 0, 0);
41 main(int argc, char *argv[])
67 /* options we need routines for */
68 opt[Echo].change = echochange;
69 opt[Term].sub = termsub;
70 opt[Xloc].sub = xlocsub;
72 telnet(dodial(argv[0]));
76 * dial and return a data connection
83 char devdir[NETPATHLEN];
85 name = netmkaddr(dest, "tcp", "telnet");
86 data = dial(name, 0, devdir, 0);
88 fatal("%s: %r", name, 0);
90 if(rfork(RFPROC | RFNOWAIT | RFNOTEG) != 0)
94 fprint(2, "connected to %s on %s\n", name, devdir);
99 post(char *srv, int fd)
104 f = create(srv, OWRITE, 0666);
106 sysfatal("create %s: %r", srv);
107 snprint(buf, sizeof buf, "%d", fd);
108 if(write(f, buf, strlen(buf)) != strlen(buf))
109 sysfatal("write %s: %r", srv);
114 * two processes pass bytes back and forth between the
115 * terminal and the network.
128 sysfatal("pipe: %r");
130 svc = smprint("/srv/%s", srv);
137 /* pipe is now std in & out */
140 switch(pid = rfork(RFPROC|RFFDG|RFMEM)){
150 sendnote(ttypid, "die");
157 while(waitpid() != pid)
161 sendnote(netpid, "die");
167 * Read the keyboard and write it to the network. '^\' gets us into
177 Binit(&ib, 0, OREAD);
178 Binit(&ob, net, OWRITE);
180 likeatty = islikeatty(0);
186 * with raw off, all ^D's get turned into Eof's.
188 * 10 in a row implies that the terminal is really gone so
201 * if not in binary mode, look for the ^\ escape to menu.
202 * also turn \n into \r\n
204 if(likeatty || !opt[Binary].local){
205 if(c == 0034){ /* CTRL \ */
208 if(menu(&ib, net) < 0)
213 if(!opt[Binary].local){
216 * This is a very strange use of the SGA option.
217 * I did this because some systems that don't
218 * announce a willingness to supress-go-ahead
219 * need the \r\n sequence to recognize input.
220 * If someone can explain this to me, please
221 * send me mail. - presotto
226 if(Bputc(&ob, '\r') < 0)
231 if(Bputc(&ob, c) < 0)
233 if(Bbuffered(&ib) == 0)
240 * Read from the network and write to the screen. If 'stopped' is set
241 * spin and don't read. Filter out spurious carriage returns.
247 int crnls = 0, freenl = 0, eofs;
250 Binit(&ib, net, OREAD);
251 Binit(&ob, 1, OWRITE);
254 if(Bbuffered(&ib) == 0)
258 send2(net, Iac, Interrupt);
268 case '\n': /* skip nl after string of cr's */
269 if(!opt[Binary].local && !returns){
277 case '\r': /* first cr becomes nl, remainder dropped */
278 if(!opt[Binary].local && !returns){
287 case 0: /* remove nulls from crnl string */
300 if(control(&ib, c) < 0)
309 if(Bputc(&ob, c) < 0)
317 if(srv != nil || notkbd)
320 fprint(2, "consctl: %s\n", s);
322 consctl = open("/dev/consctl", OWRITE);
324 fprint(2, "can't open consctl: %r\n");
327 write(consctl, s, strlen(s));
331 * turn keyboard raw mode on
340 * turn keyboard raw mode off
345 consctlcmd("rawoff");
351 #define STDHELP "\t(b)reak, (i)nterrupt, (q)uit, (r)eturns, (!cmd), (.)continue\n"
354 menu(Biobuf *bp, int net)
363 for(done = 0; !done; ){
364 cp = Brdline(bp, '\n');
369 cp[Blinelen(bp)-1] = 0;
372 system(Bfildes(bp), cp+1);
384 send3(net, Iac, Do, atoi(cp+2));
387 send3(net, Iac, Will, atoi(cp+2));
396 send2(net, Iac, Interrupt);
399 send2(net, Iac, Break);
418 notifyf(void *a, char *msg)
421 if(strcmp(msg, "interrupt") == 0){
425 if(strcmp(msg, "hangup") == 0)
431 * run a command with the network connection as standard IO
434 system(int fd, char *cmd)
440 if((pid = fork()) == -1){
442 return "fork failed";
449 execl("/bin/rc", "rc", "-c", cmd, nil);
451 execl("/bin/rc", "rc", nil);
455 for(p = waitpid(); p >= 0; p = waitpid()){
463 * suppress local echo if the remote side is doing it
466 echochange(Biobuf *bp, int cmd)
482 * send terminal type to the other side
485 termsub(Biobuf *bp, uchar *sub, int n)
496 *p++ = opt[Term].code;
498 term = getenv("TERM");
499 if(term == 0 || *term == 0)
501 strncpy(p, term, sizeof(buf) - (p - buf) - 2);
502 buf[sizeof(buf)-2] = 0;
506 return iwrite(Bfildes(bp), buf, p-buf);
512 * send an x display location to the other side
515 xlocsub(Biobuf *bp, uchar *sub, int n)
526 *p++ = opt[Xloc].code;
528 term = getenv("XDISP");
529 if(term == 0 || *term == 0)
531 strncpy(p, term, p - buf - 2);
535 return iwrite(Bfildes(bp), buf, p-buf);
545 if(fd2path(fd, buf, sizeof buf) != 0)
548 /* might be /mnt/term/dev/cons */
549 return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;