xref: /reactos/base/applications/network/ftp/cmds.c (revision c2c66aff)
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 Routines.
20  */
21 
22 #include "precomp.h"
23 
24 #include "pathnames.h"
25 
26 #ifndef lint
27 static char sccsid[] = "@(#)cmds.c	5.18 (Berkeley) 4/20/89";
28 #endif /* not lint */
29 
30 extern	char *globerr;
31 extern	char home[];
32 static	const char *remglob(const char *argv[], int doswitch);
33 extern	int allbinary;
34 extern off_t restart_point;
35 extern char reply_string[];
36 
37 const char *mname;
38 jmp_buf jabort;
39 const char *dotrans(const char *name);
40 const char *domap(const char *name);
41 
42 extern short portnum;
43 extern char *hostname;
44 extern int autologin;
45 /*
46  * Connect to peer server and
47  * auto-login, if possible.
48  */
setpeer(int argc,const char * argv[])49 void setpeer(int argc, const char *argv[])
50 {
51 	char *host;
52 
53 	if (connected) {
54 		printf("Already connected to %s, use close first.\n",
55 			hostname);
56 		(void) fflush(stdout);
57 		code = -1;
58 		return;
59 	}
60 	if (argc < 2) {
61 		(void) strcat(line, " ");
62 		printf("(to) ");
63 		(void) fflush(stdout);
64 		(void) gets(&line[strlen(line)]);
65 		makeargv();
66 		argc = margc;
67 		argv = margv;
68 	}
69 	if (argc > 3) {
70 		printf("usage: %s host-name [port]\n", argv[0]);
71 		(void) fflush(stdout);
72 		code = -1;
73 		return;
74 	}
75 	if (argc > 2) {
76 		portnum = atoi(argv[2]);
77 		if (portnum <= 0) {
78 			printf("%s: bad port number-- %s\n", argv[1], argv[2]);
79 			printf ("usage: %s host-name [port]\n", argv[0]);
80 			(void) fflush(stdout);
81 			code = -1;
82 			return;
83 		}
84 		portnum = htons(portnum);
85 	}
86 	host = hookup(argv[1], portnum);
87 	if (host) {
88 		int overbose;
89 		connected = 1;
90 		if (autologin)
91 			(void) login(argv[1]);
92 
93 		overbose = verbose;
94 		if (debug == 0)
95 			verbose = -1;
96 		allbinary = 0;
97 		if (command("SYST") == COMPLETE && overbose) {
98 			register char *cp, c;
99 			cp = index(reply_string+4, ' ');
100 			if (cp == NULL)
101 				cp = index(reply_string+4, '\r');
102 			if (cp) {
103 				if (cp[-1] == '.')
104 					cp--;
105 				c = *cp;
106 				*cp = '\0';
107 			}
108 
109 			printf("Remote system type is %s.\n",
110 				reply_string+4);
111 			if (cp)
112 				*cp = c;
113 		}
114 		if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
115 			setbinary(0, NULL);
116 			/* allbinary = 1; this violates the RFC */
117 			if (overbose)
118 			    printf("Using %s mode to transfer files.\n",
119 				typename);
120 		} else if (overbose &&
121 		    !strncmp(reply_string, "215 TOPS20", 10)) {
122 			printf(
123 "Remember to set tenex mode when transfering binary files from this machine.\n");
124 		}
125 		verbose = overbose;
126 	}
127 	(void) fflush(stdout);
128 }
129 
130 struct	types {
131 	const char	*t_name;
132 	const char	*t_mode;
133 	int	t_type;
134 	char	*t_arg;
135 } types[] = {
136 	{ "ascii",	"A",	TYPE_A,	0 },
137 	{ "binary",	"I",	TYPE_I,	0 },
138 	{ "image",	"I",	TYPE_I,	0 },
139 	{ "ebcdic",	"E",	TYPE_E,	0 },
140 	{ "tenex",	"L",	TYPE_L,	bytename },
141 	{0 }
142 };
143 
144 /*
145  * Set transfer type.
146  */
settype(int argc,const char * argv[])147 void settype(int argc, const char *argv[])
148 {
149 	register struct types *p;
150 	int comret;
151 
152 	if (argc > 2) {
153 		const char *sep;
154 
155 		printf("usage: %s [", argv[0]);
156 		sep = " ";
157 		for (p = types; p->t_name; p++) {
158 			printf("%s%s", sep, p->t_name);
159 			if (*sep == ' ')
160 				sep = " | ";
161 		}
162 		printf(" ]\n");
163 		(void) fflush(stdout);
164 		code = -1;
165 		return;
166 	}
167 	if (argc < 2) {
168 		printf("Using %s mode to transfer files.\n", typename);
169 		(void) fflush(stdout);
170 		code = 0;
171 		return;
172 	}
173 	for (p = types; p->t_name; p++)
174 		if (strcmp(argv[1], p->t_name) == 0)
175 			break;
176 	if (p->t_name == 0) {
177 		printf("%s: unknown mode\n", argv[1]);
178 		(void) fflush(stdout);
179 		code = -1;
180 		return;
181 	}
182 	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
183 		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
184 	else
185 		comret = command("TYPE %s", p->t_mode);
186 	if (comret == COMPLETE) {
187 		(void) strcpy(typename, p->t_name);
188 		type = p->t_type;
189 	}
190 }
191 
192 const char *stype[] = {
193 	"type",
194 	"",
195 	0
196 };
197 
198 /*
199  * Set binary transfer type.
200  */
201 /*VARARGS*/
setbinary(int argc,const char * argv[])202 void setbinary(int argc, const char *argv[])
203 {
204 	stype[1] = "binary";
205 	settype(2, stype);
206 }
207 
208 /*
209  * Set ascii transfer type.
210  */
211 /*VARARGS*/
setascii(int argc,const char * argv[])212 void setascii(int argc, const char *argv[])
213 {
214 	stype[1] = "ascii";
215 	settype(2, stype);
216 }
217 
218 /*
219  * Set tenex transfer type.
220  */
221 /*VARARGS*/
settenex(int argc,const char * argv[])222 void settenex(int argc, const char *argv[])
223 {
224 	stype[1] = "tenex";
225 	settype(2, stype);
226 }
227 
228 /*
229  * Set ebcdic transfer type.
230  */
231 /*VARARGS*/
setebcdic()232 void setebcdic()
233 {
234 	stype[1] = "ebcdic";
235 	settype(2, stype);
236 }
237 
238 /*
239  * Set file transfer mode.
240  */
241 
242 /*ARGSUSED*/
fsetmode(int argc,const char * argv[])243 void fsetmode(int argc, const char *argv[])
244 {
245 
246 	printf("We only support %s mode, sorry.\n", modename);
247 	(void) fflush(stdout);
248 	code = -1;
249 }
250 
251 
252 /*
253  * Set file transfer format.
254  */
255 /*ARGSUSED*/
setform(int argc,const char * argv[])256 void setform(int argc, const char *argv[])
257 {
258 
259 	printf("We only support %s format, sorry.\n", formname);
260 	(void) fflush(stdout);
261 	code = -1;
262 }
263 
264 /*
265  * Set file transfer structure.
266  */
267 /*ARGSUSED*/
setstruct(int argc,const char * argv[])268 void setstruct(int argc, const char *argv[])
269 {
270 
271 	printf("We only support %s structure, sorry.\n", structname);
272 	(void) fflush(stdout);
273 	code = -1;
274 }
275 
276 /*
277  * Send a single file.
278  */
put(int argc,const char * argv[])279 void put(int argc, const char *argv[])
280 {
281 	const char *cmd;
282 	int loc = 0;
283 	const char *oldargv1, *oldargv2;
284 
285 	if (argc == 2) {
286 		argc++;
287 		argv[2] = argv[1];
288 		loc++;
289 	}
290 	if (argc < 2) {
291 		(void) strcat(line, " ");
292 		printf("(local-file) ");
293 		(void) fflush(stdout);
294 		(void) gets(&line[strlen(line)]);
295 		makeargv();
296 		argc = margc;
297 		argv = margv;
298 	}
299 	if (argc < 2) {
300 usage:
301 		printf("usage:%s local-file remote-file\n", argv[0]);
302 		(void) fflush(stdout);
303 		code = -1;
304 		return;
305 	}
306 	if (argc < 3) {
307 		(void) strcat(line, " ");
308 		printf("(remote-file) ");
309 		(void) fflush(stdout);
310 		(void) gets(&line[strlen(line)]);
311 		makeargv();
312 		argc = margc;
313 		argv = margv;
314 	}
315 	if (argc < 3)
316 		goto usage;
317 	oldargv1 = argv[1];
318 	oldargv2 = argv[2];
319 	if (!globulize(&argv[1])) {
320 		code = -1;
321 		return;
322 	}
323 	/*
324 	 * If "globulize" modifies argv[1], and argv[2] is a copy of
325 	 * the old argv[1], make it a copy of the new argv[1].
326 	 */
327 	if (argv[1] != oldargv1 && argv[2] == oldargv1) {
328 		argv[2] = argv[1];
329 	}
330 	cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
331 	if (loc && ntflag) {
332 		argv[2] = dotrans(argv[2]);
333 	}
334 	if (loc && mapflag) {
335 		argv[2] = domap(argv[2]);
336 	}
337 	sendrequest(cmd, argv[1], argv[2],
338 	    argv[1] != oldargv1 || argv[2] != oldargv2);
339 }
340 
341 /*
342  * Send multiple files.
343  */
mput(int argc,const char * argv[])344 void mput(int argc, const char *argv[])
345 {
346 	register int i;
347 	int ointer;
348 	extern jmp_buf jabort;
349 	const char *tp;
350 
351 	if (argc < 2) {
352 		(void) strcat(line, " ");
353 		printf("(local-files) ");
354 		(void) fflush(stdout);
355 		(void) gets(&line[strlen(line)]);
356 		makeargv();
357 		argc = margc;
358 		argv = margv;
359 	}
360 	if (argc < 2) {
361 		printf("usage:%s local-files\n", argv[0]);
362 		(void) fflush(stdout);
363 		code = -1;
364 		return;
365 	}
366 	mname = argv[0];
367 	mflag = 1;
368 //	oldintr = signal(SIGINT, mabort);
369 	(void) setjmp(jabort);
370 	if (proxy) {
371 		const char *cp;
372 		char *tp2, tmpbuf[MAXPATHLEN];
373 
374 		while ((cp = remglob(argv,0)) != NULL) {
375 			if (*cp == 0) {
376 				mflag = 0;
377 				continue;
378 			}
379 			if (mflag && confirm(argv[0], cp)) {
380 				tp = cp;
381 				if (mcase) {
382 					while (*tp && !islower(*tp)) {
383 						tp++;
384 					}
385 					if (!*tp) {
386 						tp = cp;
387 						tp2 = tmpbuf;
388 						while ((*tp2 = *tp)) {
389 						     if (isupper(*tp2)) {
390 						        *tp2 = 'a' + *tp2 - 'A';
391 						     }
392 						     tp++;
393 						     tp2++;
394 						}
395 					}
396 					tp = tmpbuf;
397 				}
398 				if (ntflag) {
399 					tp = dotrans(tp);
400 				}
401 				if (mapflag) {
402 					tp = domap(tp);
403 				}
404 				sendrequest((sunique) ? "STOU" : "STOR",
405 				    cp, tp, cp != tp || !interactive);
406 				if (!mflag && fromatty) {
407 					ointer = interactive;
408 					interactive = 1;
409 					if (confirm("Continue with","mput")) {
410 						mflag++;
411 					}
412 					interactive = ointer;
413 				}
414 			}
415 		}
416 //		(void) signal(SIGINT, oldintr);
417 		mflag = 0;
418 		return;
419 	}
420 	for (i = 1; i < argc; i++) {
421 		register char **cpp, **gargs;
422 
423 		if (!doglob) {
424 			if (mflag && confirm(argv[0], argv[i])) {
425 				tp = (ntflag) ? dotrans(argv[i]) : argv[i];
426 				tp = (mapflag) ? domap(tp) : tp;
427 				sendrequest((sunique) ? "STOU" : "STOR",
428 				    argv[i], tp, tp != argv[i] || !interactive);
429 				if (!mflag && fromatty) {
430 					ointer = interactive;
431 					interactive = 1;
432 					if (confirm("Continue with","mput")) {
433 						mflag++;
434 					}
435 					interactive = ointer;
436 				}
437 			}
438 			continue;
439 		}
440 		gargs = glob(argv[i]);
441 		if (globerr != NULL) {
442 			printf("%s\n", globerr);
443 			(void) fflush(stdout);
444 			if (gargs) {
445 				blkfree(gargs);
446 				free((char *)gargs);
447 			}
448 			continue;
449 		}
450 		for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
451 			if (mflag && confirm(argv[0], *cpp)) {
452 				tp = (ntflag) ? dotrans(*cpp) : *cpp;
453 				tp = (mapflag) ? domap(tp) : tp;
454 				sendrequest((sunique) ? "STOU" : "STOR",
455 				    *cpp, tp, *cpp != tp || !interactive);
456 				if (!mflag && fromatty) {
457 					ointer = interactive;
458 					interactive = 1;
459 					if (confirm("Continue with","mput")) {
460 						mflag++;
461 					}
462 					interactive = ointer;
463 				}
464 			}
465 		}
466 		if (gargs != NULL) {
467 			blkfree(gargs);
468 			free((char *)gargs);
469 		}
470 	}
471 //	(void) signal(SIGINT, oldintr);
472 	mflag = 0;
473 }
474 
reget(int argc,const char * argv[])475 void reget(int argc, const char *argv[])
476 {
477 	(void) getit(argc, argv, 1, "r+w");
478 }
479 
get(int argc,const char * argv[])480 void get(int argc, const char *argv[])
481 {
482 	(void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
483 }
484 
485 /*
486  * Receive one file.
487  */
getit(int argc,const char * argv[],int restartit,const char * mode)488 int getit(int argc, const char *argv[], int restartit, const char *mode)
489 {
490 	int loc = 0;
491 	const char *oldargv1, *oldargv2;
492 
493 	if (argc == 2) {
494 		argc++;
495 		argv[2] = argv[1];
496 		loc++;
497 	}
498 	if (argc < 2) {
499 		(void) strcat(line, " ");
500 		printf("(remote-file) ");
501 		(void) fflush(stdout);
502 		(void) gets(&line[strlen(line)]);
503 		makeargv();
504 		argc = margc;
505 		argv = margv;
506 	}
507 	if (argc < 2) {
508 usage:
509 		printf("usage: %s remote-file [ local-file ]\n", argv[0]);
510 		(void) fflush(stdout);
511 		code = -1;
512 		return (0);
513 	}
514 	if (argc < 3) {
515 		(void) strcat(line, " ");
516 		printf("(local-file) ");
517 		(void) fflush(stdout);
518 		(void) gets(&line[strlen(line)]);
519 		makeargv();
520 		argc = margc;
521 		argv = margv;
522 	}
523 	if (argc < 3)
524 		goto usage;
525 	oldargv1 = argv[1];
526 	oldargv2 = argv[2];
527 	if (!globulize(&argv[2])) {
528 		code = -1;
529 		return (0);
530 	}
531 	if (loc && mcase) {
532 		const char *tp = argv[1];
533         char *tp2, tmpbuf[MAXPATHLEN];
534 
535 		while (*tp && !islower(*tp)) {
536 			tp++;
537 		}
538 		if (!*tp) {
539 			tp = argv[2];
540 			tp2 = tmpbuf;
541 			while ((*tp2 = *tp)) {
542 				if (isupper(*tp2)) {
543 					*tp2 = 'a' + *tp2 - 'A';
544 				}
545 				tp++;
546 				tp2++;
547 			}
548 			argv[2] = tmpbuf;
549 		}
550 	}
551 	if (loc && ntflag)
552 		argv[2] = dotrans(argv[2]);
553 	if (loc && mapflag)
554 		argv[2] = domap(argv[2]);
555 	if (restartit) {
556 		struct stat stbuf;
557 		int ret;
558 
559 		ret = stat(argv[2], &stbuf);
560 		if (restartit == 1) {
561 			if (ret < 0) {
562 				perror(argv[2]);
563 				return (0);
564 			}
565 			restart_point = stbuf.st_size;
566 		} else {
567 			if (ret == 0) {
568 				int overbose;
569 
570 				overbose = verbose;
571 				if (debug == 0)
572 					verbose = -1;
573 				if (command("MDTM %s", argv[1]) == COMPLETE) {
574 					int yy, mo, day, hour, min, sec;
575 					struct tm *tm;
576 					verbose = overbose;
577 					sscanf(reply_string,
578 					    "%*s %04d%02d%02d%02d%02d%02d",
579 					    &yy, &mo, &day, &hour, &min, &sec);
580 					tm = gmtime(&stbuf.st_mtime);
581 					tm->tm_mon++;
582 					if (tm->tm_year > yy%100)
583 						return (1);
584 					else if (tm->tm_year == yy%100) {
585 						if (tm->tm_mon > mo)
586 							return (1);
587 					} else if (tm->tm_mon == mo) {
588 						if (tm->tm_mday > day)
589 							return (1);
590 					} else if (tm->tm_mday == day) {
591 						if (tm->tm_hour > hour)
592 							return (1);
593 					} else if (tm->tm_hour == hour) {
594 						if (tm->tm_min > min)
595 							return (1);
596 					} else if (tm->tm_min == min) {
597 						if (tm->tm_sec > sec)
598 							return (1);
599 					}
600 				} else {
601 					printf("%s\n", reply_string);
602 					(void) fflush(stdout);
603 					verbose = overbose;
604 					return (0);
605 				}
606 			}
607 		}
608 	}
609 
610 	recvrequest("RETR", argv[2], argv[1], mode,
611 	    argv[1] != oldargv1 || argv[2] != oldargv2);
612 	restart_point = 0;
613 	return (0);
614 }
615 
616 #if 0
617 static void
618 mabort()
619 {
620 	int ointer;
621 	extern jmp_buf jabort;
622 
623 	printf("\n");
624 	(void) fflush(stdout);
625 	if (mflag && fromatty) {
626 		ointer = interactive;
627 		interactive = 1;
628 		if (confirm("Continue with", mname)) {
629 			interactive = ointer;
630 			longjmp(jabort,0);
631 		}
632 		interactive = ointer;
633 	}
634 	mflag = 0;
635 	longjmp(jabort,0);
636 }
637 #endif
638 
639 /*
640  * Get multiple files.
641  */
mget(int argc,const char * argv[])642 void mget(int argc, const char *argv[])
643 {
644 	const char *cp, *tp;
645     char *tp2, tmpbuf[MAXPATHLEN];
646 	int ointer;
647 	extern jmp_buf jabort;
648 
649 	if (argc < 2) {
650 		(void) strcat(line, " ");
651 		printf("(remote-files) ");
652 		(void) fflush(stdout);
653 		(void) gets(&line[strlen(line)]);
654 		makeargv();
655 		argc = margc;
656 		argv = margv;
657 	}
658 	if (argc < 2) {
659 		printf("usage:%s remote-files\n", argv[0]);
660 		(void) fflush(stdout);
661 		code = -1;
662 		return;
663 	}
664 	mname = argv[0];
665 	mflag = 1;
666 //	oldintr = signal(SIGINT,mabort);
667 	(void) setjmp(jabort);
668 	while ((cp = remglob(argv,proxy)) != NULL) {
669 		if (*cp == '\0') {
670 			mflag = 0;
671 			continue;
672 		}
673 		if (mflag && confirm(argv[0], cp)) {
674 			tp = cp;
675 			if (mcase) {
676 				while (*tp && !islower(*tp)) {
677 					tp++;
678 				}
679 				if (!*tp) {
680 					tp = cp;
681 					tp2 = tmpbuf;
682 					while ((*tp2 = *tp)) {
683 						if (isupper(*tp2)) {
684 							*tp2 = 'a' + *tp2 - 'A';
685 						}
686 						tp++;
687 						tp2++;
688 					}
689 				}
690 				tp = tmpbuf;
691 			}
692 			if (ntflag) {
693 				tp = dotrans(tp);
694 			}
695 			if (mapflag) {
696 				tp = domap(tp);
697 			}
698 			recvrequest("RETR", tp, cp, "w",
699 			    tp != cp || !interactive);
700 			if (!mflag && fromatty) {
701 				ointer = interactive;
702 				interactive = 1;
703 				if (confirm("Continue with","mget")) {
704 					mflag++;
705 				}
706 				interactive = ointer;
707 			}
708 		}
709 	}
710 //	(void) signal(SIGINT,oldintr);
711 	mflag = 0;
712 }
713 
714 const char *
remglob(const char * argv[],int doswitch)715 remglob(const char *argv[], int doswitch)
716 {
717 	char temp[16];
718 	static char buf[MAXPATHLEN];
719 	static FILE *ftemp = NULL;
720 	static const char **args;
721 	int oldverbose, oldhash;
722 	const char *cp;
723     const char *mode;
724     char *terminator;
725 
726 	if (!mflag) {
727 		if (!doglob) {
728 			args = NULL;
729 		}
730 		else {
731 			if (ftemp) {
732 				(void) fclose(ftemp);
733 				ftemp = NULL;
734 			}
735 		}
736 		return(NULL);
737 	}
738 	if (!doglob) {
739 		if (args == NULL)
740 			args = argv;
741 		if ((cp = *++args) == NULL)
742 			args = NULL;
743 		return (cp);
744 	}
745 	if (ftemp == NULL) {
746 		(void) strcpy(temp, _PATH_TMP);
747 		(void) mktemp(temp);
748 		oldverbose = verbose, verbose = 0;
749 		oldhash = hash, hash = 0;
750 		if (doswitch) {
751 			pswitch(!proxy);
752 		}
753 		for (mode = "w"; *++argv != NULL; mode = "a")
754 			recvrequest ("NLST", temp, *argv, mode, 0);
755 		if (doswitch) {
756 			pswitch(!proxy);
757 		}
758 		verbose = oldverbose; hash = oldhash;
759 		ftemp = fopen(temp, "r");
760 		(void) unlink(temp);
761 		if (ftemp == NULL) {
762 			printf("can't find list of remote files, oops\n");
763 			(void) fflush(stdout);
764 			return (NULL);
765 		}
766 	}
767 	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
768 		(void) fclose(ftemp), ftemp = NULL;
769 		return (NULL);
770 	}
771 	if ((terminator = index(buf, '\n')) != NULL)
772 		*terminator = '\0';
773 	return (buf);
774 }
775 
776 static const char *
onoff(int bool)777 onoff(int bool)
778 {
779 	return (bool ? "on" : "off");
780 }
781 
782 /*
783  * Show status.
784  */
785 /*ARGSUSED*/
status(int argc,const char * argv[])786 void status(int argc, const char *argv[])
787 {
788 	int i;
789 
790 	if (connected)
791 		printf("Connected to %s.\n", hostname);
792 	else
793 		printf("Not connected.\n");
794 	if (!proxy) {
795 		pswitch(1);
796 		if (connected) {
797 			printf("Connected for proxy commands to %s.\n", hostname);
798 		}
799 		else {
800 			printf("No proxy connection.\n");
801 		}
802 		pswitch(0);
803 	}
804 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
805 		modename, typename, formname, structname);
806 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
807 		onoff(verbose), onoff(bell), onoff(interactive),
808 		onoff(doglob));
809 	printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
810 		onoff(runique));
811 	printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
812 	if (ntflag) {
813 		printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
814 	}
815 	else {
816 		printf("Ntrans: off\n");
817 	}
818 	if (mapflag) {
819 		printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
820 	}
821 	else {
822 		printf("Nmap: off\n");
823 	}
824 	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
825 		onoff(hash), onoff(sendport));
826 	if (macnum > 0) {
827 		printf("Macros:\n");
828 		for (i=0; i<macnum; i++) {
829 			printf("\t%s\n",macros[i].mac_name);
830 		}
831 	}
832 	(void) fflush(stdout);
833 	code = 0;
834 }
835 
836 /*
837  * Set beep on cmd completed mode.
838  */
839 /*VARARGS*/
setbell(int argc,const char * argv[])840 void setbell(int argc, const char *argv[])
841 {
842 
843 	bell = !bell;
844 	printf("Bell mode %s.\n", onoff(bell));
845 	(void) fflush(stdout);
846 	code = bell;
847 }
848 
849 /*
850  * Turn on packet tracing.
851  */
852 /*VARARGS*/
settrace(int argc,const char * argv[])853 void settrace(int argc, const char *argv[])
854 {
855 
856 	trace = !trace;
857 	printf("Packet tracing %s.\n", onoff(trace));
858 	(void) fflush(stdout);
859 	code = trace;
860 }
861 
862 /*
863  * Toggle hash mark printing during transfers.
864  */
865 /*VARARGS*/
sethash(int argc,const char * argv[])866 void sethash(int argc, const char *argv[])
867 {
868 
869 	hash = !hash;
870 	printf("Hash mark printing %s", onoff(hash));
871 	code = hash;
872 	if (hash)
873 		printf(" (%d bytes/hash mark)", 1024);
874 	printf(".\n");
875 	(void) fflush(stdout);
876 }
877 
878 /*
879  * Turn on printing of server echo's.
880  */
881 /*VARARGS*/
setverbose(int argc,const char * argv[])882 void setverbose(int argc, const char *argv[])
883 {
884 
885 	verbose = !verbose;
886 	printf("Verbose mode %s.\n", onoff(verbose));
887 	(void) fflush(stdout);
888 	code = verbose;
889 }
890 
891 /*
892  * Toggle PORT cmd use before each data connection.
893  */
894 /*VARARGS*/
setport(int argc,const char * argv[])895 void setport(int argc, const char *argv[])
896 {
897 
898 	sendport = !sendport;
899 	printf("Use of PORT cmds %s.\n", onoff(sendport));
900 	(void) fflush(stdout);
901 	code = sendport;
902 }
903 
904 /*
905  * Turn on interactive prompting
906  * during mget, mput, and mdelete.
907  */
908 /*VARARGS*/
setprompt(int argc,const char * argv[])909 void setprompt(int argc, const char *argv[])
910 {
911 
912 	interactive = !interactive;
913 	printf("Interactive mode %s.\n", onoff(interactive));
914 	(void) fflush(stdout);
915 	code = interactive;
916 }
917 
918 /*
919  * Toggle metacharacter interpretation
920  * on local file names.
921  */
922 /*VARARGS*/
setglob(int argc,const char * argv[])923 void setglob(int argc, const char *argv[])
924 {
925 
926 	doglob = !doglob;
927 	printf("Globbing %s.\n", onoff(doglob));
928 	(void) fflush(stdout);
929 	code = doglob;
930 }
931 
932 /*
933  * Set debugging mode on/off and/or
934  * set level of debugging.
935  */
936 /*VARARGS*/
setdebug(int argc,const char * argv[])937 void setdebug(int argc, const char *argv[])
938 {
939 	int val;
940 
941 	if (argc > 1) {
942 		val = atoi(argv[1]);
943 		if (val < 0) {
944 			printf("%s: bad debugging value.\n", argv[1]);
945 			(void) fflush(stdout);
946 			code = -1;
947 			return;
948 		}
949 	} else
950 		val = !debug;
951 	debug = val;
952 	if (debug)
953 		options |= SO_DEBUG;
954 	else
955 		options &= ~SO_DEBUG;
956 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
957 	(void) fflush(stdout);
958 	code = debug > 0;
959 }
960 
961 /*
962  * Set current working directory
963  * on remote machine.
964  */
cd(int argc,const char * argv[])965 void cd(int argc, const char *argv[])
966 {
967 
968 	if (argc < 2) {
969 		(void) strcat(line, " ");
970 		printf("(remote-directory) ");
971 		(void) fflush(stdout);
972 		(void) gets(&line[strlen(line)]);
973 		makeargv();
974 		argc = margc;
975 		argv = margv;
976 	}
977 	if (argc < 2) {
978 		printf("usage:%s remote-directory\n", argv[0]);
979 		(void) fflush(stdout);
980 		code = -1;
981 		return;
982 	}
983 	if (command("CWD %s", argv[1]) == ERROR && code == 500) {
984 		if (verbose) {
985 			printf("CWD command not recognized, trying XCWD\n");
986 			(void) fflush(stdout);
987 		}
988 		(void) command("XCWD %s", argv[1]);
989 	}
990 }
991 
992 /*
993  * Set current working directory
994  * on local machine.
995  */
lcd(int argc,const char * argv[])996 void lcd(int argc, const char *argv[])
997 {
998 	char buf[MAXPATHLEN];
999 
1000 	if (argc < 2)
1001 		argc++, argv[1] = home;
1002 	if (argc != 2) {
1003 		printf("usage:%s local-directory\n", argv[0]);
1004 		(void) fflush(stdout);
1005 		code = -1;
1006 		return;
1007 	}
1008 	if (!globulize(&argv[1])) {
1009 		code = -1;
1010 		return;
1011 	}
1012 	if (chdir(argv[1]) < 0) {
1013 		perror(argv[1]);
1014 		code = -1;
1015 		return;
1016 	}
1017 	printf("Local directory now %s\n", getcwd(buf,sizeof(buf)));
1018 	(void) fflush(stdout);
1019 	code = 0;
1020 }
1021 
1022 /*
1023  * Delete a single file.
1024  */
delete(int argc,const char * argv[])1025 void delete(int argc, const char *argv[])
1026 {
1027 
1028 	if (argc < 2) {
1029 		(void) strcat(line, " ");
1030 		printf("(remote-file) ");
1031 		(void) fflush(stdout);
1032 		(void) gets(&line[strlen(line)]);
1033 		makeargv();
1034 		argc = margc;
1035 		argv = margv;
1036 	}
1037 	if (argc < 2) {
1038 		printf("usage:%s remote-file\n", argv[0]);
1039 		(void) fflush(stdout);
1040 		code = -1;
1041 		return;
1042 	}
1043 	(void) command("DELE %s", argv[1]);
1044 }
1045 
1046 /*
1047  * Delete multiple files.
1048  */
mdelete(int argc,const char * argv[])1049 void mdelete(int argc, const char *argv[])
1050 {
1051 	const char *cp;
1052 	int ointer;
1053 	extern jmp_buf jabort;
1054 
1055 	if (argc < 2) {
1056 		(void) strcat(line, " ");
1057 		printf("(remote-files) ");
1058 		(void) fflush(stdout);
1059 		(void) gets(&line[strlen(line)]);
1060 		makeargv();
1061 		argc = margc;
1062 		argv = margv;
1063 	}
1064 	if (argc < 2) {
1065 		printf("usage:%s remote-files\n", argv[0]);
1066 		(void) fflush(stdout);
1067 		code = -1;
1068 		return;
1069 	}
1070 	mname = argv[0];
1071 	mflag = 1;
1072 //	oldintr = signal(SIGINT, mabort);
1073 	(void) setjmp(jabort);
1074 	while ((cp = remglob(argv,0)) != NULL) {
1075 		if (*cp == '\0') {
1076 			mflag = 0;
1077 			continue;
1078 		}
1079 		if (mflag && confirm(argv[0], cp)) {
1080 			(void) command("DELE %s", cp);
1081 			if (!mflag && fromatty) {
1082 				ointer = interactive;
1083 				interactive = 1;
1084 				if (confirm("Continue with", "mdelete")) {
1085 					mflag++;
1086 				}
1087 				interactive = ointer;
1088 			}
1089 		}
1090 	}
1091 //	(void) signal(SIGINT, oldintr);
1092 	mflag = 0;
1093 }
1094 
1095 /*
1096  * Rename a remote file.
1097  */
renamefile(int argc,const char * argv[])1098 void renamefile(int argc, const char *argv[])
1099 {
1100 
1101 	if (argc < 2) {
1102 		(void) strcat(line, " ");
1103 		printf("(from-name) ");
1104 		(void) fflush(stdout);
1105 		(void) gets(&line[strlen(line)]);
1106 		makeargv();
1107 		argc = margc;
1108 		argv = margv;
1109 	}
1110 	if (argc < 2) {
1111 usage:
1112 		printf("%s from-name to-name\n", argv[0]);
1113 		(void) fflush(stdout);
1114 		code = -1;
1115 		return;
1116 	}
1117 	if (argc < 3) {
1118 		(void) strcat(line, " ");
1119 		printf("(to-name) ");
1120 		(void) fflush(stdout);
1121 		(void) gets(&line[strlen(line)]);
1122 		makeargv();
1123 		argc = margc;
1124 		argv = margv;
1125 	}
1126 	if (argc < 3)
1127 		goto usage;
1128 	if (command("RNFR %s", argv[1]) == CONTINUE)
1129 		(void) command("RNTO %s", argv[2]);
1130 }
1131 
1132 /*
1133  * Get a directory listing
1134  * of remote files.
1135  */
ls(int argc,const char * argv[])1136 void ls(int argc, const char *argv[])
1137 {
1138 	const char *cmd;
1139 
1140 	if (argc < 2)
1141 		argc++, argv[1] = NULL;
1142 	if (argc < 3)
1143 		argc++, argv[2] = "-";
1144 	if (argc > 3) {
1145 		printf("usage: %s remote-directory local-file\n", argv[0]);
1146 		(void) fflush(stdout);
1147 		code = -1;
1148 		return;
1149 	}
1150 	cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
1151 //	cmd = argv[0][0] == 'n' ? "NLST -CF" : "NLST -CF";
1152 	if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1153 		code = -1;
1154 		return;
1155 	}
1156 	if (strcmp(argv[2], "-") && *argv[2] != '|')
1157 		if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
1158 			code = -1;
1159 			return;
1160 	}
1161 	recvrequest(cmd, argv[2], argv[1], "w", 0);
1162 }
1163 
1164 /*
1165  * Get a directory listing
1166  * of multiple remote files.
1167  */
mls(int argc,const char * argv[])1168 void mls(int argc, const char *argv[])
1169 {
1170 	const char *cmd, *dest;
1171 	char mode[1];
1172 	int ointer, i;
1173 	extern jmp_buf jabort;
1174 
1175 	if (argc < 2) {
1176 		(void) strcat(line, " ");
1177 		printf("(remote-files) ");
1178 		(void) fflush(stdout);
1179 		(void) gets(&line[strlen(line)]);
1180 		makeargv();
1181 		argc = margc;
1182 		argv = margv;
1183 	}
1184 	if (argc < 3) {
1185 		(void) strcat(line, " ");
1186 		printf("(local-file) ");
1187 		(void) fflush(stdout);
1188 		(void) gets(&line[strlen(line)]);
1189 		makeargv();
1190 		argc = margc;
1191 		argv = margv;
1192 	}
1193 	if (argc < 3) {
1194 		printf("usage:%s remote-files local-file\n", argv[0]);
1195 		(void) fflush(stdout);
1196 		code = -1;
1197 		return;
1198 	}
1199 	dest = argv[argc - 1];
1200 	argv[argc - 1] = NULL;
1201 	if (strcmp(dest, "-") && *dest != '|')
1202 		if (!globulize(&dest) || !confirm("output to local-file:", dest)) {
1203 			code = -1;
1204 			return;
1205 	}
1206 	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
1207 	mname = argv[0];
1208 	mflag = 1;
1209 //	oldintr = signal(SIGINT, mabort);
1210 	(void) setjmp(jabort);
1211 	for (i = 1; mflag && i < argc-1; ++i) {
1212 		*mode = (i == 1) ? 'w' : 'a';
1213 		recvrequest(cmd, dest, argv[i], mode, 0);
1214 		if (!mflag && fromatty) {
1215 			ointer = interactive;
1216 			interactive = 1;
1217 			if (confirm("Continue with", argv[0])) {
1218 				mflag ++;
1219 			}
1220 			interactive = ointer;
1221 		}
1222 	}
1223 //	(void) signal(SIGINT, oldintr);
1224 	mflag = 0;
1225 }
1226 
1227 /*
1228  * Do a shell escape
1229  */
1230 /*ARGSUSED*/
shell(int argc,const char * argv[])1231 void shell(int argc, const char *argv[])
1232 {
1233 #if 0
1234 	int pid;
1235 	sig_t (*old1)(), (*old2)();
1236 	char shellnam[40], *shell, *namep;
1237 	union wait status;
1238 
1239 	old1 = signal (SIGINT, SIG_IGN);
1240 	old2 = signal (SIGQUIT, SIG_IGN);
1241 	if ((pid = fork()) == 0) {
1242 		for (pid = 3; pid < 20; pid++)
1243 			(void) close(pid);
1244 		(void) signal(SIGINT, SIG_DFL);
1245 		(void) signal(SIGQUIT, SIG_DFL);
1246 		shell = getenv("SHELL");
1247 		if (shell == NULL)
1248 			shell = _PATH_BSHELL;
1249 		namep = rindex(shell,'/');
1250 		if (namep == NULL)
1251 			namep = shell;
1252 		(void) strcpy(shellnam,"-");
1253 		(void) strcat(shellnam, ++namep);
1254 		if (strcmp(namep, "sh") != 0)
1255 			shellnam[0] = '+';
1256 		if (debug) {
1257 			printf ("%s\n", shell);
1258 			(void) fflush (stdout);
1259 		}
1260 		if (argc > 1) {
1261 			execl(shell,shellnam,"-c",altarg,(char *)0);
1262 		}
1263 		else {
1264 			execl(shell,shellnam,(char *)0);
1265 		}
1266 		perror(shell);
1267 		code = -1;
1268 		exit(1);
1269 		}
1270 	if (pid > 0)
1271 		while (wait(&status) != pid)
1272 			;
1273 	(void) signal(SIGINT, old1);
1274 	(void) signal(SIGQUIT, old2);
1275 	if (pid == -1) {
1276 		perror("Try again later");
1277 		code = -1;
1278 	}
1279 	else {
1280 		code = 0;
1281 	}
1282 #endif
1283 
1284     char *              AppName;
1285     char                ShellCmd[MAX_PATH];
1286     char                CmdLine[MAX_PATH];
1287     int                 i;
1288     PROCESS_INFORMATION ProcessInformation;
1289     BOOL                Result;
1290     STARTUPINFO         StartupInfo;
1291     char                ShellName[] = "COMSPEC";
1292     int                 NumBytes;
1293 
1294     NumBytes = GetEnvironmentVariable( ShellName, ShellCmd, MAX_PATH);
1295 
1296     if (NumBytes == 0)
1297     {
1298         return;
1299     }
1300 
1301     AppName = ShellCmd;
1302     strcpy( CmdLine, ShellCmd );
1303 
1304     if (argc > 1)
1305     {
1306         strncat(CmdLine, " /C", MAX_PATH - strlen(CmdLine) - 1);
1307     }
1308 
1309     for (i=1; i<argc; i++)
1310     {
1311         strncat(CmdLine, " ", MAX_PATH - strlen(CmdLine) - 1);
1312         strncat(CmdLine, argv[i], MAX_PATH - strlen(CmdLine) - 1);
1313     }
1314 
1315     StartupInfo.cb          = sizeof( StartupInfo );
1316     StartupInfo.lpReserved  = NULL;
1317     StartupInfo.lpDesktop   = NULL;
1318     StartupInfo.lpTitle     = NULL;
1319     StartupInfo.dwX         = 0;
1320     StartupInfo.dwY         = 0;
1321     StartupInfo.dwXSize     = 0;
1322     StartupInfo.dwYSize     = 0;
1323     StartupInfo.dwFlags     = 0;
1324     StartupInfo.wShowWindow = 0;
1325     StartupInfo.cbReserved2 = 0;
1326     StartupInfo.lpReserved2 = NULL;
1327 
1328     Result = CreateProcess( AppName,                // cmd name
1329                             CmdLine,                // cmd line arguments
1330                             NULL,
1331                             NULL,                   // security attributes
1332                             FALSE,                  // inherit flags
1333                             0,                      // Creation flags
1334                             NULL,                   // Environment
1335                             NULL,                   // Current directory
1336                             &StartupInfo,           // Startup info structure
1337                             &ProcessInformation);   // processInfo structure
1338 
1339     if (Result)
1340     {
1341         WaitForSingleObject( ProcessInformation.hProcess, 0xffffffff);
1342 
1343         CloseHandle( ProcessInformation.hProcess);
1344     }
1345 }
1346 
1347 /*
1348  * Send new user information (re-login)
1349  */
user(int argc,const char * argv[])1350 void user(int argc, const char *argv[])
1351 {
1352 	char acct[80], *getpass();
1353 	int n, aflag = 0;
1354 
1355 	if (argc < 2) {
1356 		(void) strcat(line, " ");
1357 		printf("(username) ");
1358 		(void) fflush(stdout);
1359 		(void) gets(&line[strlen(line)]);
1360 		makeargv();
1361 		argc = margc;
1362 		argv = margv;
1363 	}
1364 	if (argc > 4) {
1365 		printf("usage: %s username [password] [account]\n", argv[0]);
1366 		(void) fflush(stdout);
1367 		code = -1;
1368 		return;
1369 	}
1370 	n = command("USER %s", argv[1]);
1371 	if (n == CONTINUE) {
1372 		if (argc < 3 )
1373 			argv[2] = getpass("Password: "), argc++;
1374 		n = command("PASS %s", argv[2]);
1375 	}
1376 	if (n == CONTINUE) {
1377 		if (argc < 4) {
1378 			printf("Account: "); (void) fflush(stdout);
1379 			(void) fflush(stdout);
1380 			(void) fgets(acct, sizeof(acct) - 1, stdin);
1381 			acct[strlen(acct) - 1] = '\0';
1382 			argv[3] = acct; argc++;
1383 		}
1384 		n = command("ACCT %s", argv[3]);
1385 		aflag++;
1386 	}
1387 	if (n != COMPLETE) {
1388 		fprintf(stdout, "Login failed.\n");
1389 		(void) fflush(stdout);
1390 		return;
1391 	}
1392 	if (!aflag && argc == 4) {
1393 		(void) command("ACCT %s", argv[3]);
1394 	}
1395 }
1396 
1397 /*
1398  * Print working directory.
1399  */
1400 /*VARARGS*/
pwd(int argc,const char * argv[])1401 void pwd(int argc, const char *argv[])
1402 {
1403 	int oldverbose = verbose;
1404 
1405 	/*
1406 	 * If we aren't verbose, this doesn't do anything!
1407 	 */
1408 	verbose = 1;
1409 	if (command("PWD") == ERROR && code == 500) {
1410 		printf("PWD command not recognized, trying XPWD\n");
1411 		(void) fflush(stdout);
1412 		(void) command("XPWD");
1413 	}
1414 	verbose = oldverbose;
1415 }
1416 
1417 /*
1418  * Make a directory.
1419  */
makedir(int argc,const char * argv[])1420 void makedir(int argc, const char *argv[])
1421 {
1422 
1423 	if (argc < 2) {
1424 		(void) strcat(line, " ");
1425 		printf("(directory-name) ");
1426 		(void) fflush(stdout);
1427 		(void) gets(&line[strlen(line)]);
1428 		makeargv();
1429 		argc = margc;
1430 		argv = margv;
1431 	}
1432 	if (argc < 2) {
1433 		printf("usage: %s directory-name\n", argv[0]);
1434 		(void) fflush(stdout);
1435 		code = -1;
1436 		return;
1437 	}
1438 	if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1439 		if (verbose) {
1440 			printf("MKD command not recognized, trying XMKD\n");
1441 			(void) fflush(stdout);
1442 		}
1443 		(void) command("XMKD %s", argv[1]);
1444 	}
1445 }
1446 
1447 /*
1448  * Remove a directory.
1449  */
removedir(int argc,const char * argv[])1450 void removedir(int argc, const char *argv[])
1451 {
1452 
1453 	if (argc < 2) {
1454 		(void) strcat(line, " ");
1455 		printf("(directory-name) ");
1456 		(void) fflush(stdout);
1457 		(void) gets(&line[strlen(line)]);
1458 		makeargv();
1459 		argc = margc;
1460 		argv = margv;
1461 	}
1462 	if (argc < 2) {
1463 		printf("usage: %s directory-name\n", argv[0]);
1464 		(void) fflush(stdout);
1465 		code = -1;
1466 		return;
1467 	}
1468 	if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1469 		if (verbose) {
1470 			printf("RMD command not recognized, trying XRMD\n");
1471 			(void) fflush(stdout);
1472 		}
1473 		(void) command("XRMD %s", argv[1]);
1474 	}
1475 }
1476 
1477 /*
1478  * Send a line, verbatim, to the remote machine.
1479  */
quote(int argc,const char * argv[])1480 void quote(int argc, const char *argv[])
1481 {
1482 	int i;
1483 	char buf[BUFSIZ];
1484 
1485 	if (argc < 2) {
1486 		(void) strcat(line, " ");
1487 		printf("(command line to send) ");
1488 		(void) fflush(stdout);
1489 		(void) gets(&line[strlen(line)]);
1490 		makeargv();
1491 		argc = margc;
1492 		argv = margv;
1493 	}
1494 	if (argc < 2) {
1495 		printf("usage: %s line-to-send\n", argv[0]);
1496 		(void) fflush(stdout);
1497 		code = -1;
1498 		return;
1499 	}
1500 	(void) strcpy(buf, argv[1]);
1501 	for (i = 2; i < argc; i++) {
1502 		(void) strcat(buf, " ");
1503 		(void) strcat(buf, argv[i]);
1504 	}
1505 	if (command(buf) == PRELIM) {
1506 		while (getreply(0) == PRELIM);
1507 	}
1508 }
1509 
1510 /*
1511  * Send a SITE command to the remote machine.  The line
1512  * is sent almost verbatim to the remote machine, the
1513  * first argument is changed to SITE.
1514  */
site(int argc,const char * argv[])1515 void site(int argc, const char *argv[])
1516 {
1517 	int i;
1518 	char buf[BUFSIZ];
1519 
1520 	if (argc < 2) {
1521 		(void) strcat(line, " ");
1522 		printf("(arguments to SITE command) ");
1523 		(void) fflush(stdout);
1524 		(void) gets(&line[strlen(line)]);
1525 		makeargv();
1526 		argc = margc;
1527 		argv = margv;
1528 	}
1529 	if (argc < 2) {
1530 		printf("usage: %s line-to-send\n", argv[0]);
1531 		(void) fflush(stdout);
1532 		code = -1;
1533 		return;
1534 	}
1535 	(void) strcpy(buf, "SITE ");
1536 	(void) strcat(buf, argv[1]);
1537 	for (i = 2; i < argc; i++) {
1538 		(void) strcat(buf, " ");
1539 		(void) strcat(buf, argv[i]);
1540 	}
1541 	if (command(buf) == PRELIM) {
1542 		while (getreply(0) == PRELIM);
1543 	}
1544 }
1545 
do_chmod(int argc,const char * argv[])1546 void do_chmod(int argc, const char *argv[])
1547 {
1548 	if (argc == 2) {
1549 		printf("usage: %s mode file-name\n", argv[0]);
1550 		(void) fflush(stdout);
1551 		code = -1;
1552 		return;
1553 	}
1554 	if (argc < 3) {
1555 		(void) strcat(line, " ");
1556 		printf("(mode and file-name) ");
1557 		(void) fflush(stdout);
1558 		(void) gets(&line[strlen(line)]);
1559 		makeargv();
1560 		argc = margc;
1561 		argv = margv;
1562 	}
1563 	if (argc != 3) {
1564 		printf("usage: %s mode file-name\n", argv[0]);
1565 		(void) fflush(stdout);
1566 		code = -1;
1567 		return;
1568 	}
1569 	(void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1570 }
1571 
do_umask(int argc,const char * argv[])1572 void do_umask(int argc, const char *argv[])
1573 {
1574 	int oldverbose = verbose;
1575 
1576 	verbose = 1;
1577 	(void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1578 	verbose = oldverbose;
1579 }
1580 
idle(int argc,const char * argv[])1581 void idle(int argc, const char *argv[])
1582 {
1583 	int oldverbose = verbose;
1584 
1585 	verbose = 1;
1586 	(void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1587 	verbose = oldverbose;
1588 }
1589 
1590 /*
1591  * Ask the other side for help.
1592  */
rmthelp(int argc,const char * argv[])1593 void rmthelp(int argc, const char *argv[])
1594 {
1595 	int oldverbose = verbose;
1596 
1597 	verbose = 1;
1598 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1599 	verbose = oldverbose;
1600 }
1601 
1602 /*
1603  * Terminate session and exit.
1604  */
1605 /*VARARGS*/
quit(int argc,const char * argv[])1606 void quit(int argc, const char *argv[])
1607 {
1608 	if (connected)
1609 		disconnect(0, NULL);
1610 	pswitch(1);
1611 	if (connected) {
1612 		disconnect(0, NULL);
1613 	}
1614 	exit(0);
1615 }
1616 
1617 /*
1618  * Terminate session, but don't exit.
1619  */
disconnect(int argc,const char * argv[])1620 void disconnect(int argc, const char *argv[])
1621 {
1622 	extern SOCKET cout;
1623 	extern int data;
1624 
1625 	if (!connected)
1626 		return;
1627 	(void) command("QUIT");
1628 	cout = 0;
1629 	connected = 0;
1630 	data = -1;
1631 	if (!proxy) {
1632 		macnum = 0;
1633 	}
1634 }
1635 
confirm(const char * cmd,const char * file)1636 int confirm(const char *cmd, const char *file)
1637 {
1638 	char line[BUFSIZ];
1639 
1640 	if (!interactive)
1641 		return (1);
1642 	printf("%s %s? ", cmd, file);
1643 	(void) fflush(stdout);
1644 	(void) gets(line);
1645 	return (*line != 'n' && *line != 'N');
1646 }
1647 
1648 #if 0
1649 static void fatal(const char *msg)
1650 {
1651 
1652 	fprintf(stderr, "ftp: %s\n", msg);
1653 	exit(1);
1654 }
1655 #endif
1656 
1657 /*
1658  * Glob a local file name specification with
1659  * the expectation of a single return value.
1660  * Can't control multiple values being expanded
1661  * from the expression, we return only the first.
1662  */
globulize(const char ** cpp)1663 int globulize(const char **cpp)
1664 {
1665 	char **globbed;
1666 
1667 	if (!doglob)
1668 		return (1);
1669 	globbed = glob(*cpp);
1670 	if (globerr != NULL) {
1671 		printf("%s: %s\n", *cpp, globerr);
1672 		(void) fflush(stdout);
1673 		if (globbed) {
1674 			blkfree(globbed);
1675 			free((char *)globbed);
1676 		}
1677 		return (0);
1678 	}
1679 	if (globbed) {
1680 		*cpp = *globbed++;
1681 		/* don't waste too much memory */
1682 		if (*globbed) {
1683 			blkfree(globbed);
1684 			free((char *)globbed);
1685 		}
1686 	}
1687 	return (1);
1688 }
1689 
account(int argc,const char * argv[])1690 void account(int argc, const char *argv[])
1691 {
1692 	char acct[50], *getpass(), *ap;
1693 
1694 	if (argc > 1) {
1695 		++argv;
1696 		--argc;
1697 		(void) strncpy(acct,*argv,49);
1698 		acct[49] = '\0';
1699 		while (argc > 1) {
1700 			--argc;
1701 			++argv;
1702 			(void) strncat(acct,*argv, 49-strlen(acct));
1703 		}
1704 		ap = acct;
1705 	}
1706 	else {
1707 		ap = getpass("Account:");
1708 	}
1709 	(void) command("ACCT %s", ap);
1710 }
1711 
1712 jmp_buf abortprox;
1713 
1714 #if 0
1715 static void
1716 proxabort()
1717 {
1718 	extern int proxy;
1719 
1720 	if (!proxy) {
1721 		pswitch(1);
1722 	}
1723 	if (connected) {
1724 		proxflag = 1;
1725 	}
1726 	else {
1727 		proxflag = 0;
1728 	}
1729 	pswitch(0);
1730 	longjmp(abortprox,1);
1731 }
1732 #endif
1733 
doproxy(int argc,const char * argv[])1734 void doproxy(int argc, const char *argv[])
1735 {
1736 	register struct cmd *c;
1737 	struct cmd *getcmd();
1738 //	extern struct cmd cmdtab[];
1739 	extern jmp_buf abortprox;
1740 
1741 	if (argc < 2) {
1742 		(void) strcat(line, " ");
1743 		printf("(command) ");
1744 		(void) fflush(stdout);
1745 		(void) gets(&line[strlen(line)]);
1746 		makeargv();
1747 		argc = margc;
1748 		argv = margv;
1749 	}
1750 	if (argc < 2) {
1751 		printf("usage:%s command\n", argv[0]);
1752 		(void) fflush(stdout);
1753 		code = -1;
1754 		return;
1755 	}
1756 	c = getcmd(argv[1]);
1757 	if (c == (struct cmd *) -1) {
1758 		printf("?Ambiguous command\n");
1759 		(void) fflush(stdout);
1760 		code = -1;
1761 		return;
1762 	}
1763 	if (c == 0) {
1764 		printf("?Invalid command\n");
1765 		(void) fflush(stdout);
1766 		code = -1;
1767 		return;
1768 	}
1769 	if (!c->c_proxy) {
1770 		printf("?Invalid proxy command\n");
1771 		(void) fflush(stdout);
1772 		code = -1;
1773 		return;
1774 	}
1775 	if (setjmp(abortprox)) {
1776 		code = -1;
1777 		return;
1778 	}
1779 //	oldintr = signal(SIGINT, proxabort);
1780 	pswitch(1);
1781 	if (c->c_conn && !connected) {
1782 		printf("Not connected\n");
1783 		(void) fflush(stdout);
1784 		pswitch(0);
1785 //		(void) signal(SIGINT, oldintr);
1786 		code = -1;
1787 		return;
1788 	}
1789 	(*c->c_handler)(argc-1, argv+1);
1790 	if (connected) {
1791 		proxflag = 1;
1792 	}
1793 	else {
1794 		proxflag = 0;
1795 	}
1796 	pswitch(0);
1797 //	(void) signal(SIGINT, oldintr);
1798 }
1799 
setcase(int argc,const char * argv[])1800 void setcase(int argc, const char *argv[])
1801 {
1802 	mcase = !mcase;
1803 	printf("Case mapping %s.\n", onoff(mcase));
1804 	(void) fflush(stdout);
1805 	code = mcase;
1806 }
1807 
setcr(int argc,const char * argv[])1808 void setcr(int argc, const char *argv[])
1809 {
1810 	crflag = !crflag;
1811 	printf("Carriage Return stripping %s.\n", onoff(crflag));
1812 	(void) fflush(stdout);
1813 	code = crflag;
1814 }
1815 
setntrans(int argc,const char * argv[])1816 void setntrans(int argc, const char *argv[])
1817 {
1818 	if (argc == 1) {
1819 		ntflag = 0;
1820 		printf("Ntrans off.\n");
1821 		(void) fflush(stdout);
1822 		code = ntflag;
1823 		return;
1824 	}
1825 	ntflag++;
1826 	code = ntflag;
1827 	(void) strncpy(ntin, argv[1], 16);
1828 	ntin[16] = '\0';
1829 	if (argc == 2) {
1830 		ntout[0] = '\0';
1831 		return;
1832 	}
1833 	(void) strncpy(ntout, argv[2], 16);
1834 	ntout[16] = '\0';
1835 }
1836 
1837 const char *
dotrans(const char * name)1838 dotrans(const char *name)
1839 {
1840 	static char new[MAXPATHLEN];
1841 	const char *cp1;
1842     char *cp2 = new;
1843 	register int i, ostop, found;
1844 
1845 	for (ostop = 0; ostop < 16 && *(ntout + ostop); ostop++);
1846 	for (cp1 = name; *cp1; cp1++) {
1847 		found = 0;
1848 		for (i = 0; i < 16 && *(ntin + i); i++) {
1849 			if (*cp1 == *(ntin + i)) {
1850 				found++;
1851 				if (i < ostop) {
1852 					*cp2++ = *(ntout + i);
1853 				}
1854 				break;
1855 			}
1856 		}
1857 		if (!found) {
1858 			*cp2++ = *cp1;
1859 		}
1860 	}
1861 	*cp2 = '\0';
1862 	return(new);
1863 }
1864 
setpassive(int argc,const char * argv[])1865 void setpassive(int argc, const char *argv[])
1866 {
1867 	passivemode = !passivemode;
1868 	printf("Passive mode %s.\n", onoff(passivemode));
1869 	(void) fflush(stdout);
1870 	code = passivemode;
1871 }
1872 
setnmap(int argc,const char * argv[])1873 void setnmap(int argc, const char *argv[])
1874 {
1875 	char *cp;
1876 
1877 	if (argc == 1) {
1878 		mapflag = 0;
1879 		printf("Nmap off.\n");
1880 		(void) fflush(stdout);
1881 		code = mapflag;
1882 		return;
1883 	}
1884 	if (argc < 3) {
1885 		(void) strcat(line, " ");
1886 		printf("(mapout) ");
1887 		(void) fflush(stdout);
1888 		(void) gets(&line[strlen(line)]);
1889 		makeargv();
1890 		argc = margc;
1891 		argv = margv;
1892 	}
1893 	if (argc < 3) {
1894 		printf("Usage: %s [mapin mapout]\n",argv[0]);
1895 		(void) fflush(stdout);
1896 		code = -1;
1897 		return;
1898 	}
1899 	mapflag = 1;
1900 	code = 1;
1901 	cp = index(altarg, ' ');
1902 	if (proxy) {
1903 		while(*++cp == ' ');
1904 		altarg = cp;
1905 		cp = index(altarg, ' ');
1906 	}
1907 	*cp = '\0';
1908 	(void) strncpy(mapin, altarg, MAXPATHLEN - 1);
1909 	while (*++cp == ' ');
1910 	(void) strncpy(mapout, cp, MAXPATHLEN - 1);
1911 }
1912 
1913 const char *
domap(const char * name)1914 domap(const char *name)
1915 {
1916 	static char new[MAXPATHLEN];
1917 	const char *cp1 = name;
1918     char *cpn, *cp2 = mapin;
1919 	const char *tp[9], *te[9];
1920 	int i, toks[9], toknum = 0, match = 1;
1921 
1922 	for (i=0; i < 9; ++i) {
1923 		toks[i] = 0;
1924 	}
1925 	while (match && *cp1 && *cp2) {
1926 		switch (*cp2) {
1927 			case '\\':
1928 				if (*++cp2 != *cp1) {
1929 					match = 0;
1930 				}
1931 				break;
1932 			case '$':
1933 				if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1934 					if (*cp1 != *(++cp2+1)) {
1935 						toks[toknum = *cp2 - '1']++;
1936 						tp[toknum] = cp1;
1937 						while (*++cp1 && *(cp2+1)
1938 							!= *cp1);
1939 						te[toknum] = cp1;
1940 					}
1941 					cp2++;
1942 					break;
1943 				}
1944 				/* FALLTHROUGH */
1945 			default:
1946 				if (*cp2 != *cp1) {
1947 					match = 0;
1948 				}
1949 				break;
1950 		}
1951 		if (match && *cp1) {
1952 			cp1++;
1953 		}
1954 		if (match && *cp2) {
1955 			cp2++;
1956 		}
1957 	}
1958 	if (!match && *cp1) /* last token mismatch */
1959 	{
1960 		toks[toknum] = 0;
1961 	}
1962 
1963 	cpn = new;
1964 	*cpn = '\0';
1965 	cp2 = mapout;
1966 	while (*cp2) {
1967 		match = 0;
1968 		switch (*cp2) {
1969 			case '\\':
1970 				if (*(cp2 + 1)) {
1971 					*cpn++ = *++cp2;
1972 				}
1973 				break;
1974 			case '[':
1975 LOOP:
1976 				if (*++cp2 == '$' && isdigit(*(cp2+1))) {
1977 					if (*++cp2 == '0') {
1978 						const char *cp3 = name;
1979 
1980 						while (*cp3) {
1981 							*cpn++ = *cp3++;
1982 						}
1983 						match = 1;
1984 					}
1985 					else if (toks[toknum = *cp2 - '1']) {
1986 						const char *cp3 = tp[toknum];
1987 
1988 						while (cp3 != te[toknum]) {
1989 							*cpn++ = *cp3++;
1990 						}
1991 						match = 1;
1992 					}
1993 				}
1994 				else {
1995 					while (*cp2 && *cp2 != ',' &&
1996 					    *cp2 != ']') {
1997 						if (*cp2 == '\\') {
1998 							cp2++;
1999 						}
2000 						else if (*cp2 == '$' &&
2001    						        isdigit(*(cp2+1))) {
2002 							if (*++cp2 == '0') {
2003 							   const char *cp3 = name;
2004 
2005 							   while (*cp3) {
2006 								*cpn++ = *cp3++;
2007 							   }
2008 							}
2009 							else if (toks[toknum =
2010 							    *cp2 - '1']) {
2011 							   const char *cp3=tp[toknum];
2012 
2013 							   while (cp3 !=
2014 								  te[toknum]) {
2015 								*cpn++ = *cp3++;
2016 							   }
2017 							}
2018 						}
2019 						else if (*cp2) {
2020 							*cpn++ = *cp2++;
2021 						}
2022 					}
2023 					if (!*cp2) {
2024 						printf("nmap: unbalanced brackets\n");
2025 						(void) fflush(stdout);
2026 						return(name);
2027 					}
2028 					match = 1;
2029 					cp2--;
2030 				}
2031 				if (match) {
2032 					while (*++cp2 && *cp2 != ']') {
2033 					      if (*cp2 == '\\' && *(cp2 + 1)) {
2034 							cp2++;
2035 					      }
2036 					}
2037 					if (!*cp2) {
2038 						printf("nmap: unbalanced brackets\n");
2039 						(void) fflush(stdout);
2040 						return(name);
2041 					}
2042 					break;
2043 				}
2044 				switch (*++cp2) {
2045 					case ',':
2046 						goto LOOP;
2047 					case ']':
2048 						break;
2049 					default:
2050 						cp2--;
2051 						goto LOOP;
2052 				}
2053 				break;
2054 			case '$':
2055 				if (isdigit(*(cp2 + 1))) {
2056 					if (*++cp2 == '0') {
2057 						const char *cp3 = name;
2058 
2059 						while (*cp3) {
2060 							*cpn++ = *cp3++;
2061 						}
2062 					}
2063 					else if (toks[toknum = *cp2 - '1']) {
2064 						const char *cp3 = tp[toknum];
2065 
2066 						while (cp3 != te[toknum]) {
2067 							*cpn++ = *cp3++;
2068 						}
2069 					}
2070 					break;
2071 				}
2072 				/* intentional drop through */
2073 			default:
2074 				*cpn++ = *cp2;
2075 				break;
2076 		}
2077 		cp2++;
2078 	}
2079 	*cpn = '\0';
2080 	if (!*new) {
2081 		return(name);
2082 	}
2083 	return(new);
2084 }
2085 
setsunique(int argc,const char * argv[])2086 void setsunique(int argc, const char *argv[])
2087 {
2088 	sunique = !sunique;
2089 	printf("Store unique %s.\n", onoff(sunique));
2090 	(void) fflush(stdout);
2091 	code = sunique;
2092 }
2093 
setrunique(int argc,const char * argv[])2094 void setrunique(int argc, const char *argv[])
2095 {
2096 	runique = !runique;
2097 	printf("Receive unique %s.\n", onoff(runique));
2098 	(void) fflush(stdout);
2099 	code = runique;
2100 }
2101 
2102 /* change directory to parent directory */
cdup(int argc,const char * argv[])2103 void cdup(int argc, const char *argv[])
2104 {
2105 	if (command("CDUP") == ERROR && code == 500) {
2106 		if (verbose) {
2107 			printf("CDUP command not recognized, trying XCUP\n");
2108 			(void) fflush(stdout);
2109 		}
2110 		(void) command("XCUP");
2111 	}
2112 }
2113 
2114 /* restart transfer at specific point */
restart(int argc,const char * argv[])2115 void restart(int argc, const char *argv[])
2116 {
2117 	if (argc != 2)
2118 		printf("restart: offset not specified\n");
2119 	else {
2120 		restart_point = atol(argv[1]);
2121 		printf("restarting at %ld. %s\n", restart_point,
2122 		    "execute get, put or append to initiate transfer");
2123 	}
2124 	(void) fflush(stdout);
2125 }
2126 
2127 /* show remote system type */
syst(int argc,const char * argv[])2128 void syst(int argc, const char *argv[])
2129 {
2130 	(void) command("SYST");
2131 }
2132 
macdef(int argc,const char * argv[])2133 void macdef(int argc, const char *argv[])
2134 {
2135 	char *tmp;
2136 	int c;
2137 
2138 	if (macnum == 16) {
2139 		printf("Limit of 16 macros have already been defined\n");
2140 		(void) fflush(stdout);
2141 		code = -1;
2142 		return;
2143 	}
2144 	if (argc < 2) {
2145 		(void) strcat(line, " ");
2146 		printf("(macro name) ");
2147 		(void) fflush(stdout);
2148 		(void) gets(&line[strlen(line)]);
2149 		makeargv();
2150 		argc = margc;
2151 		argv = margv;
2152 	}
2153 	if (argc != 2) {
2154 		printf("Usage: %s macro_name\n",argv[0]);
2155 		(void) fflush(stdout);
2156 		code = -1;
2157 		return;
2158 	}
2159 	if (interactive) {
2160 		printf("Enter macro line by line, terminating it with a null line\n");
2161 		(void) fflush(stdout);
2162 	}
2163 	(void) strncpy(macros[macnum].mac_name, argv[1], 8);
2164 	if (macnum == 0) {
2165 		macros[macnum].mac_start = macbuf;
2166 	}
2167 	else {
2168 		macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2169 	}
2170 	tmp = macros[macnum].mac_start;
2171 	while (tmp != macbuf+4096) {
2172 		if ((c = getchar()) == EOF) {
2173 			printf("macdef:end of file encountered\n");
2174 			(void) fflush(stdout);
2175 			code = -1;
2176 			return;
2177 		}
2178 		if ((*tmp = c) == '\n') {
2179 			if (tmp == macros[macnum].mac_start) {
2180 				macros[macnum++].mac_end = tmp;
2181 				code = 0;
2182 				return;
2183 			}
2184 			if (*(tmp-1) == '\0') {
2185 				macros[macnum++].mac_end = tmp - 1;
2186 				code = 0;
2187 				return;
2188 			}
2189 			*tmp = '\0';
2190 		}
2191 		tmp++;
2192 	}
2193 	while (1) {
2194 		while ((c = getchar()) != '\n' && c != EOF)
2195 			/* LOOP */;
2196 		if (c == EOF || getchar() == '\n') {
2197 			printf("Macro not defined - 4k buffer exceeded\n");
2198 			(void) fflush(stdout);
2199 			code = -1;
2200 			return;
2201 		}
2202 	}
2203 }
2204 
2205 /*
2206  * get size of file on remote machine
2207  */
sizecmd(int argc,const char * argv[])2208 void sizecmd(int argc, const char *argv[])
2209 {
2210 
2211 	if (argc < 2) {
2212 		(void) strcat(line, " ");
2213 		printf("(filename) ");
2214 		(void) fflush(stdout);
2215 		(void) gets(&line[strlen(line)]);
2216 		makeargv();
2217 		argc = margc;
2218 		argv = margv;
2219 	}
2220 	if (argc < 2) {
2221 		printf("usage:%s filename\n", argv[0]);
2222 		(void) fflush(stdout);
2223 		code = -1;
2224 		return;
2225 	}
2226 	(void) command("SIZE %s", argv[1]);
2227 }
2228 
2229 /*
2230  * get last modification time of file on remote machine
2231  */
modtime(int argc,const char * argv[])2232 void modtime(int argc, const char *argv[])
2233 {
2234 	int overbose;
2235 
2236 	if (argc < 2) {
2237 		(void) strcat(line, " ");
2238 		printf("(filename) ");
2239 		(void) fflush(stdout);
2240 		(void) gets(&line[strlen(line)]);
2241 		makeargv();
2242 		argc = margc;
2243 		argv = margv;
2244 	}
2245 	if (argc < 2) {
2246 		printf("usage:%s filename\n", argv[0]);
2247 		(void) fflush(stdout);
2248 		code = -1;
2249 		return;
2250 	}
2251 	overbose = verbose;
2252 	if (debug == 0)
2253 		verbose = -1;
2254 	if (command("MDTM %s", argv[1]) == COMPLETE) {
2255 		int yy, mo, day, hour, min, sec;
2256 		sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
2257 			&day, &hour, &min, &sec);
2258 		/* might want to print this in local time */
2259 		printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
2260 			mo, day, yy, hour, min, sec);
2261 	} else
2262 		printf("%s\n", reply_string);
2263 	verbose = overbose;
2264 	(void) fflush(stdout);
2265 }
2266 
2267 /*
2268  * show status on remote machine
2269  */
rmtstatus(int argc,const char * argv[])2270 void rmtstatus(int argc, const char *argv[])
2271 {
2272 	(void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2273 }
2274 
2275 /*
2276  * get file if modtime is more recent than current file
2277  */
newer(int argc,const char * argv[])2278 void newer(int argc, const char *argv[])
2279 {
2280 	if (getit(argc, argv, -1, "w")) {
2281 		printf("Local file \"%s\" is newer than remote file \"%s\"\n",
2282 			argv[1], argv[2]);
2283 		(void) fflush(stdout);
2284 	}
2285 }
2286