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