Add copyright notice
[unix-history] / usr / src / usr.bin / ftp / cmds.c
CommitLineData
59d0d309 1#ifndef lint
71a655cd 2static char sccsid[] = "@(#)cmds.c 4.11 (Berkeley) %G%";
59d0d309
SL
3#endif
4
5/*
6 * FTP User Program -- Command Routines.
7 */
cf8133c7 8#include <sys/param.h>
59d0d309
SL
9#include <sys/socket.h>
10
62c4a390
SL
11#include <arpa/ftp.h>
12
59d0d309
SL
13#include <signal.h>
14#include <stdio.h>
15#include <errno.h>
16#include <netdb.h>
17
59d0d309
SL
18#include "ftp_var.h"
19
cf8133c7
SL
20extern char *globerr;
21extern char **glob();
9072bd8a 22extern char *home;
cf8133c7 23extern short gflag;
9072bd8a
SL
24extern char *remglob();
25extern char *getenv();
26extern char *index();
27extern char *rindex();
59d0d309
SL
28
29/*
30 * Connect to peer server and
31 * auto-login, if possible.
32 */
33setpeer(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) {
d33c618b 59 port = atoi(argv[2]);
59d0d309 60 if (port <= 0) {
d33c618b
SL
61 printf("%s: bad port number-- %s\n", argv[1], argv[2]);
62 printf ("usage: %s host-name [port]\n", argv[0]);
59d0d309
SL
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
75struct types {
76 char *t_name;
77 char *t_mode;
78 int t_type;
d33c618b 79 char *t_arg;
59d0d309 80} types[] = {
d33c618b
SL
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 },
59d0d309
SL
86 0
87};
88
89/*
90 * Set transfer type.
91 */
92settype(argc, argv)
93 char *argv[];
94{
95 register struct types *p;
d33c618b 96 int comret;
59d0d309
SL
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 }
d33c618b
SL
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) {
59d0d309
SL
127 strcpy(typename, p->t_name);
128 type = p->t_type;
129 }
130}
131
132/*
133 * Set binary transfer type.
134 */
135/*VARARGS*/
136setbinary()
137{
138
139 call(settype, "type", "binary", 0);
140}
141
142/*
143 * Set ascii transfer type.
144 */
145/*VARARGS*/
146setascii()
147{
148
149 call(settype, "type", "ascii", 0);
150}
151
152/*
153 * Set tenex transfer type.
154 */
155/*VARARGS*/
156settenex()
157{
158
159 call(settype, "type", "tenex", 0);
160}
161
162/*
163 * Set ebcdic transfer type.
164 */
165/*VARARGS*/
166setebcdic()
167{
168
169 call(settype, "type", "ebcdic", 0);
170}
171
172/*
173 * Set file transfer mode.
174 */
175setmode(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 */
185setform(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 */
195setstruct(argc, argv)
196 char *argv[];
197{
198
199 printf("We only support %s structure, sorry.\n", structname);
200}
201
71a655cd
RC
202/*
203 * Send a single file.
204 */
59d0d309 205put(argc, argv)
5ac6fc46
SL
206 int argc;
207 char *argv[];
208{
9072bd8a 209 char *cmd;
5ac6fc46 210
59d0d309
SL
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) {
222usage:
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;
cf8133c7
SL
236 if (!globulize(&argv[1]))
237 return;
9072bd8a 238 cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
5ac6fc46 239 sendrequest(cmd, argv[1], argv[2]);
59d0d309
SL
240}
241
242/*
9072bd8a 243 * Send multiple files.
cf8133c7
SL
244 */
245mput(argc, argv)
246 char *argv[];
247{
614e24b6 248 register int i;
cf8133c7 249
5ac6fc46
SL
250 if (argc < 2) {
251 strcat(line, " ");
252 printf("(local-files) ");
253 gets(&line[strlen(line)]);
254 makeargv();
255 argc = margc;
256 argv = margv;
cf8133c7
SL
257 }
258 if (argc < 2) {
cf8133c7
SL
259 printf("%s local-files\n", argv[0]);
260 return;
261 }
614e24b6
SL
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]);
cf8133c7 271 if (globerr != NULL) {
5ac6fc46
SL
272 printf("%s\n", globerr);
273 if (gargs)
274 blkfree(gargs);
614e24b6 275 continue;
cf8133c7 276 }
614e24b6
SL
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);
cf8133c7
SL
282 }
283}
284
285/*
286 * Receive one file.
59d0d309
SL
287 */
288get(argc, argv)
289 char *argv[];
290{
59d0d309 291
59d0d309
SL
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) {
303usage:
cf8133c7 304 printf("%s remote-file [ local-file ]\n", argv[0]);
59d0d309
SL
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;
cf8133c7
SL
317 if (!globulize(&argv[2]))
318 return;
5ac6fc46 319 recvrequest("RETR", argv[2], argv[1], "w");
59d0d309
SL
320}
321
cf8133c7
SL
322/*
323 * Get multiple files.
324 */
325mget(argc, argv)
326 char *argv[];
327{
9072bd8a 328 char *cp;
cf8133c7 329
cf8133c7
SL
330 if (argc < 2) {
331 strcat(line, " ");
9072bd8a 332 printf("(remote-files) ");
cf8133c7
SL
333 gets(&line[strlen(line)]);
334 makeargv();
335 argc = margc;
336 argv = margv;
337 }
338 if (argc < 2) {
5ac6fc46 339 printf("%s remote-files\n", argv[0]);
cf8133c7
SL
340 return;
341 }
5ac6fc46
SL
342 while ((cp = remglob(argc, argv)) != NULL)
343 if (confirm(argv[0], cp))
344 recvrequest("RETR", cp, cp, "w");
345}
cf8133c7 346
5ac6fc46
SL
347char *
348remglob(argc, argv)
349 char *argv[];
350{
9072bd8a 351 char temp[16];
5ac6fc46
SL
352 static char buf[MAXPATHLEN];
353 static FILE *ftemp = NULL;
354 static char **args;
614e24b6 355 int oldverbose, oldhash;
9072bd8a 356 char *cp, *mode;
5ac6fc46
SL
357
358 if (!doglob) {
9072bd8a 359 if (args == NULL)
5ac6fc46
SL
360 args = argv;
361 if ((cp = *++args) == NULL)
362 args = NULL;
363 return (cp);
cf8133c7 364 }
cf8133c7 365 if (ftemp == NULL) {
5ac6fc46
SL
366 strcpy(temp, "/tmp/ftpXXXXXX");
367 mktemp(temp);
368 oldverbose = verbose, verbose = 0;
614e24b6 369 oldhash = hash, hash = 0;
9072bd8a
SL
370 for (mode = "w"; *++argv != NULL; mode = "a")
371 recvrequest ("NLST", temp, *argv, mode);
614e24b6 372 verbose = oldverbose; hash = oldhash;
5ac6fc46
SL
373 ftemp = fopen(temp, "r");
374 unlink(temp);
375 if (ftemp == NULL) {
376 printf("can't find list of remote files, oops\n");
9072bd8a 377 return (NULL);
5ac6fc46 378 }
cf8133c7 379 }
5ac6fc46
SL
380 if (fgets(buf, sizeof (buf), ftemp) == NULL) {
381 fclose(ftemp), ftemp = NULL;
382 return (NULL);
cf8133c7 383 }
5ac6fc46
SL
384 if ((cp = index(buf, '\n')) != NULL)
385 *cp = '\0';
386 return (buf);
cf8133c7
SL
387}
388
59d0d309
SL
389char *
390onoff(bool)
391 int bool;
392{
393
394 return (bool ? "on" : "off");
395}
396
397/*
398 * Show status.
399 */
400status(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);
cf8133c7
SL
410 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n",
411 onoff(verbose), onoff(bell), onoff(interactive),
412 onoff(doglob));
7136ef0a
SL
413 printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
414 onoff(hash), onoff(sendport));
59d0d309
SL
415}
416
417/*
418 * Set beep on cmd completed mode.
419 */
420/*VARARGS*/
421setbell()
422{
423
424 bell = !bell;
425 printf("Bell mode %s.\n", onoff(bell));
426}
427
428/*
429 * Turn on packet tracing.
430 */
431/*VARARGS*/
432settrace()
433{
434
435 trace = !trace;
436 printf("Packet tracing %s.\n", onoff(trace));
437}
438
5ac6fc46
SL
439/*
440 * Toggle hash mark printing during transfers.
441 */
442/*VARARGS*/
443sethash()
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
59d0d309
SL
453/*
454 * Turn on printing of server echo's.
455 */
456/*VARARGS*/
457setverbose()
458{
459
460 verbose = !verbose;
461 printf("Verbose mode %s.\n", onoff(verbose));
462}
463
5ac6fc46
SL
464/*
465 * Toggle PORT cmd use before each data connection.
466 */
467/*VARARGS*/
468setport()
469{
470
471 sendport = !sendport;
472 printf("Use of PORT cmds %s.\n", onoff(sendport));
473}
474
59d0d309
SL
475/*
476 * Turn on interactive prompting
477 * during mget, mput, and mdelete.
478 */
479/*VARARGS*/
480setprompt()
481{
482
483 interactive = !interactive;
484 printf("Interactive mode %s.\n", onoff(interactive));
485}
486
cf8133c7
SL
487/*
488 * Toggle metacharacter interpretation
489 * on local file names.
490 */
491/*VARARGS*/
492setglob()
493{
494
495 doglob = !doglob;
496 printf("Globbing %s.\n", onoff(doglob));
497}
498
59d0d309
SL
499/*
500 * Set debugging mode on/off and/or
501 * set level of debugging.
502 */
9072bd8a 503/*VARARGS*/
59d0d309
SL
504setdebug(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 */
529cd(argc, argv)
530 char *argv[];
531{
532
59d0d309
SL
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
59d0d309
SL
548/*
549 * Set current working directory
550 * on local machine.
551 */
552lcd(argc, argv)
553 char *argv[];
554{
cf8133c7 555 char buf[MAXPATHLEN];
59d0d309 556
cf8133c7
SL
557 if (argc < 2)
558 argc++, argv[1] = home;
59d0d309
SL
559 if (argc != 2) {
560 printf("%s local-directory\n", argv[0]);
561 return;
562 }
cf8133c7
SL
563 if (!globulize(&argv[1]))
564 return;
565 if (chdir(argv[1]) < 0) {
59d0d309 566 perror(argv[1]);
cf8133c7
SL
567 return;
568 }
569 printf("Local directory now %s\n", getwd(buf));
59d0d309
SL
570}
571
572/*
573 * Delete a single file.
574 */
575delete(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
5ac6fc46
SL
594/*
595 * Delete multiple files.
596 */
597mdelete(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}
9072bd8a 618
59d0d309
SL
619/*
620 * Rename a remote file.
621 */
622renamefile(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) {
635usage:
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 */
657ls(argc, argv)
658 char *argv[];
659{
9072bd8a 660 char *cmd;
59d0d309
SL
661
662 if (argc < 2)
663 argc++, argv[1] = NULL;
664 if (argc < 3)
665 argc++, argv[2] = "-";
9072bd8a
SL
666 if (argc > 3) {
667 printf("usage: %s remote-directory local-file\n", argv[0]);
668 return;
669 }
59d0d309 670 cmd = argv[0][0] == 'l' ? "NLST" : "LIST";
cf8133c7
SL
671 if (strcmp(argv[2], "-") && !globulize(&argv[2]))
672 return;
9072bd8a
SL
673 recvrequest(cmd, argv[2], argv[1], "w");
674}
675
676/*
677 * Get a directory listing
678 * of multiple remote files.
679 */
680mls(argc, argv)
681 char *argv[];
682{
614e24b6 683 char *cmd, *mode, *cp, *dest;
9072bd8a 684
614e24b6
SL
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, "-"))
ee87b73e 708 if (!globulize(&dest) || !confirm("local-file", dest))
9072bd8a 709 return;
614e24b6
SL
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);
59d0d309
SL
714}
715
716/*
717 * Do a shell escape
718 */
719shell(argc, argv)
720 char *argv[];
721{
9072bd8a
SL
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);
59d0d309
SL
782}
783
784/*
785 * Send new user information (re-login)
786 */
787user(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]);
9072bd8a 804 return (0);
59d0d309
SL
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*/
832pwd()
833{
9072bd8a 834
59d0d309
SL
835 (void) command("XPWD");
836}
837
838/*
839 * Make a directory.
840 */
841makedir(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 */
863removedir(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 */
885quote(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 */
914rmthelp(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*/
928quit()
929{
930
71a655cd
RC
931 if (connected)
932 disconnect();
59d0d309
SL
933 exit(0);
934}
935
936/*
937 * Terminate session, but don't exit.
938 */
939disconnect()
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}
cf8133c7 952
5ac6fc46 953confirm(cmd, file)
cf8133c7
SL
954 char *cmd, *file;
955{
956 char line[BUFSIZ];
957
958 if (!interactive)
5ac6fc46 959 return (1);
cf8133c7
SL
960 printf("%s %s? ", cmd, file);
961 fflush(stdout);
962 gets(line);
5ac6fc46 963 return (*line != 'n' && *line != 'N');
cf8133c7
SL
964}
965
966fatal(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 */
980globulize(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}