() error
[unix-history] / usr / src / usr.bin / tip / tip.c
CommitLineData
5f50159a
BJ
1/* tip.c 4.1 81/05/09 */
2/*
3 * tip - Unix link to other systems
4 * tip [-v] [-speed] system-name
5 *
6 * Uses remote file for system descriptions.
7 * Current commands (escapes):
8 *
9 * ~! fork a shell on the local machine
10 * ~c change working directory on local machine
11 * ~^D exit tip
12 * ~< fetch file from remote system
13 * ~> send file to remote system
14 * ~t take a file from a remote UNIX (uses cat & echo)
15 * ~p send a file to a remote UNIX (uses cat)
16 * ~| fetch file from remote system and pipe it to
17 * a local process
18 * ~% fork and wait for a program which inherits file
19 * descriptors 3 & 4 attached to the remote machine
20 * (optional by CONNECT define)
21 * ~s set or show variable
22 * ~? give a help summary
23 *
24 * Samuel J. Leffler 1-18-81
25 *
26 * sjl 2-11-81
27 * add auto-dial stuff for the BIZCOMP
28 *
29 * sjl 2-14-81
30 * cleaned up auto-dialer stuff and added variables
31 *
32 * sjl 2-19-81
33 * handle quit and interrupt during calls
34 *
35 * sjl 3-8-81
36 * made to pass lint
37 *
38 * sjl 4-11-81
39 * mods to handle both FIOCAPACITY and FIONREAD in biz.c
40 *
41 * sjl 4-17-81
42 * added take and put, made piping stuff work
43 * honor uucp locks
44 * rewrite remote file stuff for DN-11 like acu's and just to clean
45 * it up
46 */
47
48#include "tip.h"
49
50/*
51 * Baud rate mapping table
52 */
53int bauds[] = {
54 0, 50, 75, 110, 134, 150, 200, 300, 600,
55 1200, 1800, 2400, 4800, 9600, 19200, -1
56};
57
58int intprompt();
59int timeout();
60static int cleanup();
61
62main(argc, argv)
63char *argv[];
64{
65 char *system = NOSTR;
66 register int i;
67#ifdef VMUNIX
68 int disc;
69#endif
70 char *p;
71
72 if (argc > 4) {
73 fprintf(stderr, "usage: tip [-v] [-speed] [system-name]\n");
74 exit(1);
75 }
76 if (!isatty(0)) {
77 fprintf(stderr, "tip: must be interactive\n");
78 exit(1);
79 }
80 if (argc > 1 && argv[argc-1][0] != '-')
81 system = argv[argc-1]; /* always last item */
82 signal(SIGINT, cleanup);
83 signal(SIGQUIT, cleanup);
84 signal(SIGHUP, cleanup);
85 signal(SIGTERM, cleanup);
86 if ((i = hunt(system)) == 0) {
87 printf("all ports busy\n");
88 exit(3);
89 }
90 if (i == -1) {
91 printf("link down\n");
92 exit(3);
93 }
94 loginit();
95 /*
96 * Now that we have the logfile and the ACU open
97 * return to the real uid and gid. These things will
98 * be closed on exit. Note that we can't run as root,
99 * because locking mechanism on the tty and the accounting
100 * will be bypassed.
101 */
102 setuid(getuid());
103 setgid(getgid());
104 for (i = 1; i < argc-1; i++)
105 if (equal(argv[i], "-v"))
106 vflag++;
107 /*
108 * Kludge, their's no easy way to get the initialization
109 * in the right order, so force it here
110 */
111 if ((PH = getenv("PHONES")) == NOSTR)
112 PH = "/etc/phones";
113 vinit(); /* init variables */
114 for (i = 1; i < argc-1; i++)
115 if (argv[i][0] == '-' && argv[i][1] != 'v') {
116 if (isnum(argv[i][1]))
117 number(value(BAUDRATE)) = atoi(&argv[i][1]);
118 else
119 printf("%s: unknown option\n", argv[i]);
120 }
121 if ((arg.sg_ispeed = speed(number(value(BAUDRATE)))) == NULL) {
122 printf("tip: bad baud rate %d\n", number(value(BAUDRATE)));
123 delock(uucplock);
124 exit(3);
125 }
126 arg.sg_ospeed = arg.sg_ispeed;
127 /*
128 * NOTE that remote side runs in TANDEM mode,
129 * if the host doesn't honor X-ON/X-OFF with default
130 * start/stop chars, the remote description must be
131 * extended and tchars will have to be set up here.
132 * If the host doesn't honor TANDEM mode, then watch
133 * out, as you'll get garbage.
134 */
135 arg.sg_flags = RAW | TANDEM;
136 ioctl(FD, TIOCSETP, &arg);
137
138 ioctl(0, TIOCGETP, &defarg); /* store initial status */
139 ioctl(0, TIOCGETC, &defchars);
140 arg = defarg;
141 arg.sg_flags = ANYP | CBREAK;
142 tchars = defchars;
143 tchars.t_intrc = tchars.t_quitc = -1;
144
145 if (p = connect()) {
146 printf("\07%s\n[EOT]\n", p);
147 delock(uucplock);
148 exit(1);
149 }
150 write(1, "\07connected\n", 11);
151 raw();
152#ifdef VMUNIX
153 ioctl(0, TIOCGETD, (char *)&odisc);
154 disc = OTTYDISC;
155 ioctl(0, TIOCSETD, (char *)&disc);
156#endif
157 pipe(fildes); pipe(repdes);
158 signal(SIGALRM, timeout);
159 if (pid = fork())
160 tipin();
161 else
162 tipout();
163 /*NOTREACHED*/
164}
165
166static
167cleanup()
168{
169 delock(uucplock);
170 exit(0);
171}
172
173/*
174 * put the controlling keyboard into raw mode
175 */
176raw()
177{
178 ioctl(0, TIOCSETP, &arg);
179 ioctl(0, TIOCSETC, &tchars);
180}
181
182
183/*
184 * return keyboard to normal mode
185 */
186unraw()
187{
188 ioctl(0, TIOCSETP, &defarg);
189 ioctl(0, TIOCSETC, &defchars);
190}
191
192/*
193 * Print string ``s'', then read a string
194 * in from the terminal. Handles signals & allows use of
195 * normal erase and kill characters.
196 */
197prompt(s, p)
198 char *s;
199 register char *p;
200{
201 register char *b = p;
202
203 stoprompt = 0;
204 signal(SIGINT, intprompt);
205 signal(SIGQUIT, SIG_IGN);
206 unraw();
207 printf("%s", s);
208 while ((*p = getchar()) != EOF && *p != '\n') {
209 if (stoprompt)
210 goto pbreak;
211 p++;
212 }
213 *p = '\0';
214pbreak:
215 raw();
216 signal(SIGINT, SIG_DFL);
217 signal(SIGQUIT,SIG_DFL);
218 return(stoprompt || p == b);
219}
220
221/*
222 * Interrupt service routine during prompting
223 */
224intprompt()
225{
226 signal(SIGINT, SIG_IGN);
227 stoprompt = 1;
228 printf("\r\n");
229}
230
231/*
232 * ****TIPIN TIPIN****
233 */
234tipin()
235{
236 char gch, bol = 1;
237
238 while (1) {
239 gch = getchar()&0177;
240 if ((gch == character(value(ESCAPE))) && bol) {
241 if (!(gch = escape()))
242 continue;
243 } else if (gch == character(value(RAISECHAR))) {
244 boolean(value(RAISE)) = !boolean(value(RAISE));
245 printf("%s", ctrl(character(value(RAISECHAR))));
246 continue;
247 } else if (gch == '\r') {
248 bol = 1;
249 write(FD, &gch, 1);
250 continue;
251 } else if (gch == character(value(FORCE))) {
252 printf("%s", ctrl(character(value(FORCE))));
253 gch = getchar()&0177;
254 }
255 bol = any(gch, value(EOL));
256 if (boolean(value(RAISE)) && islower(gch))
257 toupper(gch);
258 write(FD, &gch, 1);
259 }
260}
261
262/*
263 * Escape handler --
264 * called on recognition of ``escapec'' at the beginning of a line
265 */
266escape()
267{
268 register char gch;
269 register esctable_t *p;
270 char c = character(value(ESCAPE));
271 extern esctable_t etable[];
272
273 gch = (getchar()&0177);
274 for (p = etable; p->e_char; p++)
275 if (p->e_char == gch) {
276 if ((p->e_flags&PRIV) && getuid())
277 continue;
278 printf("%s", ctrl(c));
279 (*p->e_func)(gch);
280 return(0);
281 }
282
283 write(FD, &c, 1);
284 return(gch);
285}
286
287speed(n)
288{
289 register int *p;
290
291 for (p = bauds; *p != -1; p++)
292 if (*p == n)
293 return(p-bauds);
294 return(NULL);
295}
296
297any(c, p)
298 register char c, *p;
299{
300 while (*p)
301 if (*p++ == c)
302 return(1);
303 return(0);
304}
305
306size(s)
307 register char *s;
308{
309 register int i = 0;
310
311 while (*s++) i++;
312 return(i);
313}
314
315char *
316interp(s)
317 register char *s;
318{
319 static char buf[256];
320 register char *p = buf, c, *q;
321
322 while (c = *s++) {
323 for (q = "\nn\rr\tt\ff\033E\bb"; *q; q++)
324 if (*q++ == c) {
325 *p++ = '\\'; *p++ = *q;
326 goto next;
327 }
328 if (c < 040) {
329 *p++ = '^'; *p++ = c + 'A'-1;
330 } else if (c == 0177) {
331 *p++ = '^'; *p++ = '?';
332 } else
333 *p++ = c;
334 next:
335 ;
336 }
337 *p = '\0';
338 return(buf);
339}
340
341char *
342ctrl(c)
343 char c;
344{
345 static char s[3];
346
347 if (c < 040 || c == 0177) {
348 s[0] = '^';
349 s[1] = c == 0177 ? '?' : c+'A'-1;
350 s[2] = '\0';
351 } else {
352 s[0] = c;
353 s[1] = '\0';
354 }
355 return(s);
356}
357
358/*
359 * Help command
360 */
361help(c)
362 char c;
363{
364 register esctable_t *p;
365 extern esctable_t etable[];
366
367 printf("%c\r\n", c);
368 for (p = etable; p->e_char; p++) {
369 if ((p->e_flags&PRIV) && getuid())
370 continue;
371 printf("%2s", ctrl(character(value(ESCAPE))));
372 printf("%-2s %c %s\r\n", ctrl(p->e_char),
373 p->e_flags&EXP ? '*': ' ', p->e_help);
374 }
375}