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