xref: /reactos/base/applications/network/ftp/main.c (revision 8a978a17)
1 /*
2  * Copyright (c) 1985, 1989 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 /*
19  * FTP User Program -- Command Interface.
20  */
21 
22 #include "precomp.h"
23 
24 #include <fcntl.h>
25 
26 #ifndef lint
27 char copyright[] =
28 "@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\
29  All rights reserved.\n";
30 #endif /* not lint */
31 
32 #ifndef lint
33 static char sccsid[] = "@(#)main.c	based on 5.13 (Berkeley) 3/14/89";
34 #endif /* not lint */
35 
36 #if defined(sun) && !defined(FD_SET)
37 typedef int uid_t;
38 #endif
39 
40 uid_t	getuid(void);
41 void	intr(void);
42 void	lostpeer(void);
43 char	*getlogin(void);
44 
45 short	portnum;
46 
47 char	home[128];
48 char	*globerr;
49 int	autologin;
50 
51 
52 
53 /* Lot's of options... */
54 /*
55  * Options and other state info.
56  */
57 int	trace;			/* trace packets exchanged */
58 int	hash;			/* print # for each buffer transferred */
59 //int	sendport;		/* use PORT cmd for each data connection */
60 int	verbose;		/* print messages coming back from server */
61 int	connected;		/* connected to server */
62 int	fromatty;		/* input is from a terminal */
63 int	interactive;		/* interactively prompt on m* cmds */
64 int	debug;			/* debugging level */
65 int	bell;			/* ring bell on cmd completion */
66 int	doglob;			/* glob local file names */
67 int	proxy;			/* proxy server connection active */
68 int	passivemode;
69 int	proxflag;		/* proxy connection exists */
70 int	sunique;		/* store files on server with unique name */
71 int	runique;		/* store local files with unique name */
72 int	mcase;			/* map upper to lower case for mget names */
73 int	ntflag;			/* use ntin ntout tables for name translation */
74 int	mapflag;		/* use mapin mapout templates on file names */
75 int	code;			/* return/reply code for ftp command */
76 int	crflag;			/* if 1, strip car. rets. on ascii gets */
77 char	pasv[64];		/* passive port for proxy data connection */
78 char	*altarg;		/* argv[1] with no shell-like preprocessing  */
79 char	ntin[17];		/* input translation table */
80 char	ntout[17];		/* output translation table */
81 // #include <sys/param.h>
82 char	mapin[MAXPATHLEN];	/* input map template */
83 char	mapout[MAXPATHLEN];	/* output map template */
84 char	typename[32];		/* name of file transfer type */
85 int	type;			/* file transfer type */
86 char	structname[32];		/* name of file transfer structure */
87 int	stru;			/* file transfer structure */
88 char	formname[32];		/* name of file transfer format */
89 int	form;			/* file transfer format */
90 char	modename[32];		/* name of file transfer mode */
91 int	mode;			/* file transfer mode */
92 char	bytename[32];		/* local byte size in ascii */
93 int	bytesize;		/* local byte size in binary */
94 
95 jmp_buf	toplevel;		/* non-local goto stuff for cmd scanner */
96 
97 char	line[200];		/* input line buffer */
98 char	*stringbase;		/* current scan point in line buffer */
99 char	argbuf[200];		/* argument storage buffer */
100 char	*argbase;		/* current storage point in arg buffer */
101 int	margc;			/* count of arguments on input line */
102 const char	*margv[20];	/* args parsed from input line */
103 int	cpend;			/* flag: if != 0, then pending server reply */
104 int	mflag;			/* flag: if != 0, then active multi command */
105 
106 int	options;		/* used during socket creation */
107 
108 int	macnum;			/* number of defined macros */
109 struct	macel macros[16];
110 char	macbuf[4096];
111 
112 /*
113  * Need to start a listen on the data channel
114  * before we send the command, otherwise the
115  * server's connect may fail.
116  */
117 int sendport = -1;
118 
119 static const char *slurpstring();
120 
121 
122 int main(int argc, const char *argv[])
123 {
124 	const char *cp;
125 	int top;
126 #if 0
127 	char homedir[MAXPATHLEN];
128 #endif
129 
130         int err;
131         WORD wVerReq;
132 
133         WSADATA WSAData;
134         struct	servent *sp;		/* service spec for tcp/ftp */
135 
136 	/* Disable output buffering, for the benefit of Emacs.  */
137 	//setbuf(stdout, NULL);
138 
139         _fmode = O_BINARY; // This causes an error somewhere.
140 
141         wVerReq = MAKEWORD(1,1);
142 
143         err = WSAStartup(wVerReq, &WSAData);
144         if (err != 0)
145         {
146            fprintf(stderr, "Could not initialize Windows socket interface.");
147            exit(1);
148         }
149 
150 	sp = getservbyname("ftp", "tcp");
151 	if (sp == 0) {
152 		fprintf(stderr, "ftp: ftp/tcp: unknown service\n");
153 		exit(1);
154 	}
155 
156         portnum = sp->s_port;
157 
158 
159 	doglob = 1;
160 	interactive = 1;
161 	autologin = 1;
162 	argc--, argv++;
163 	while (argc > 0 && **argv == '-') {
164 		for (cp = *argv + 1; *cp; cp++)
165 			switch (*cp) {
166 
167 			case 'd':
168 				options |= SO_DEBUG;
169 				debug++;
170 				break;
171 
172 			case 'v':
173 				verbose++;
174 				break;
175 
176 			case 't':
177 				trace++;
178 				break;
179 
180 			case 'i':
181 				interactive = 0;
182 				break;
183 
184 			case 'n':
185 				autologin = 0;
186 				break;
187 
188 			case 'g':
189 				doglob = 0;
190 				break;
191 
192 			default:
193 				fprintf(stdout,
194 				  "ftp: %c: unknown option\n", *cp);
195 				exit(1);
196 			}
197 		argc--, argv++;
198 	}
199 //	fromatty = isatty(fileno(stdin));
200         fromatty = 1; // Strengthen this test
201 	/*
202 	 * Set up defaults for FTP.
203 	 */
204 	(void) strcpy(typename, "ascii"), type = TYPE_A;
205 	(void) strcpy(formname, "non-print"), form = FORM_N;
206 	(void) strcpy(modename, "stream"), mode = MODE_S;
207 	(void) strcpy(structname, "file"), stru = STRU_F;
208 	(void) strcpy(bytename, "8"), bytesize = 8;
209 	if (fromatty)
210 		verbose++;
211 	cpend = 0;           /* no pending replies */
212 	proxy = 0;	/* proxy not active */
213     passivemode = 1; /* passive mode *is* active */
214 	crflag = 1;    /* strip c.r. on ascii gets */
215 	/*
216 	 * Set up the home directory in case we're globbing.
217 	 */
218 #if 0
219 	cp = getlogin();
220 	if (cp != NULL) {
221 		pw = getpwnam(cp);
222 	}
223 	if (pw == NULL)
224 		pw = getpwuid(getuid());
225 	if (pw != NULL) {
226 		home = homedir;
227 		(void) strcpy(home, pw->pw_dir);
228 	}
229 #endif
230 	cp = getenv("SystemDrive");
231 	if (cp != NULL && *cp != 0)
232 	{
233 		strcpy(home, cp);
234 		strcat(home, "/");
235 	}
236 	else
237 	{
238 		strcpy(home, "C:/");
239 	}
240 	if (argc > 0) {
241 		if (setjmp(toplevel))
242 			exit(0);
243 //		(void) signal(SIGINT, intr);
244 //		(void) signal(SIGPIPE, lostpeer);
245 		setpeer(argc + 1, argv - 1);
246 	}
247 	top = setjmp(toplevel) == 0;
248 	if (top) {
249 //		(void) signal(SIGINT, intr);
250 //		(void) signal(SIGPIPE, lostpeer);
251 	}
252 	for (;;) {
253 		cmdscanner(top);
254 		top = 1;
255 	}
256 }
257 
258 void intr(void)
259 {
260 	longjmp(toplevel, 1);
261 }
262 
263 void lostpeer(void)
264 {
265    extern SOCKET cout;
266    extern int data;
267 
268    if (connected) {
269       if (cout) {
270          closesocket(cout);
271          cout = 0;
272       }
273       if (data >= 0) {
274          (void) shutdown(data, 1+1);
275          (void) close(data);
276          data = -1;
277       }
278       connected = 0;
279    }
280    pswitch(1);
281    if (connected) {
282       if (cout) {
283 						closesocket(cout);
284          cout = 0;
285       }
286       connected = 0;
287    }
288    proxflag = 0;
289    pswitch(0);
290 }
291 
292 /*char *
293 tail(char *filename)
294 {
295 	register char *s;
296 
297 	while (*filename) {
298 		s = rindex(filename, '/');
299 		if (s == NULL)
300 			break;
301 		if (s[1])
302 			return (s + 1);
303 		*s = '\0';
304 	}
305 	return (filename);
306 }
307 */
308 /*
309  * Command parser.
310  */
311 void cmdscanner(int top)
312 {
313 	register struct cmd *c;
314 
315 	if (!top)
316 		(void) putchar('\n');
317 	for (;;) {
318 		(void) fflush(stdout);
319 		if (fromatty) {
320 			printf("ftp> ");
321 			(void) fflush(stdout);
322 		}
323 		if (gets(line) == 0) {
324 			if (feof(stdin) || ferror(stdin))
325 				quit(0, NULL);
326 			break;
327 		}
328 		if (line[0] == 0)
329 			break;
330 		makeargv();
331 		if (margc == 0) {
332 			continue;
333 		}
334 		c = getcmd(margv[0]);
335 		if (c == (struct cmd *)-1) {
336 			printf("?Ambiguous command\n");
337 			continue;
338 		}
339 		if (c == 0) {
340 			printf("?Invalid command\n");
341 			continue;
342 		}
343 		if (c->c_conn && !connected) {
344 			printf ("Not connected.\n");
345 			continue;
346 		}
347 		(*c->c_handler)(margc, margv);
348 		if (bell && c->c_bell)
349 			(void) putchar('\007');
350 		if (c->c_handler != help)
351 			break;
352 	}
353 	(void) fflush(stdout);
354 //	(void) signal(SIGINT, intr);
355 //	(void) signal(SIGPIPE, lostpeer);
356 }
357 
358 struct cmd *
359 getcmd(const char *name)
360 {
361 	extern struct cmd cmdtab[];
362 	const char *p, *q;
363 	struct cmd *c, *found;
364 	int nmatches, longest;
365 
366 	longest = 0;
367 	nmatches = 0;
368 	found = 0;
369 	for (c = cmdtab; (p = c->c_name); c++) {
370 		for (q = name; *q == *p++; q++)
371 			if (*q == 0)		/* exact match? */
372 				return (c);
373 		if (!*q) {			/* the name was a prefix */
374 			if (q - name > longest) {
375 				longest = q - name;
376 				nmatches = 1;
377 				found = c;
378 			} else if (q - name == longest)
379 				nmatches++;
380 		}
381 	}
382 	if (nmatches > 1)
383 		return ((struct cmd *)-1);
384 	return (found);
385 }
386 
387 /*
388  * Slice a string up into argc/argv.
389  */
390 
391 int slrflag;
392 
393 void makeargv(void)
394 {
395 	const char **argp;
396 
397 	margc = 0;
398 	argp = margv;
399 	stringbase = line;		/* scan from first of buffer */
400 	argbase = argbuf;		/* store from first of buffer */
401 	slrflag = 0;
402 	while ((*argp++ = slurpstring()))
403 		margc++;
404 }
405 
406 /*
407  * Parse string into argbuf;
408  * implemented with FSM to
409  * handle quoting and strings
410  */
411 static const char *
412 slurpstring(void)
413 {
414 	int got_one = 0;
415 	register char *sb = stringbase;
416 	register char *ap = argbase;
417 	char *tmp = argbase;		/* will return this if token found */
418 
419 	if (*sb == '!' || *sb == '$') {	/* recognize ! as a token for shell */
420 		switch (slrflag) {	/* and $ as token for macro invoke */
421 			case 0:
422 				slrflag++;
423 				stringbase++;
424 				return ((*sb == '!') ? "!" : "$");
425 				/* NOTREACHED */
426 			case 1:
427 				slrflag++;
428 				altarg = stringbase;
429 				break;
430 			default:
431 				break;
432 		}
433 	}
434 
435 S0:
436 	switch (*sb) {
437 
438 	case '\0':
439 		goto OUT1;
440 
441 	case ' ':
442 	case '\t':
443 		sb++; goto S0;
444 
445 	default:
446 		switch (slrflag) {
447 			case 0:
448 				slrflag++;
449 				break;
450 			case 1:
451 				slrflag++;
452 				altarg = sb;
453 				break;
454 			default:
455 				break;
456 		}
457 		goto S1;
458 	}
459 
460 S1:
461 	switch (*sb) {
462 
463 	case ' ':
464 	case '\t':
465 	case '\0':
466 		goto OUT1;	/* end of token */
467 
468 	case '\\':
469 		sb++; goto S2;	/* slurp next character */
470 
471 	case '"':
472 		sb++; goto S3;	/* slurp quoted string */
473 
474 	default:
475 		*ap++ = *sb++;	/* add character to token */
476 		got_one = 1;
477 		goto S1;
478 	}
479 
480 S2:
481 	switch (*sb) {
482 
483 	case '\0':
484 		goto OUT1;
485 
486 	default:
487 		*ap++ = *sb++;
488 		got_one = 1;
489 		goto S1;
490 	}
491 
492 S3:
493 	switch (*sb) {
494 
495 	case '\0':
496 		goto OUT1;
497 
498 	case '"':
499 		sb++; goto S1;
500 
501 	default:
502 		*ap++ = *sb++;
503 		got_one = 1;
504 		goto S3;
505 	}
506 
507 OUT1:
508 	if (got_one)
509 		*ap++ = '\0';
510 	argbase = ap;			/* update storage pointer */
511 	stringbase = sb;		/* update scan pointer */
512 	if (got_one) {
513 		return(tmp);
514 	}
515 	switch (slrflag) {
516 		case 0:
517 			slrflag++;
518 			break;
519 		case 1:
520 			slrflag++;
521 			altarg = (char *) 0;
522 			break;
523 		default:
524 			break;
525 	}
526 	return((char *)0);
527 }
528 
529 #define HELPINDENT (sizeof ("directory"))
530 
531 /*
532  * Help command.
533  * Call each command handler with argc == 0 and argv[0] == name.
534  */
535 void help(int argc, const char *argv[])
536 {
537 	extern struct cmd cmdtab[];
538 	struct cmd *c;
539 
540 	if (argc == 1) {
541 		register int i, j, w, k;
542 		int columns, width = 0, lines;
543 		extern int NCMDS;
544 
545 		printf("Commands may be abbreviated.  Commands are:\n\n");
546 		for (c = cmdtab; c < &cmdtab[NCMDS]; c++) {
547 			int len = strlen(c->c_name);
548 
549 			if (len > width)
550 				width = len;
551 		}
552 		width = (width + 8) &~ 7;
553 		columns = 80 / width;
554 		if (columns == 0)
555 			columns = 1;
556 		lines = (NCMDS + columns - 1) / columns;
557 		for (i = 0; i < lines; i++) {
558 			for (j = 0; j < columns; j++) {
559 				c = cmdtab + j * lines + i;
560 				if (c->c_name && (!proxy || c->c_proxy)) {
561 					printf("%s", c->c_name);
562 				}
563 				else if (c->c_name) {
564 					for (k=0; k < (int) strlen(c->c_name); k++) {
565 						(void) putchar(' ');
566 					}
567 				}
568 				if (c + lines >= &cmdtab[NCMDS]) {
569 					printf("\n");
570 					break;
571 				}
572 				w = strlen(c->c_name);
573 				while (w < width) {
574 					w = (w + 8) &~ 7;
575 					(void) putchar('\t');
576 				}
577 			}
578 		}
579 		(void) fflush(stdout);
580 		return;
581 	}
582 	while (--argc > 0) {
583 		const char *arg;
584 		arg = *++argv;
585 		c = getcmd(arg);
586 		if (c == (struct cmd *)-1)
587 			printf("?Ambiguous help command %s\n", arg);
588 		else if (c == (struct cmd *)0)
589 			printf("?Invalid help command %s\n", arg);
590 		else
591 			printf("%-*s\t%s\n", (int)HELPINDENT,
592 				c->c_name, c->c_help);
593 	}
594 	(void) fflush(stdout);
595 }
596