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