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