xref: /csrg-svn/usr.bin/ftp/cmds.c (revision 25908)
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.3 (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 	char *oldargv1;
217 
218 	if (argc == 2)
219 		argc++, argv[2] = argv[1];
220 	if (argc < 2) {
221 		strcat(line, " ");
222 		printf("(local-file) ");
223 		gets(&line[strlen(line)]);
224 		makeargv();
225 		argc = margc;
226 		argv = margv;
227 	}
228 	if (argc < 2) {
229 usage:
230 		printf("%s local-file remote-file\n", argv[0]);
231 		return;
232 	}
233 	if (argc < 3) {
234 		strcat(line, " ");
235 		printf("(remote-file) ");
236 		gets(&line[strlen(line)]);
237 		makeargv();
238 		argc = margc;
239 		argv = margv;
240 	}
241 	if (argc < 3)
242 		goto usage;
243 	oldargv1 = argv[1];
244 	if (!globulize(&argv[1]))
245 		return;
246 	/*
247 	 * If "globulize" modifies argv[1], and argv[2] is a copy of
248 	 * the old argv[1], make it a copy of the new argv[1].
249 	 */
250 	if (argv[1] != oldargv1 && argv[2] == oldargv1)
251 		argv[2] = argv[1];
252 	cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
253 	sendrequest(cmd, argv[1], argv[2]);
254 }
255 
256 /*
257  * Send multiple files.
258  */
259 mput(argc, argv)
260 	char *argv[];
261 {
262 	register int i;
263 
264 	if (argc < 2) {
265 		strcat(line, " ");
266 		printf("(local-files) ");
267 		gets(&line[strlen(line)]);
268 		makeargv();
269 		argc = margc;
270 		argv = margv;
271 	}
272 	if (argc < 2) {
273 		printf("%s local-files\n", argv[0]);
274 		return;
275 	}
276 	for (i = 1; i < argc; i++) {
277 		register char **cpp, **gargs;
278 
279 		if (!doglob) {
280 			if (confirm(argv[0], argv[i]))
281 				sendrequest("STOR", argv[i], argv[i]);
282 			continue;
283 		}
284 		gargs = glob(argv[i]);
285 		if (globerr != NULL) {
286 			printf("%s\n", globerr);
287 			if (gargs)
288 				blkfree(gargs);
289 			continue;
290 		}
291 		for (cpp = gargs; cpp && *cpp != NULL; cpp++)
292 			if (confirm(argv[0], *cpp))
293 				sendrequest("STOR", *cpp, *cpp);
294 		if (gargs != NULL)
295 			blkfree(gargs);
296 	}
297 }
298 
299 /*
300  * Receive one file.
301  */
302 get(argc, argv)
303 	char *argv[];
304 {
305 
306 	if (argc == 2)
307 		argc++, argv[2] = argv[1];
308 	if (argc < 2) {
309 		strcat(line, " ");
310 		printf("(remote-file) ");
311 		gets(&line[strlen(line)]);
312 		makeargv();
313 		argc = margc;
314 		argv = margv;
315 	}
316 	if (argc < 2) {
317 usage:
318 		printf("%s remote-file [ local-file ]\n", argv[0]);
319 		return;
320 	}
321 	if (argc < 3) {
322 		strcat(line, " ");
323 		printf("(local-file) ");
324 		gets(&line[strlen(line)]);
325 		makeargv();
326 		argc = margc;
327 		argv = margv;
328 	}
329 	if (argc < 3)
330 		goto usage;
331 	if (!globulize(&argv[2]))
332 		return;
333 	recvrequest("RETR", argv[2], argv[1], "w");
334 }
335 
336 /*
337  * Get multiple files.
338  */
339 mget(argc, argv)
340 	char *argv[];
341 {
342 	char *cp;
343 
344 	if (argc < 2) {
345 		strcat(line, " ");
346 		printf("(remote-files) ");
347 		gets(&line[strlen(line)]);
348 		makeargv();
349 		argc = margc;
350 		argv = margv;
351 	}
352 	if (argc < 2) {
353 		printf("%s remote-files\n", argv[0]);
354 		return;
355 	}
356 	while ((cp = remglob(argc, argv)) != NULL)
357 		if (confirm(argv[0], cp))
358 			recvrequest("RETR", cp, cp, "w");
359 }
360 
361 char *
362 remglob(argc, argv)
363 	char *argv[];
364 {
365 	char temp[16];
366 	static char buf[MAXPATHLEN];
367 	static FILE *ftemp = NULL;
368 	static char **args;
369 	int oldverbose, oldhash;
370 	char *cp, *mode;
371 
372 	if (!doglob) {
373 		if (args == NULL)
374 			args = argv;
375 		if ((cp = *++args) == NULL)
376 			args = NULL;
377 		return (cp);
378 	}
379 	if (ftemp == NULL) {
380 		strcpy(temp, "/tmp/ftpXXXXXX");
381 		mktemp(temp);
382 		oldverbose = verbose, verbose = 0;
383 		oldhash = hash, hash = 0;
384 		for (mode = "w"; *++argv != NULL; mode = "a")
385 			recvrequest ("NLST", temp, *argv, mode);
386 		verbose = oldverbose; hash = oldhash;
387 		ftemp = fopen(temp, "r");
388 		unlink(temp);
389 		if (ftemp == NULL) {
390 			printf("can't find list of remote files, oops\n");
391 			return (NULL);
392 		}
393 	}
394 	if (fgets(buf, sizeof (buf), ftemp) == NULL) {
395 		fclose(ftemp), ftemp = NULL;
396 		return (NULL);
397 	}
398 	if ((cp = index(buf, '\n')) != NULL)
399 		*cp = '\0';
400 	return (buf);
401 }
402 
403 char *
404 onoff(bool)
405 	int bool;
406 {
407 
408 	return (bool ? "on" : "off");
409 }
410 
411 /*
412  * Show status.
413  */
414 status(argc, argv)
415 	char *argv[];
416 {
417 
418 	if (connected)
419 		printf("Connected to %s.\n", hostname);
420 	else
421 		printf("Not connected.\n");
422 	printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
423 		modename, typename, formname, structname);
424 	printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
425 		onoff(verbose), onoff(bell), onoff(interactive),
426 		onoff(doglob));
427 	printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
428 		onoff(hash), onoff(sendport));
429 }
430 
431 /*
432  * Set beep on cmd completed mode.
433  */
434 /*VARARGS*/
435 setbell()
436 {
437 
438 	bell = !bell;
439 	printf("Bell mode %s.\n", onoff(bell));
440 }
441 
442 /*
443  * Turn on packet tracing.
444  */
445 /*VARARGS*/
446 settrace()
447 {
448 
449 	trace = !trace;
450 	printf("Packet tracing %s.\n", onoff(trace));
451 }
452 
453 /*
454  * Toggle hash mark printing during transfers.
455  */
456 /*VARARGS*/
457 sethash()
458 {
459 
460 	hash = !hash;
461 	printf("Hash mark printing %s", onoff(hash));
462 	if (hash)
463 		printf(" (%d bytes/hash mark)", BUFSIZ);
464 	printf(".\n");
465 }
466 
467 /*
468  * Turn on printing of server echo's.
469  */
470 /*VARARGS*/
471 setverbose()
472 {
473 
474 	verbose = !verbose;
475 	printf("Verbose mode %s.\n", onoff(verbose));
476 }
477 
478 /*
479  * Toggle PORT cmd use before each data connection.
480  */
481 /*VARARGS*/
482 setport()
483 {
484 
485 	sendport = !sendport;
486 	printf("Use of PORT cmds %s.\n", onoff(sendport));
487 }
488 
489 /*
490  * Turn on interactive prompting
491  * during mget, mput, and mdelete.
492  */
493 /*VARARGS*/
494 setprompt()
495 {
496 
497 	interactive = !interactive;
498 	printf("Interactive mode %s.\n", onoff(interactive));
499 }
500 
501 /*
502  * Toggle metacharacter interpretation
503  * on local file names.
504  */
505 /*VARARGS*/
506 setglob()
507 {
508 
509 	doglob = !doglob;
510 	printf("Globbing %s.\n", onoff(doglob));
511 }
512 
513 /*
514  * Set debugging mode on/off and/or
515  * set level of debugging.
516  */
517 /*VARARGS*/
518 setdebug(argc, argv)
519 	char *argv[];
520 {
521 	int val;
522 
523 	if (argc > 1) {
524 		val = atoi(argv[1]);
525 		if (val < 0) {
526 			printf("%s: bad debugging value.\n", argv[1]);
527 			return;
528 		}
529 	} else
530 		val = !debug;
531 	debug = val;
532 	if (debug)
533 		options |= SO_DEBUG;
534 	else
535 		options &= ~SO_DEBUG;
536 	printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
537 }
538 
539 /*
540  * Set current working directory
541  * on remote machine.
542  */
543 cd(argc, argv)
544 	char *argv[];
545 {
546 
547 	if (argc < 2) {
548 		strcat(line, " ");
549 		printf("(remote-directory) ");
550 		gets(&line[strlen(line)]);
551 		makeargv();
552 		argc = margc;
553 		argv = margv;
554 	}
555 	if (argc < 2) {
556 		printf("%s remote-directory\n", argv[0]);
557 		return;
558 	}
559 	(void) command("CWD %s", argv[1]);
560 }
561 
562 /*
563  * Set current working directory
564  * on local machine.
565  */
566 lcd(argc, argv)
567 	char *argv[];
568 {
569 	char buf[MAXPATHLEN];
570 
571 	if (argc < 2)
572 		argc++, argv[1] = home;
573 	if (argc != 2) {
574 		printf("%s local-directory\n", argv[0]);
575 		return;
576 	}
577 	if (!globulize(&argv[1]))
578 		return;
579 	if (chdir(argv[1]) < 0) {
580 		perror(argv[1]);
581 		return;
582 	}
583 	printf("Local directory now %s\n", getwd(buf));
584 }
585 
586 /*
587  * Delete a single file.
588  */
589 delete(argc, argv)
590 	char *argv[];
591 {
592 
593 	if (argc < 2) {
594 		strcat(line, " ");
595 		printf("(remote-file) ");
596 		gets(&line[strlen(line)]);
597 		makeargv();
598 		argc = margc;
599 		argv = margv;
600 	}
601 	if (argc < 2) {
602 		printf("%s remote-file\n", argv[0]);
603 		return;
604 	}
605 	(void) command("DELE %s", argv[1]);
606 }
607 
608 /*
609  * Delete multiple files.
610  */
611 mdelete(argc, argv)
612 	char *argv[];
613 {
614 	char *cp;
615 
616 	if (argc < 2) {
617 		strcat(line, " ");
618 		printf("(remote-files) ");
619 		gets(&line[strlen(line)]);
620 		makeargv();
621 		argc = margc;
622 		argv = margv;
623 	}
624 	if (argc < 2) {
625 		printf("%s remote-files\n", argv[0]);
626 		return;
627 	}
628 	while ((cp = remglob(argc, argv)) != NULL)
629 		if (confirm(argv[0], cp))
630 			(void) command("DELE %s", cp);
631 }
632 
633 /*
634  * Rename a remote file.
635  */
636 renamefile(argc, argv)
637 	char *argv[];
638 {
639 
640 	if (argc < 2) {
641 		strcat(line, " ");
642 		printf("(from-name) ");
643 		gets(&line[strlen(line)]);
644 		makeargv();
645 		argc = margc;
646 		argv = margv;
647 	}
648 	if (argc < 2) {
649 usage:
650 		printf("%s from-name to-name\n", argv[0]);
651 		return;
652 	}
653 	if (argc < 3) {
654 		strcat(line, " ");
655 		printf("(to-name) ");
656 		gets(&line[strlen(line)]);
657 		makeargv();
658 		argc = margc;
659 		argv = margv;
660 	}
661 	if (argc < 3)
662 		goto usage;
663 	if (command("RNFR %s", argv[1]) == CONTINUE)
664 		(void) command("RNTO %s", argv[2]);
665 }
666 
667 /*
668  * Get a directory listing
669  * of remote files.
670  */
671 ls(argc, argv)
672 	char *argv[];
673 {
674 	char *cmd;
675 
676 	if (argc < 2)
677 		argc++, argv[1] = NULL;
678 	if (argc < 3)
679 		argc++, argv[2] = "-";
680 	if (argc > 3) {
681 		printf("usage: %s remote-directory local-file\n", argv[0]);
682 		return;
683 	}
684 	cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
685 	if (strcmp(argv[2], "-") && !globulize(&argv[2]))
686 		return;
687 	recvrequest(cmd, argv[2], argv[1], "w");
688 }
689 
690 /*
691  * Get a directory listing
692  * of multiple remote files.
693  */
694 mls(argc, argv)
695 	char *argv[];
696 {
697 	char *cmd, *mode, *cp, *dest;
698 
699 	if (argc < 2) {
700 		strcat(line, " ");
701 		printf("(remote-files) ");
702 		gets(&line[strlen(line)]);
703 		makeargv();
704 		argc = margc;
705 		argv = margv;
706 	}
707 	if (argc < 3) {
708 		strcat(line, " ");
709 		printf("(local-file) ");
710 		gets(&line[strlen(line)]);
711 		makeargv();
712 		argc = margc;
713 		argv = margv;
714 	}
715 	if (argc < 3) {
716 		printf("%s remote-files local-file\n", argv[0]);
717 		return;
718 	}
719 	dest = argv[argc - 1];
720 	argv[argc - 1] = NULL;
721 	if (strcmp(dest, "-"))
722 		if (!globulize(&dest) || !confirm("local-file", dest))
723 			return;
724 	cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
725 	for (mode = "w"; cp = remglob(argc, argv); mode = "a")
726 		if (confirm(argv[0], cp))
727 			recvrequest(cmd, dest, cp, mode);
728 }
729 
730 /*
731  * Do a shell escape
732  */
733 shell(argc, argv)
734 	char *argv[];
735 {
736 	int pid, status, (*old1)(), (*old2)();
737 	char shellnam[40], *shell, *namep;
738 	char **cpp, **gargs;
739 
740 	old1 = signal (SIGINT, SIG_IGN);
741 	old2 = signal (SIGQUIT, SIG_IGN);
742 	if ((pid = fork()) == 0) {
743 		for (pid = 3; pid < 20; pid++)
744 			close(pid);
745 		signal(SIGINT, SIG_DFL);
746 		signal(SIGQUIT, SIG_DFL);
747 		shell = getenv("SHELL");
748 		if (shell == NULL)
749 			shell = "/bin/sh";
750 		namep = rindex(shell,'/');
751 		if (namep == NULL)
752 			namep = shell;
753 		if (argc <= 1) {
754 			if (debug) {
755 				printf ("%s\n", shell);
756 				fflush (stdout);
757 			}
758 			execl(shell, shell, (char *)0);
759 		} else {
760 			char *args[4];	/* "sh" "-c" <command> NULL */
761 
762 			args[0] = shell;
763 			args[1] = "-c";
764 			args[2] = argv[1];
765 			args[3] = NULL;
766 			if (debug) {
767 				printf("%s -c %s\n", shell, argv[1]);
768 				fflush(stdout);
769 			}
770 			execv(shell, args);
771 		}
772 		perror(shell);
773 		exit(1);
774 	}
775 	if (pid > 0)
776 		while (wait(&status) != pid)
777 			;
778 	signal(SIGINT, old1);
779 	signal(SIGQUIT, old2);
780 	if (pid == -1)
781 		perror("Try again later");
782 	return (0);
783 }
784 
785 /*
786  * Send new user information (re-login)
787  */
788 user(argc, argv)
789 	int argc;
790 	char **argv;
791 {
792 	char acct[80], *getpass();
793 	int n;
794 
795 	if (argc < 2) {
796 		strcat(line, " ");
797 		printf("(username) ");
798 		gets(&line[strlen(line)]);
799 		makeargv();
800 		argc = margc;
801 		argv = margv;
802 	}
803 	if (argc > 4) {
804 		printf("usage: %s username [password] [account]\n", argv[0]);
805 		return (0);
806 	}
807 	n = command("USER %s", argv[1]);
808 	if (n == CONTINUE) {
809 		if (argc < 3 )
810 			argv[2] = getpass("Password: "), argc++;
811 		n = command("PASS %s", argv[2]);
812 	}
813 	if (n == CONTINUE) {
814 		if (argc < 4) {
815 			printf("Account: "); (void) fflush(stdout);
816 			(void) fgets(acct, sizeof(acct) - 1, stdin);
817 			acct[strlen(acct) - 1] = '\0';
818 			argv[3] = acct; argc++;
819 		}
820 		n = command("ACCT %s", acct);
821 	}
822 	if (n != COMPLETE) {
823 		fprintf(stderr, "Login failed.\n");
824 		return (0);
825 	}
826 	return (1);
827 }
828 
829 /*
830  * Print working directory.
831  */
832 /*VARARGS*/
833 pwd()
834 {
835 
836 	(void) command("XPWD");
837 }
838 
839 /*
840  * Make a directory.
841  */
842 makedir(argc, argv)
843 	char *argv[];
844 {
845 
846 	if (argc < 2) {
847 		strcat(line, " ");
848 		printf("(directory-name) ");
849 		gets(&line[strlen(line)]);
850 		makeargv();
851 		argc = margc;
852 		argv = margv;
853 	}
854 	if (argc < 2) {
855 		printf("%s directory-name\n", argv[0]);
856 		return;
857 	}
858 	(void) command("XMKD %s", argv[1]);
859 }
860 
861 /*
862  * Remove a directory.
863  */
864 removedir(argc, argv)
865 	char *argv[];
866 {
867 
868 	if (argc < 2) {
869 		strcat(line, " ");
870 		printf("(directory-name) ");
871 		gets(&line[strlen(line)]);
872 		makeargv();
873 		argc = margc;
874 		argv = margv;
875 	}
876 	if (argc < 2) {
877 		printf("%s directory-name\n", argv[0]);
878 		return;
879 	}
880 	(void) command("XRMD %s", argv[1]);
881 }
882 
883 /*
884  * Send a line, verbatim, to the remote machine.
885  */
886 quote(argc, argv)
887 	char *argv[];
888 {
889 	int i;
890 	char buf[BUFSIZ];
891 
892 	if (argc < 2) {
893 		strcat(line, " ");
894 		printf("(command line to send) ");
895 		gets(&line[strlen(line)]);
896 		makeargv();
897 		argc = margc;
898 		argv = margv;
899 	}
900 	if (argc < 2) {
901 		printf("usage: %s line-to-send\n", argv[0]);
902 		return;
903 	}
904 	strcpy(buf, argv[1]);
905 	for (i = 2; i < argc; i++) {
906 		strcat(buf, " ");
907 		strcat(buf, argv[i]);
908 	}
909 	(void) command(buf);
910 }
911 
912 /*
913  * Ask the other side for help.
914  */
915 rmthelp(argc, argv)
916 	char *argv[];
917 {
918 	int oldverbose = verbose;
919 
920 	verbose = 1;
921 	(void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
922 	verbose = oldverbose;
923 }
924 
925 /*
926  * Terminate session and exit.
927  */
928 /*VARARGS*/
929 quit()
930 {
931 
932 	if (connected)
933 		disconnect();
934 	exit(0);
935 }
936 
937 /*
938  * Terminate session, but don't exit.
939  */
940 disconnect()
941 {
942 	extern FILE *cout;
943 	extern int data;
944 
945 	if (!connected)
946 		return;
947 	(void) command("QUIT");
948 	(void) fclose(cout);
949 	cout = NULL;
950 	connected = 0;
951 	data = -1;
952 }
953 
954 confirm(cmd, file)
955 	char *cmd, *file;
956 {
957 	char line[BUFSIZ];
958 
959 	if (!interactive)
960 		return (1);
961 	printf("%s %s? ", cmd, file);
962 	fflush(stdout);
963 	gets(line);
964 	return (*line != 'n' && *line != 'N');
965 }
966 
967 fatal(msg)
968 	char *msg;
969 {
970 
971 	fprintf(stderr, "ftp: %s\n");
972 	exit(1);
973 }
974 
975 /*
976  * Glob a local file name specification with
977  * the expectation of a single return value.
978  * Can't control multiple values being expanded
979  * from the expression, we return only the first.
980  */
981 globulize(cpp)
982 	char **cpp;
983 {
984 	char **globbed;
985 
986 	if (!doglob)
987 		return (1);
988 	globbed = glob(*cpp);
989 	if (globerr != NULL) {
990 		printf("%s: %s\n", *cpp, globerr);
991 		if (globbed)
992 			blkfree(globbed);
993 		return (0);
994 	}
995 	if (globbed) {
996 		*cpp = *globbed++;
997 		/* don't waste too much memory */
998 		if (*globbed)
999 			blkfree(globbed);
1000 	}
1001 	return (1);
1002 }
1003