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