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