new copyright notice
[unix-history] / usr / src / usr.bin / ftp / main.c
CommitLineData
edf71f48 1/*
3371ac92 2 * Copyright (c) 1985, 1989 Regents of the University of California.
11c5f0a3
KB
3 * All rights reserved.
4 *
1343342a 5 * %sccs.include.redist.c%
edf71f48
DF
6 */
7
8#ifndef lint
9char copyright[] =
3371ac92 10"@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\
edf71f48 11 All rights reserved.\n";
11c5f0a3 12#endif /* not lint */
edf71f48 13
ba5bf9f5 14#ifndef lint
1343342a 15static char sccsid[] = "@(#)main.c 5.16 (Berkeley) %G%";
11c5f0a3 16#endif /* not lint */
ba5bf9f5
SL
17
18/*
19 * FTP User Program -- Command Interface.
20 */
9069f68e 21#include "ftp_var.h"
ba5bf9f5
SL
22#include <sys/socket.h>
23#include <sys/ioctl.h>
04480325 24#include <sys/types.h>
ba5bf9f5 25
62c4a390
SL
26#include <arpa/ftp.h>
27
ba5bf9f5
SL
28#include <signal.h>
29#include <stdio.h>
30#include <errno.h>
31#include <ctype.h>
32#include <netdb.h>
3b645f65 33#include <pwd.h>
ba5bf9f5 34
04480325 35uid_t getuid();
029aa654
RA
36sig_t intr();
37sig_t lostpeer();
3b645f65 38extern char *home;
14433a73 39char *getlogin();
ba5bf9f5
SL
40
41main(argc, argv)
42 char *argv[];
43{
44 register char *cp;
45 int top;
14433a73 46 struct passwd *pw = NULL;
3b645f65 47 char homedir[MAXPATHLEN];
ba5bf9f5
SL
48
49 sp = getservbyname("ftp", "tcp");
50 if (sp == 0) {
51 fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
52 exit(1);
53 }
a16b8edf 54 doglob = 1;
5ac6fc46 55 interactive = 1;
a16b8edf 56 autologin = 1;
ba5bf9f5
SL
57 argc--, argv++;
58 while (argc > 0 && **argv == '-') {
59 for (cp = *argv + 1; *cp; cp++)
60 switch (*cp) {
61
62 case 'd':
63 options |= SO_DEBUG;
64 debug++;
65 break;
66
67 case 'v':
68 verbose++;
69 break;
70
71 case 't':
72 trace++;
73 break;
74
75 case 'i':
5ac6fc46 76 interactive = 0;
ba5bf9f5
SL
77 break;
78
79 case 'n':
80 autologin = 0;
81 break;
82
a16b8edf
SL
83 case 'g':
84 doglob = 0;
85 break;
86
ba5bf9f5 87 default:
04480325 88 fprintf(stdout,
ba5bf9f5
SL
89 "ftp: %c: unknown option\n", *cp);
90 exit(1);
91 }
92 argc--, argv++;
93 }
94 fromatty = isatty(fileno(stdin));
ba5bf9f5
SL
95 if (fromatty)
96 verbose++;
029aa654 97 cpend = 0; /* no pending replies */
9069f68e 98 proxy = 0; /* proxy not active */
029aa654
RA
99 crflag = 1; /* strip c.r. on ascii gets */
100 sendport = -1; /* not using ports */
3b645f65
SL
101 /*
102 * Set up the home directory in case we're globbing.
103 */
14433a73 104 cp = getlogin();
9069f68e 105 if (cp != NULL) {
14433a73 106 pw = getpwnam(cp);
9069f68e 107 }
3b645f65
SL
108 if (pw == NULL)
109 pw = getpwuid(getuid());
110 if (pw != NULL) {
111 home = homedir;
04480325 112 (void) strcpy(home, pw->pw_dir);
3b645f65 113 }
ba5bf9f5
SL
114 if (argc > 0) {
115 if (setjmp(toplevel))
116 exit(0);
04480325
GM
117 (void) signal(SIGINT, intr);
118 (void) signal(SIGPIPE, lostpeer);
ba5bf9f5
SL
119 setpeer(argc + 1, argv - 1);
120 }
121 top = setjmp(toplevel) == 0;
122 if (top) {
04480325
GM
123 (void) signal(SIGINT, intr);
124 (void) signal(SIGPIPE, lostpeer);
ba5bf9f5
SL
125 }
126 for (;;) {
127 cmdscanner(top);
128 top = 1;
129 }
130}
131
029aa654 132sig_t
ba5bf9f5
SL
133intr()
134{
135
136 longjmp(toplevel, 1);
137}
138
029aa654 139sig_t
ba5bf9f5
SL
140lostpeer()
141{
142 extern FILE *cout;
143 extern int data;
ba5bf9f5
SL
144
145 if (connected) {
146 if (cout != NULL) {
04480325
GM
147 (void) shutdown(fileno(cout), 1+1);
148 (void) fclose(cout);
ba5bf9f5
SL
149 cout = NULL;
150 }
151 if (data >= 0) {
04480325 152 (void) shutdown(data, 1+1);
ba5bf9f5
SL
153 (void) close(data);
154 data = -1;
155 }
156 connected = 0;
157 }
9069f68e
GM
158 pswitch(1);
159 if (connected) {
160 if (cout != NULL) {
04480325
GM
161 (void) shutdown(fileno(cout), 1+1);
162 (void) fclose(cout);
9069f68e
GM
163 cout = NULL;
164 }
165 connected = 0;
166 }
167 proxflag = 0;
168 pswitch(0);
ba5bf9f5
SL
169}
170
04480325 171/*char *
ba5bf9f5
SL
172tail(filename)
173 char *filename;
174{
175 register char *s;
176
177 while (*filename) {
178 s = rindex(filename, '/');
179 if (s == NULL)
180 break;
181 if (s[1])
182 return (s + 1);
183 *s = '\0';
184 }
185 return (filename);
186}
04480325 187*/
ba5bf9f5
SL
188/*
189 * Command parser.
190 */
191cmdscanner(top)
192 int top;
193{
194 register struct cmd *c;
195 struct cmd *getcmd();
ba5bf9f5
SL
196 extern int help();
197
198 if (!top)
04480325 199 (void) putchar('\n');
ba5bf9f5
SL
200 for (;;) {
201 if (fromatty) {
202 printf("ftp> ");
04480325 203 (void) fflush(stdout);
ba5bf9f5 204 }
5a94754b 205 if (gets(line) == 0) {
f888943d 206 if (feof(stdin) || ferror(stdin))
c3b6c3a8 207 quit();
ba5bf9f5 208 break;
5a94754b 209 }
ba5bf9f5
SL
210 if (line[0] == 0)
211 break;
212 makeargv();
9069f68e 213 if (margc == 0) {
14433a73 214 continue;
9069f68e 215 }
ba5bf9f5
SL
216 c = getcmd(margv[0]);
217 if (c == (struct cmd *)-1) {
218 printf("?Ambiguous command\n");
219 continue;
220 }
221 if (c == 0) {
222 printf("?Invalid command\n");
223 continue;
224 }
5ac6fc46
SL
225 if (c->c_conn && !connected) {
226 printf ("Not connected.\n");
227 continue;
228 }
ba5bf9f5
SL
229 (*c->c_handler)(margc, margv);
230 if (bell && c->c_bell)
ff00793c 231 (void) putchar('\007');
ba5bf9f5
SL
232 if (c->c_handler != help)
233 break;
234 }
04480325
GM
235 (void) signal(SIGINT, intr);
236 (void) signal(SIGPIPE, lostpeer);
ba5bf9f5
SL
237}
238
239struct cmd *
240getcmd(name)
241 register char *name;
242{
a7d96790 243 extern struct cmd cmdtab[];
ba5bf9f5
SL
244 register char *p, *q;
245 register struct cmd *c, *found;
246 register int nmatches, longest;
247
248 longest = 0;
249 nmatches = 0;
250 found = 0;
251 for (c = cmdtab; p = c->c_name; c++) {
252 for (q = name; *q == *p++; q++)
253 if (*q == 0) /* exact match? */
254 return (c);
255 if (!*q) { /* the name was a prefix */
256 if (q - name > longest) {
257 longest = q - name;
258 nmatches = 1;
259 found = c;
260 } else if (q - name == longest)
261 nmatches++;
262 }
263 }
264 if (nmatches > 1)
265 return ((struct cmd *)-1);
266 return (found);
267}
268
269/*
270 * Slice a string up into argc/argv.
271 */
9069f68e
GM
272
273int slrflag;
274
ba5bf9f5
SL
275makeargv()
276{
277 char **argp;
278 char *slurpstring();
279
280 margc = 0;
281 argp = margv;
282 stringbase = line; /* scan from first of buffer */
283 argbase = argbuf; /* store from first of buffer */
9069f68e
GM
284 slrflag = 0;
285 while (*argp++ = slurpstring())
ba5bf9f5
SL
286 margc++;
287}
288
289/*
290 * Parse string into argbuf;
291 * implemented with FSM to
292 * handle quoting and strings
293 */
294char *
295slurpstring()
296{
297 int got_one = 0;
298 register char *sb = stringbase;
299 register char *ap = argbase;
300 char *tmp = argbase; /* will return this if token found */
301
9069f68e
GM
302 if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */
303 switch (slrflag) { /* and $ as token for macro invoke */
304 case 0:
305 slrflag++;
306 stringbase++;
307 return ((*sb == '!') ? "!" : "$");
ff00793c 308 /* NOTREACHED */
9069f68e
GM
309 case 1:
310 slrflag++;
311 altarg = stringbase;
312 break;
313 default:
314 break;
315 }
316 }
317
ba5bf9f5
SL
318S0:
319 switch (*sb) {
320
321 case '\0':
322 goto OUT;
323
324 case ' ':
325 case '\t':
326 sb++; goto S0;
327
328 default:
9069f68e
GM
329 switch (slrflag) {
330 case 0:
331 slrflag++;
332 break;
333 case 1:
334 slrflag++;
335 altarg = sb;
336 break;
337 default:
338 break;
339 }
ba5bf9f5
SL
340 goto S1;
341 }
342
343S1:
344 switch (*sb) {
345
346 case ' ':
347 case '\t':
348 case '\0':
349 goto OUT; /* end of token */
350
351 case '\\':
352 sb++; goto S2; /* slurp next character */
353
354 case '"':
355 sb++; goto S3; /* slurp quoted string */
356
357 default:
358 *ap++ = *sb++; /* add character to token */
359 got_one = 1;
360 goto S1;
361 }
362
363S2:
364 switch (*sb) {
365
366 case '\0':
367 goto OUT;
368
369 default:
370 *ap++ = *sb++;
371 got_one = 1;
372 goto S1;
373 }
374
375S3:
376 switch (*sb) {
377
378 case '\0':
379 goto OUT;
380
381 case '"':
382 sb++; goto S1;
383
384 default:
385 *ap++ = *sb++;
386 got_one = 1;
387 goto S3;
388 }
389
390OUT:
391 if (got_one)
392 *ap++ = '\0';
393 argbase = ap; /* update storage pointer */
394 stringbase = sb; /* update scan pointer */
9069f68e 395 if (got_one) {
ba5bf9f5 396 return(tmp);
9069f68e
GM
397 }
398 switch (slrflag) {
399 case 0:
400 slrflag++;
401 break;
402 case 1:
403 slrflag++;
404 altarg = (char *) 0;
405 break;
406 default:
407 break;
408 }
ba5bf9f5
SL
409 return((char *)0);
410}
411
412#define HELPINDENT (sizeof ("directory"))
413
414/*
415 * Help command.
416 * Call each command handler with argc == 0 and argv[0] == name.
417 */
418help(argc, argv)
419 int argc;
420 char *argv[];
421{
a7d96790 422 extern struct cmd cmdtab[];
ba5bf9f5
SL
423 register struct cmd *c;
424
425 if (argc == 1) {
9069f68e 426 register int i, j, w, k;
ba5bf9f5
SL
427 int columns, width = 0, lines;
428 extern int NCMDS;
429
430 printf("Commands may be abbreviated. Commands are:\n\n");
431 for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
432 int len = strlen(c->c_name);
433
434 if (len > width)
435 width = len;
436 }
437 width = (width + 8) &~ 7;
438 columns = 80 / width;
439 if (columns == 0)
440 columns = 1;
441 lines = (NCMDS + columns - 1) / columns;
442 for (i = 0; i < lines; i++) {
443 for (j = 0; j < columns; j++) {
444 c = cmdtab + j * lines + i;
9069f68e 445 if (c->c_name && (!proxy || c->c_proxy)) {
14433a73 446 printf("%s", c->c_name);
9069f68e
GM
447 }
448 else if (c->c_name) {
449 for (k=0; k < strlen(c->c_name); k++) {
04480325 450 (void) putchar(' ');
9069f68e
GM
451 }
452 }
ba5bf9f5
SL
453 if (c + lines >= &cmdtab[NCMDS]) {
454 printf("\n");
455 break;
456 }
457 w = strlen(c->c_name);
458 while (w < width) {
459 w = (w + 8) &~ 7;
04480325 460 (void) putchar('\t');
ba5bf9f5
SL
461 }
462 }
463 }
464 return;
465 }
466 while (--argc > 0) {
467 register char *arg;
468 arg = *++argv;
469 c = getcmd(arg);
470 if (c == (struct cmd *)-1)
471 printf("?Ambiguous help command %s\n", arg);
472 else if (c == (struct cmd *)0)
473 printf("?Invalid help command %s\n", arg);
474 else
475 printf("%-*s\t%s\n", HELPINDENT,
476 c->c_name, c->c_help);
477 }
478}