xref: /csrg-svn/usr.bin/ftp/cmds.c (revision 11650)
1 #ifndef lint
2 static char sccsid[] = "@(#)cmds.c	4.4 (Berkeley) 03/23/83";
3 #endif
4 
5 /*
6  * FTP User Program -- Command Routines.
7  */
8 #include <sys/param.h>
9 #include <sys/socket.h>
10 
11 #include <signal.h>
12 #include <stdio.h>
13 #include <errno.h>
14 #include <netdb.h>
15 #include <stat.h>
16 
17 #include "ftp.h"
18 #include "ftp_var.h"
19 
20 extern	char *globerr;
21 extern	char **glob();
22 extern	short gflag;
23 
24 /*
25  * Connect to peer server and
26  * auto-login, if possible.
27  */
28 setpeer(argc, argv)
29 	int argc;
30 	char *argv[];
31 {
32 	struct hostent *host, *hookup();
33 	int port;
34 
35 	if (connected) {
36 		printf("Already connected to %s, use disconnect first.\n",
37 			hostname);
38 		return;
39 	}
40 	if (argc < 2) {
41 		strcat(line, " ");
42 		printf("(to) ");
43 		gets(&line[strlen(line)]);
44 		makeargv();
45 		argc = margc;
46 		argv = margv;
47 	}
48 	if (argc > 3) {
49 		printf("usage: %s host-name [port]\n", argv[0]);
50 		return;
51 	}
52 	port = sp->s_port;
53 	if (argc > 2) {
54 		port = atoi(argv[2]);
55 		if (port <= 0) {
56 			printf("%s: bad port number-- %s\n", argv[1], argv[2]);
57 			printf ("usage: %s host-name [port]\n", argv[0]);
58 			return;
59 		}
60 		port = htons(port);
61 	}
62 	host = hookup(argv[1], port);
63 	if (host) {
64 		connected = 1;
65 		if (autologin)
66 			login(host);
67 	}
68 }
69 
70 struct	types {
71 	char	*t_name;
72 	char	*t_mode;
73 	int	t_type;
74 	char	*t_arg;
75 } types[] = {
76 	{ "ascii",	"A",	TYPE_A,	0 },
77 	{ "binary",	"I",	TYPE_I,	0 },
78 	{ "image",	"I",	TYPE_I,	0 },
79 	{ "ebcdic",	"E",	TYPE_E,	0 },
80 	{ "tenex",	"L",	TYPE_L,	bytename },
81 	0
82 };
83 
84 /*
85  * Set transfer type.
86  */
87 settype(argc, argv)
88 	char *argv[];
89 {
90 	register struct types *p;
91 	int comret;
92 
93 	if (argc > 2) {
94 		char *sep;
95 
96 		printf("usage: %s [", argv[0]);
97 		sep = " ";
98 		for (p = types; p->t_name; p++) {
99 			printf("%s%s", sep, p->t_name);
100 			if (*sep == ' ')
101 				sep = " | ";
102 		}
103 		printf(" ]\n");
104 		return;
105 	}
106 	if (argc < 2) {
107 		printf("Using %s mode to transfer files.\n", typename);
108 		return;
109 	}
110 	for (p = types; p->t_name; p++)
111 		if (strcmp(argv[1], p->t_name) == 0)
112 			break;
113 	if (p->t_name == 0) {
114 		printf("%s: unknown mode\n", argv[1]);
115 		return;
116 	}
117 	if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
118 		comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
119 	else
120 		comret = command("TYPE %s", p->t_mode);
121 	if (comret == COMPLETE) {
122 		strcpy(typename, p->t_name);
123 		type = p->t_type;
124 	}
125 }
126 
127 /*
128  * Set binary transfer type.
129  */
130 /*VARARGS*/
131 setbinary()
132 {
133 
134 	call(settype, "type", "binary", 0);
135 }
136 
137 /*
138  * Set ascii transfer type.
139  */
140 /*VARARGS*/
141 setascii()
142 {
143 
144 	call(settype, "type", "ascii", 0);
145 }
146 
147 /*
148  * Set tenex transfer type.
149  */
150 /*VARARGS*/
151 settenex()
152 {
153 
154 	call(settype, "type", "tenex", 0);
155 }
156 
157 /*
158  * Set ebcdic transfer type.
159  */
160 /*VARARGS*/
161 setebcdic()
162 {
163 
164 	call(settype, "type", "ebcdic", 0);
165 }
166 
167 /*
168  * Set file transfer mode.
169  */
170 setmode(argc, argv)
171 	char *argv[];
172 {
173 
174 	printf("We only support %s mode, sorry.\n", modename);
175 }
176 
177 /*
178  * Set file transfer format.
179  */
180 setform(argc, argv)
181 	char *argv[];
182 {
183 
184 	printf("We only support %s format, sorry.\n", formname);
185 }
186 
187 /*
188  * Set file transfer structure.
189  */
190 setstruct(argc, argv)
191 	char *argv[];
192 {
193 
194 	printf("We only support %s structure, sorry.\n", structname);
195 }
196 
197 /*
198  * Send a single file.
199  */
200 append(argc, argv)
201 	char *argv[];
202 {
203 
204 	return (put1("APPE", argc, argv));
205 }
206 
207 put(argc, argv)
208 	char *argv[];
209 {
210 
211 	return (put1("STOR", argc, argv));
212 }
213 
214 put1(cmd, argc, argv)
215 	char *cmd;
216 	int argc;
217 	char *argv[];
218 {
219 
220 	if (argc == 2)
221 		argc++, argv[2] = argv[1];
222 	if (argc < 2) {
223 		strcat(line, " ");
224 		printf("(local-file) ");
225 		gets(&line[strlen(line)]);
226 		makeargv();
227 		argc = margc;
228 		argv = margv;
229 	}
230 	if (argc < 2) {
231 usage:
232 		printf("%s local-file remote-file\n", argv[0]);
233 		return;
234 	}
235 	if (argc < 3) {
236 		strcat(line, " ");
237 		printf("(remote-file) ");
238 		gets(&line[strlen(line)]);
239 		makeargv();
240 		argc = margc;
241 		argv = margv;
242 	}
243 	if (argc < 3)
244 		goto usage;
245 	if (!globulize(&argv[1]))
246 		return;
247 	sendrequest(cmd, argv[1], argv[2]);
248 }
249 
250 /*
251  * Send one or more files.
252  */
253 mput(argc, argv)
254 	char *argv[];
255 {
256 	char **cpp, **gargs = NULL;
257 	int i;
258 
259 	if (argc < 2) {
260 		strcat(line, " ");
261 		printf("(local-files) ");
262 		gets(&line[strlen(line)]);
263 		makeargv();
264 		argc = margc;
265 		argv = margv;
266 	}
267 	if (argc < 2) {
268 		printf("%s local-files\n", argv[0]);
269 		return;
270 	}
271 	cpp = argv + 1;
272 	if (doglob) {
273 		gargs = glob(cpp);
274 		if (globerr != NULL) {
275 			printf("%s\n", globerr);
276 			if (gargs)
277 				blkfree(gargs);
278 			return;
279 		}
280 	}
281 	if (gargs != NULL)
282 		cpp = gargs;
283 	for (; *cpp != NULL; cpp++)
284 		if (confirm(argv[0], *cpp))
285 			sendrequest("STOR", *cpp, *cpp);
286 	if (gargs != NULL)
287 		blkfree(gargs);
288 }
289 
290 /*
291  * Receive one file.
292  */
293 get(argc, argv)
294 	char *argv[];
295 {
296 
297 	if (argc == 2)
298 		argc++, argv[2] = argv[1];
299 	if (argc < 2) {
300 		strcat(line, " ");
301 		printf("(remote-file) ");
302 		gets(&line[strlen(line)]);
303 		makeargv();
304 		argc = margc;
305 		argv = margv;
306 	}
307 	if (argc < 2) {
308 usage:
309 		printf("%s remote-file [ local-file ]\n", argv[0]);
310 		return;
311 	}
312 	if (argc < 3) {
313 		strcat(line, " ");
314 		printf("(local-file) ");
315 		gets(&line[strlen(line)]);
316 		makeargv();
317 		argc = margc;
318 		argv = margv;
319 	}
320 	if (argc < 3)
321 		goto usage;
322 	if (!globulize(&argv[2]))
323 		return;
324 	recvrequest("RETR", argv[2], argv[1], "w");
325 }
326 
327 /*
328  * Get multiple files.
329  */
330 mget(argc, argv)
331 	char *argv[];
332 {
333 	register char *cp;
334 
335 	if (argc < 2) {
336 		strcat(line, " ");
337 		printf("(remote-directory) ");
338 		gets(&line[strlen(line)]);
339 		makeargv();
340 		argc = margc;
341 		argv = margv;
342 	}
343 	if (argc < 2) {
344 		printf("%s remote-files\n", argv[0]);
345 		return;
346 	}
347 	while ((cp = remglob(argc, argv)) != NULL)
348 		if (confirm(argv[0], cp))
349 			recvrequest("RETR", cp, cp, "w");
350 }
351 
352 char *
353 remglob(argc, argv)
354 	char *argv[];
355 {
356 	char temp[16], *cp;
357 	static char buf[MAXPATHLEN];
358 	static FILE *ftemp = NULL;
359 	static char **args;
360 	int oldverbose;
361 
362 	if (!doglob) {
363 		if (argc == NULL)
364 			args = argv;
365 		if ((cp = *++args) == NULL)
366 			args = NULL;
367 		return (cp);
368 	}
369 	if (ftemp == NULL) {
370 		strcpy(temp, "/tmp/ftpXXXXXX");
371 		mktemp(temp);
372 		oldverbose = verbose, verbose = 0;
373 		recvrequest("NLST", temp, argv[1], "w");
374 		verbose = oldverbose;
375 		ftemp = fopen(temp, "r");
376 		unlink(temp);
377 		if (ftemp == NULL) {
378 			printf("can't find list of remote files, oops\n");
379 			return;
380 		}
381 	}
382 	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
383 		fclose(ftemp), ftemp = NULL;
384 		return (NULL);
385 	}
386 	if ((cp = index(buf, '\n')) != NULL)
387 		*cp = '\0';
388 	return (buf);
389 }
390 
391 char *
392 onoff(bool)
393 	int bool;
394 {
395 
396 	return (bool ? "on" : "off");
397 }
398 
399 /*
400  * Show status.
401  */
402 status(argc, argv)
403 	char *argv[];
404 {
405 
406 	if (connected)
407 		printf("Connected to %s.\n", hostname);
408 	else
409 		printf("Not connected.\n");
410 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
411 		modename, typename, formname, structname);
412 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
413 		onoff(verbose), onoff(bell), onoff(interactive),
414 		onoff(doglob));
415 	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
416 		onoff(hash), onoff(sendport));
417 }
418 
419 /*
420  * Set beep on cmd completed mode.
421  */
422 /*VARARGS*/
423 setbell()
424 {
425 
426 	bell = !bell;
427 	printf("Bell mode %s.\n", onoff(bell));
428 }
429 
430 /*
431  * Turn on packet tracing.
432  */
433 /*VARARGS*/
434 settrace()
435 {
436 
437 	trace = !trace;
438 	printf("Packet tracing %s.\n", onoff(trace));
439 }
440 
441 /*
442  * Toggle hash mark printing during transfers.
443  */
444 /*VARARGS*/
445 sethash()
446 {
447 
448 	hash = !hash;
449 	printf("Hash mark printing %s", onoff(hash));
450 	if (hash)
451 		printf(" (%d bytes/hash mark)", BUFSIZ);
452 	printf(".\n");
453 }
454 
455 /*
456  * Turn on printing of server echo's.
457  */
458 /*VARARGS*/
459 setverbose()
460 {
461 
462 	verbose = !verbose;
463 	printf("Verbose mode %s.\n", onoff(verbose));
464 }
465 
466 /*
467  * Toggle PORT cmd use before each data connection.
468  */
469 /*VARARGS*/
470 setport()
471 {
472 
473 	sendport = !sendport;
474 	printf("Use of PORT cmds %s.\n", onoff(sendport));
475 }
476 
477 /*
478  * Turn on interactive prompting
479  * during mget, mput, and mdelete.
480  */
481 /*VARARGS*/
482 setprompt()
483 {
484 
485 	interactive = !interactive;
486 	printf("Interactive mode %s.\n", onoff(interactive));
487 }
488 
489 /*
490  * Toggle metacharacter interpretation
491  * on local file names.
492  */
493 /*VARARGS*/
494 setglob()
495 {
496 
497 	doglob = !doglob;
498 	printf("Globbing %s.\n", onoff(doglob));
499 }
500 
501 /*
502  * Set debugging mode on/off and/or
503  * set level of debugging.
504  */
505 setdebug(argc, argv)
506 	char *argv[];
507 {
508 	int val;
509 
510 	if (argc > 1) {
511 		val = atoi(argv[1]);
512 		if (val < 0) {
513 			printf("%s: bad debugging value.\n", argv[1]);
514 			return;
515 		}
516 	} else
517 		val = !debug;
518 	debug = val;
519 	if (debug)
520 		options |= SO_DEBUG;
521 	else
522 		options &= ~SO_DEBUG;
523 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
524 }
525 
526 /*
527  * Set current working directory
528  * on remote machine.
529  */
530 cd(argc, argv)
531 	char *argv[];
532 {
533 
534 	if (!connected) {
535 		printf("Not connected.\n");
536 		return;
537 	}
538 	if (argc < 2) {
539 		strcat(line, " ");
540 		printf("(remote-directory) ");
541 		gets(&line[strlen(line)]);
542 		makeargv();
543 		argc = margc;
544 		argv = margv;
545 	}
546 	if (argc < 2) {
547 		printf("%s remote-directory\n", argv[0]);
548 		return;
549 	}
550 	(void) command("CWD %s", argv[1]);
551 }
552 
553 /*
554  * Set current working directory
555  * on local machine.
556  */
557 lcd(argc, argv)
558 	char *argv[];
559 {
560 	char buf[MAXPATHLEN];
561 	extern char *home;
562 
563 	if (argc < 2)
564 		argc++, argv[1] = home;
565 	if (argc != 2) {
566 		printf("%s local-directory\n", argv[0]);
567 		return;
568 	}
569 	if (!globulize(&argv[1]))
570 		return;
571 	if (chdir(argv[1]) < 0) {
572 		perror(argv[1]);
573 		return;
574 	}
575 	printf("Local directory now %s\n", getwd(buf));
576 }
577 
578 /*
579  * Delete a single file.
580  */
581 delete(argc, argv)
582 	char *argv[];
583 {
584 
585 	if (argc < 2) {
586 		strcat(line, " ");
587 		printf("(remote-file) ");
588 		gets(&line[strlen(line)]);
589 		makeargv();
590 		argc = margc;
591 		argv = margv;
592 	}
593 	if (argc < 2) {
594 		printf("%s remote-file\n", argv[0]);
595 		return;
596 	}
597 	(void) command("DELE %s", argv[1]);
598 }
599 
600 /*
601  * Delete multiple files.
602  */
603 mdelete(argc, argv)
604 	char *argv[];
605 {
606 	char *cp;
607 
608 	if (argc < 2) {
609 		strcat(line, " ");
610 		printf("(remote-files) ");
611 		gets(&line[strlen(line)]);
612 		makeargv();
613 		argc = margc;
614 		argv = margv;
615 	}
616 	if (argc < 2) {
617 		printf("%s remote-files\n", argv[0]);
618 		return;
619 	}
620 	while ((cp = remglob(argc, argv)) != NULL)
621 		if (confirm(argv[0], cp))
622 			(void) command("DELE %s", cp);
623 }
624 /*
625  * Rename a remote file.
626  */
627 renamefile(argc, argv)
628 	char *argv[];
629 {
630 
631 	if (argc < 2) {
632 		strcat(line, " ");
633 		printf("(from-name) ");
634 		gets(&line[strlen(line)]);
635 		makeargv();
636 		argc = margc;
637 		argv = margv;
638 	}
639 	if (argc < 2) {
640 usage:
641 		printf("%s from-name to-name\n", argv[0]);
642 		return;
643 	}
644 	if (argc < 3) {
645 		strcat(line, " ");
646 		printf("(to-name) ");
647 		gets(&line[strlen(line)]);
648 		makeargv();
649 		argc = margc;
650 		argv = margv;
651 	}
652 	if (argc < 3)
653 		goto usage;
654 	if (command("RNFR %s", argv[1]) == CONTINUE)
655 		(void) command("RNTO %s", argv[2]);
656 }
657 
658 /*
659  * Get a directory listing
660  * of remote files.
661  */
662 ls(argc, argv)
663 	char *argv[];
664 {
665 	char *cmd, *mode;
666 	int i;
667 
668 	if (argc < 2)
669 		argc++, argv[1] = NULL;
670 	if (argc < 3)
671 		argc++, argv[2] = "-";
672 	cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
673 	if (strcmp(argv[2], "-") && !globulize(&argv[2]))
674 		return;
675 	mode = argc > 3 ? "a" : "w";
676 	for (i = 1; i < argc - 1; i++)
677 		recvrequest(cmd, argv[argc - 1], argv[i], mode);
678 }
679 
680 /*
681  * Do a shell escape
682  */
683 shell(argc, argv)
684 	char *argv[];
685 {
686 
687 	printf("Sorry, this function is unimplemented.\n");
688 }
689 
690 /*
691  * Send new user information (re-login)
692  */
693 user(argc, argv)
694 	int argc;
695 	char **argv;
696 {
697 	char acct[80], *getpass();
698 	int n;
699 
700 	if (argc < 2) {
701 		strcat(line, " ");
702 		printf("(username) ");
703 		gets(&line[strlen(line)]);
704 		makeargv();
705 		argc = margc;
706 		argv = margv;
707 	}
708 	if (argc > 4) {
709 		printf("usage: %s username [password] [account]\n", argv[0]);
710 		return;
711 	}
712 	n = command("USER %s", argv[1]);
713 	if (n == CONTINUE) {
714 		if (argc < 3 )
715 			argv[2] = getpass("Password: "), argc++;
716 		n = command("PASS %s", argv[2]);
717 	}
718 	if (n == CONTINUE) {
719 		if (argc < 4) {
720 			printf("Account: "); (void) fflush(stdout);
721 			(void) fgets(acct, sizeof(acct) - 1, stdin);
722 			acct[strlen(acct) - 1] = '\0';
723 			argv[3] = acct; argc++;
724 		}
725 		n = command("ACCT %s", acct);
726 	}
727 	if (n != COMPLETE) {
728 		fprintf(stderr, "Login failed.\n");
729 		return (0);
730 	}
731 	return (1);
732 }
733 
734 /*
735  * Print working directory.
736  */
737 /*VARARGS*/
738 pwd()
739 {
740 	if (!connected) {
741 		printf("Not connected.\n");
742 		return;
743 	}
744 	(void) command("XPWD");
745 }
746 
747 /*
748  * Make a directory.
749  */
750 makedir(argc, argv)
751 	char *argv[];
752 {
753 
754 	if (argc < 2) {
755 		strcat(line, " ");
756 		printf("(directory-name) ");
757 		gets(&line[strlen(line)]);
758 		makeargv();
759 		argc = margc;
760 		argv = margv;
761 	}
762 	if (argc < 2) {
763 		printf("%s directory-name\n", argv[0]);
764 		return;
765 	}
766 	(void) command("XMKD %s", argv[1]);
767 }
768 
769 /*
770  * Remove a directory.
771  */
772 removedir(argc, argv)
773 	char *argv[];
774 {
775 
776 	if (argc < 2) {
777 		strcat(line, " ");
778 		printf("(directory-name) ");
779 		gets(&line[strlen(line)]);
780 		makeargv();
781 		argc = margc;
782 		argv = margv;
783 	}
784 	if (argc < 2) {
785 		printf("%s directory-name\n", argv[0]);
786 		return;
787 	}
788 	(void) command("XRMD %s", argv[1]);
789 }
790 
791 /*
792  * Send a line, verbatim, to the remote machine.
793  */
794 quote(argc, argv)
795 	char *argv[];
796 {
797 	int i;
798 	char buf[BUFSIZ];
799 
800 	if (argc < 2) {
801 		strcat(line, " ");
802 		printf("(command line to send) ");
803 		gets(&line[strlen(line)]);
804 		makeargv();
805 		argc = margc;
806 		argv = margv;
807 	}
808 	if (argc < 2) {
809 		printf("usage: %s line-to-send\n", argv[0]);
810 		return;
811 	}
812 	strcpy(buf, argv[1]);
813 	for (i = 2; i < argc; i++) {
814 		strcat(buf, " ");
815 		strcat(buf, argv[i]);
816 	}
817 	(void) command(buf);
818 }
819 
820 /*
821  * Ask the other side for help.
822  */
823 rmthelp(argc, argv)
824 	char *argv[];
825 {
826 	int oldverbose = verbose;
827 
828 	verbose = 1;
829 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
830 	verbose = oldverbose;
831 }
832 
833 /*
834  * Terminate session and exit.
835  */
836 /*VARARGS*/
837 quit()
838 {
839 
840 	disconnect();
841 	exit(0);
842 }
843 
844 /*
845  * Terminate session, but don't exit.
846  */
847 disconnect()
848 {
849 	extern FILE *cout;
850 	extern int data;
851 
852 	if (!connected)
853 		return;
854 	(void) command("QUIT");
855 	(void) fclose(cout);
856 	cout = NULL;
857 	connected = 0;
858 	data = -1;
859 }
860 
861 confirm(cmd, file)
862 	char *cmd, *file;
863 {
864 	char line[BUFSIZ];
865 
866 	if (!interactive)
867 		return (1);
868 	printf("%s %s? ", cmd, file);
869 	fflush(stdout);
870 	gets(line);
871 	return (*line != 'n' && *line != 'N');
872 }
873 
874 fatal(msg)
875 	char *msg;
876 {
877 
878 	fprintf(stderr, "ftp: %s\n");
879 	exit(1);
880 }
881 
882 /*
883  * Glob a local file name specification with
884  * the expectation of a single return value.
885  * Can't control multiple values being expanded
886  * from the expression, we return only the first.
887  */
888 globulize(cpp)
889 	char **cpp;
890 {
891 	char **globbed;
892 
893 	if (!doglob)
894 		return (1);
895 	globbed = glob(*cpp);
896 	if (globerr != NULL) {
897 		printf("%s: %s\n", *cpp, globerr);
898 		if (globbed)
899 			blkfree(globbed);
900 		return (0);
901 	}
902 	if (globbed) {
903 		*cpp = *globbed++;
904 		/* don't waste too much memory */
905 		if (*globbed)
906 			blkfree(globbed);
907 	}
908 	return (1);
909 }
910