1 /* $FreeBSD: src/usr.bin/ftp/cmds.c,v 1.16.2.3 2002/08/27 09:55:08 yar Exp $ */
2 /* $NetBSD: cmds.c,v 1.30.2.1 1997/11/18 00:58:26 mellon Exp $ */
5 * Copyright (c) 1985, 1989, 1993, 1994
6 * The Regents of the University of California. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 #include <sys/cdefs.h>
40 static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94";
42 __RCSID("$FreeBSD: src/usr.bin/ftp/cmds.c,v 1.16.2.3 2002/08/27 09:55:08 yar Exp $");
43 __RCSID_SOURCE("$NetBSD: cmds.c,v 1.30.2.1 1997/11/18 00:58:26 mellon Exp $");
48 * FTP User Program -- Command Routines.
50 #include <sys/types.h>
51 #include <sys/socket.h>
66 #include "pathnames.h"
78 { "ascii", "A", TYPE_A, 0 },
79 { "binary", "I", TYPE_I, 0 },
80 { "image", "I", TYPE_I, 0 },
81 { "ebcdic", "E", TYPE_E, 0 },
82 { "tenex", "L", TYPE_L, bytename },
100 printf("usage: %s [", argv[0]);
102 for (p = types; p->t_name; p++) {
103 printf("%s%s", sep, p->t_name);
111 printf("Using %s mode to transfer files.\n", typename);
115 for (p = types; p->t_name; p++)
116 if (strcmp(argv[1], p->t_name) == 0)
118 if (p->t_name == 0) {
119 printf("%s: unknown mode.\n", argv[1]);
123 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
124 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
126 comret = command("TYPE %s", p->t_mode);
127 if (comret == COMPLETE) {
128 (void)strcpy(typename, p->t_name);
129 curtype = type = p->t_type;
134 * Internal form of settype; changes current type in use with server
135 * without changing our notion of the type for data transfers.
136 * Used to change to and from ascii for listings.
139 changetype(newtype, show)
143 int comret, oldverbose = verbose;
147 if (newtype == curtype)
149 if (debug == 0 && show == 0)
151 for (p = types; p->t_name; p++)
152 if (newtype == p->t_type)
154 if (p->t_name == 0) {
155 warnx("internal error: unknown type %d.", newtype);
158 if (newtype == TYPE_L && bytename[0] != '\0')
159 comret = command("TYPE %s %s", p->t_mode, bytename);
161 comret = command("TYPE %s", p->t_mode);
162 if (comret == COMPLETE)
164 verbose = oldverbose;
174 * Set binary transfer type.
178 setbinary(argc, argv)
188 * Set ascii transfer type.
202 * Set tenex transfer type.
216 * Set file transfer mode.
220 setftmode(argc, argv)
225 printf("We only support %s mode, sorry.\n", modename);
230 * Set file transfer format.
239 printf("We only support %s format, sorry.\n", formname);
244 * Set file transfer structure.
248 setstruct(argc, argv)
253 printf("We only support %s structure, sorry.\n", structname);
258 * Send a single file.
267 char *oldargv1, *oldargv2;
274 if (argc < 2 && !another(&argc, &argv, "local-file"))
276 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
278 printf("usage: %s local-file [ remote-file ]\n", argv[0]);
284 if (!globulize(&argv[1])) {
289 * If "globulize" modifies argv[1], and argv[2] is a copy of
290 * the old argv[1], make it a copy of the new argv[1].
292 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
295 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
297 argv[2] = dotrans(argv[2]);
299 if (loc && mapflag) {
300 argv[2] = domap(argv[2]);
302 sendrequest(cmd, argv[1], argv[2],
303 argv[1] != oldargv1 || argv[2] != oldargv2);
304 if (oldargv1 != argv[1]) /* free up after globulize() */
309 * Send multiple files.
321 if (argc < 2 && !another(&argc, &argv, "local-files")) {
322 printf("usage: %s local-files\n", argv[0]);
328 oldintr = signal(SIGINT, mabort);
329 (void)setjmp(jabort);
331 char *cp, *tp2, tmpbuf[MAXPATHLEN];
333 while ((cp = remglob(argv, 0, NULL)) != NULL) {
338 if (mflag && confirm(argv[0], cp)) {
341 while (*tp && !islower((unsigned char)*tp)) {
347 while ((*tp2 = *tp) != '\0') {
348 if (isupper((unsigned char)*tp2))
349 *tp2 = tolower((unsigned char)*tp2);
362 sendrequest((sunique) ? "STOU" : "STOR",
363 cp, tp, cp != tp || !interactive);
364 if (!mflag && fromatty) {
365 ointer = interactive;
367 if (confirm("Continue with", "mput")) {
370 interactive = ointer;
374 (void)signal(SIGINT, oldintr);
378 for (i = 1; i < argc; i++) {
384 if (mflag && confirm(argv[0], argv[i])) {
385 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
386 tp = (mapflag) ? domap(tp) : tp;
387 sendrequest((sunique) ? "STOU" : "STOR",
388 argv[i], tp, tp != argv[i] || !interactive);
389 if (!mflag && fromatty) {
390 ointer = interactive;
392 if (confirm("Continue with", "mput")) {
395 interactive = ointer;
401 memset(&gl, 0, sizeof(gl));
402 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
403 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
404 warnx("%s: not found", argv[i]);
408 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
409 if (mflag && confirm(argv[0], *cpp)) {
410 tp = (ntflag) ? dotrans(*cpp) : *cpp;
411 tp = (mapflag) ? domap(tp) : tp;
412 sendrequest((sunique) ? "STOU" : "STOR",
413 *cpp, tp, *cpp != tp || !interactive);
414 if (!mflag && fromatty) {
415 ointer = interactive;
417 if (confirm("Continue with", "mput")) {
420 interactive = ointer;
426 (void)signal(SIGINT, oldintr);
436 (void)getit(argc, argv, 1, "r+w");
445 (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
452 getit(argc, argv, restartit, mode)
460 char *oldargv1, *oldargv2, *globargv2;
467 if (argc < 2 && !another(&argc, &argv, "remote-file"))
469 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
471 printf("usage: %s remote-file [ local-file ]\n", argv[0]);
477 if (!globulize(&argv[2])) {
483 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
485 while (*tp && !islower((unsigned char)*tp)) {
491 while ((*tp2 = *tp) != '\0') {
492 if (isupper((unsigned char)*tp2)) {
493 *tp2 = tolower((unsigned char)*tp2);
502 argv[2] = dotrans(argv[2]);
504 argv[2] = domap(argv[2]);
509 ret = stat(argv[2], &stbuf);
510 if (restartit == 1) {
512 warn("local: %s", argv[2]);
515 restart_point = stbuf.st_size;
520 mtime = remotemodtime(argv[1], 0);
523 if (stbuf.st_mtime >= mtime) {
531 recvrequest("RETR", argv[2], argv[1], mode,
532 argv[1] != oldargv1 || argv[2] != oldargv2, loc);
535 if (oldargv2 != globargv2) /* free up after globulize() */
549 (void)fflush(stdout);
550 if (mflag && fromatty) {
551 ointer = interactive;
555 if (confirm("Continue with", mname)) {
556 interactive = ointer;
560 interactive = ointer;
568 * Get multiple files.
577 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
579 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
580 printf("usage: %s remote-files\n", argv[0]);
586 oldintr = signal(SIGINT, mabort);
587 (void)setjmp(jabort);
588 while ((cp = remglob(argv, proxy, NULL)) != NULL) {
593 if (mflag && confirm(argv[0], cp)) {
596 for (tp2 = tmpbuf; (ch = *tp++) != 0; )
597 *tp2++ = isupper((unsigned char)ch) ?
598 tolower((unsigned char)ch) :
609 recvrequest("RETR", tp, cp, "w",
610 tp != cp || !interactive, 1);
611 if (!mflag && fromatty) {
612 ointer = interactive;
614 if (confirm("Continue with", "mget")) {
617 interactive = ointer;
621 (void)signal(SIGINT, oldintr);
630 return (bool ? "on" : "off");
645 printf("Connected %sto %s.\n",
646 connected == -1 ? "and logged in" : "", hostname);
648 puts("Not connected.");
652 printf("Connected for proxy commands to %s.\n",
656 puts("No proxy connection.");
660 printf("Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
661 *gateserver ? gateserver : "(none)", gateport);
662 printf("Passive mode: %s.\n", onoff(passivemode));
663 printf("Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
664 modename, typename, formname, structname);
665 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
666 onoff(verbose), onoff(bell), onoff(interactive),
668 printf("Store unique: %s; Receive unique: %s.\n", onoff(sunique),
670 printf("Preserve modification times: %s.\n", onoff(preserve));
671 printf("Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
673 printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
676 puts("Ntrans: off.");
679 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
684 printf("Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
685 onoff(hash), mark, onoff(progress));
686 printf("Use of PORT cmds: %s.\n", onoff(sendport));
687 printf("Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
688 (!try_epsv && epsv4) ? " (but disabled for this connection)" : "");
690 printf("Command line editing: %s.\n", onoff(editing));
694 for (i=0; i<macnum; i++) {
695 printf("\t%s\n", macros[i].mac_name);
705 togglevar(argc, argv, var, mesg)
713 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
715 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
718 printf("usage: %s [ on | off ]\n", argv[0]);
722 printf("%s %s.\n", mesg, onoff(*var));
727 * Set beep on cmd completed mode.
736 code = togglevar(argc, argv, &bell, "Bell mode");
741 * Set command line editing
750 code = togglevar(argc, argv, &editing, "Editing mode");
756 * Turn on packet tracing.
765 code = togglevar(argc, argv, &trace, "Packet tracing");
769 * Toggle hash mark printing during transfers, or set hash mark bytecount.
779 else if (argc != 2) {
780 printf("usage: %s [ on | off | bytecount ]\n", argv[0]);
783 } else if (strcasecmp(argv[1], "on") == 0)
785 else if (strcasecmp(argv[1], "off") == 0)
791 nmark = strtol(argv[1], &ep, 10);
792 if (nmark < 1 || *ep != '\0') {
793 printf("mark: bad bytecount value `%s'.\n", argv[1]);
800 printf("Hash mark printing %s", onoff(hash));
802 printf(" (%d bytes/hash mark)", mark);
808 * Turn on printing of server echo's.
812 setverbose(argc, argv)
817 code = togglevar(argc, argv, &verbose, "Verbose mode");
821 * Toggle PORT cmd use before each data connection.
830 code = togglevar(argc, argv, &sendport, "Use of PORT cmds");
834 * Toggle transfer progress bar.
838 setprogress(argc, argv)
843 code = togglevar(argc, argv, &progress, "Progress bar");
847 * Turn on interactive prompting during mget, mput, and mdelete.
851 setprompt(argc, argv)
856 code = togglevar(argc, argv, &interactive, "Interactive mode");
860 * Toggle gate-ftp mode, or set gate-ftp server
868 static char gsbuf[MAXHOSTNAMELEN];
871 printf("usage: %s [ on | off | gateserver [ port ] ]\n",
875 } else if (argc < 2) {
876 gatemode = !gatemode;
878 if (argc == 2 && strcasecmp(argv[1], "on") == 0)
880 else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
887 port = strtol(argv[2], &ep, 10);
888 if (port < 0 || port > 0xffff || *ep != '\0') {
889 printf("%s: bad gateport value.\n",
894 if (gateport != NULL)
896 asprintf(&gateport, "%ld", port);
898 strncpy(gsbuf, argv[1], sizeof(gsbuf) - 1);
899 gsbuf[sizeof(gsbuf) - 1] = '\0';
904 if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
906 "Disabling gate-ftp mode - no gate-ftp server defined.\n");
909 printf("Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
910 *gateserver ? gateserver : "(none)", gateport);
916 * Toggle metacharacter interpretation on local file names.
925 code = togglevar(argc, argv, &doglob, "Globbing");
929 * Toggle preserving modification times on retrieved files.
933 setpreserve(argc, argv)
938 code = togglevar(argc, argv, &preserve, "Preserve modification times");
942 * Set debugging mode on/off and/or set level of debugging.
951 printf("usage: %s [ on | off | debuglevel ]\n", argv[0]);
954 } else if (argc == 2) {
955 if (strcasecmp(argv[1], "on") == 0)
957 else if (strcasecmp(argv[1], "off") == 0)
963 val = strtol(argv[1], &ep, 10);
964 if (val < 0 || val > INT_MAX || *ep != '\0') {
965 printf("%s: bad debugging value.\n", argv[1]);
976 options &= ~SO_DEBUG;
977 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
982 * Set current working directory on remote machine.
991 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
993 printf("usage: %s remote-directory\n", argv[0]);
997 r = command("CWD %s", argv[1]);
998 if (r == ERROR && code == 500) {
1000 puts("CWD command not recognized, trying XCWD.");
1001 r = command("XCWD %s", argv[1]);
1008 * Set current working directory on local machine.
1015 char buf[MAXPATHLEN];
1019 argc++, argv[1] = home;
1021 printf("usage: %s local-directory\n", argv[0]);
1026 if (!globulize(&argv[1])) {
1030 if (chdir(argv[1]) < 0) {
1031 warn("local: %s", argv[1]);
1034 if (getcwd(buf, sizeof(buf)) != NULL)
1035 printf("Local directory now %s\n", buf);
1037 warn("getcwd: %s", argv[1]);
1040 if (oldargv1 != argv[1]) /* free up after globulize() */
1045 * Delete a single file.
1053 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
1054 printf("usage: %s remote-file\n", argv[0]);
1058 (void)command("DELE %s", argv[1]);
1062 * Delete multiple files.
1073 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1074 printf("usage: %s remote-files\n", argv[0]);
1080 oldintr = signal(SIGINT, mabort);
1081 (void)setjmp(jabort);
1082 while ((cp = remglob(argv, 0, NULL)) != NULL) {
1087 if (mflag && confirm(argv[0], cp)) {
1088 (void)command("DELE %s", cp);
1089 if (!mflag && fromatty) {
1090 ointer = interactive;
1092 if (confirm("Continue with", "mdelete")) {
1095 interactive = ointer;
1099 (void)signal(SIGINT, oldintr);
1104 * Rename a remote file.
1107 renamefile(argc, argv)
1112 if (argc < 2 && !another(&argc, &argv, "from-name"))
1114 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1116 printf("usage: %s from-name to-name\n", argv[0]);
1120 if (command("RNFR %s", argv[1]) == CONTINUE)
1121 (void)command("RNTO %s", argv[2]);
1125 * Get a directory listing of remote files.
1133 char *oldargv2, *globargv2;
1136 argc++, argv[1] = NULL;
1138 argc++, argv[2] = "-";
1140 printf("usage: %s remote-directory local-file\n", argv[0]);
1144 cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST";
1146 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1150 globargv2 = argv[2];
1151 if (strcmp(argv[2], "-") && *argv[2] != '|')
1152 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1157 recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
1159 /* flush results in case commands are coming from a pipe */
1162 if (argv[2] != globargv2) /* free up after globulize() */
1164 if (globargv2 != oldargv2)
1169 * Get a directory listing of multiple remote files.
1179 char mode[1], *dest, *odest;
1181 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1183 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1185 printf("usage: %s remote-files local-file\n", argv[0]);
1189 odest = dest = argv[argc - 1];
1190 argv[argc - 1] = NULL;
1191 if (strcmp(dest, "-") && *dest != '|')
1192 if (!globulize(&dest) ||
1193 !confirm("output to local-file:", dest)) {
1197 dolist = strcmp(argv[0], "mls");
1200 oldintr = signal(SIGINT, mabort);
1201 (void)setjmp(jabort);
1202 for (i = 1; mflag && i < argc-1; ++i) {
1203 *mode = (i == 1) ? 'w' : 'a';
1204 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
1206 if (!mflag && fromatty) {
1207 ointer = interactive;
1209 if (confirm("Continue with", argv[0])) {
1212 interactive = ointer;
1215 (void)signal(SIGINT, oldintr);
1217 if (dest != odest) /* free up after globulize() */
1232 char shellnam[MAXPATHLEN], *shell, *namep;
1235 old1 = signal (SIGINT, SIG_IGN);
1236 old2 = signal (SIGQUIT, SIG_IGN);
1237 if ((pid = fork()) == 0) {
1238 for (pid = 3; pid < 20; pid++)
1240 (void)signal(SIGINT, SIG_DFL);
1241 (void)signal(SIGQUIT, SIG_DFL);
1242 shell = getenv("SHELL");
1244 shell = _PATH_BSHELL;
1245 namep = strrchr(shell, '/');
1249 (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2);
1250 shellnam[sizeof(shellnam) - 1] = '\0';
1251 if (strcmp(namep, "sh") != 0)
1255 (void)fflush(stdout);
1258 execl(shell, shellnam, "-c", altarg, (char *)0);
1261 execl(shell, shellnam, (char *)0);
1268 while (wait(&wait_status) != pid)
1270 (void)signal(SIGINT, old1);
1271 (void)signal(SIGQUIT, old2);
1273 warn("Try again later");
1282 * Send new user information (re-login)
1293 (void)another(&argc, &argv, "username");
1294 if (argc < 2 || argc > 4) {
1295 printf("usage: %s username [password] [account]\n", argv[0]);
1299 n = command("USER %s", argv[1]);
1300 if (n == CONTINUE) {
1302 argv[2] = getpass("Password: "), argc++;
1303 n = command("PASS %s", argv[2]);
1305 if (n == CONTINUE) {
1307 (void)fputs("Account: ", stdout);
1308 (void)fflush(stdout);
1309 (void)fgets(acct, sizeof(acct) - 1, stdin);
1310 acct[strlen(acct) - 1] = '\0';
1311 argv[3] = acct; argc++;
1313 n = command("ACCT %s", argv[3]);
1316 if (n != COMPLETE) {
1317 puts("Login failed.");
1320 if (!aflag && argc == 4) {
1321 (void)command("ACCT %s", argv[3]);
1327 * Print working directory on remote machine.
1335 int oldverbose = verbose;
1338 * If we aren't verbose, this doesn't do anything!
1341 if (command("PWD") == ERROR && code == 500) {
1342 puts("PWD command not recognized, trying XPWD.");
1343 (void)command("XPWD");
1345 verbose = oldverbose;
1349 * Print working directory on local machine.
1356 char buf[MAXPATHLEN];
1358 if (getcwd(buf, sizeof(buf)) != NULL)
1359 printf("Local directory %s\n", buf);
1374 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1376 printf("usage: %s directory-name\n", argv[0]);
1380 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1382 puts("MKD command not recognized, trying XMKD.");
1383 (void)command("XMKD %s", argv[1]);
1388 * Remove a directory.
1391 removedir(argc, argv)
1396 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1398 printf("usage: %s directory-name\n", argv[0]);
1402 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1404 puts("RMD command not recognized, trying XRMD.");
1405 (void)command("XRMD %s", argv[1]);
1410 * Send a line, verbatim, to the remote machine.
1418 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1419 printf("usage: %s line-to-send\n", argv[0]);
1423 quote1("", argc, argv);
1427 * Send a SITE command to the remote machine. The line
1428 * is sent verbatim to the remote machine, except that the
1429 * word "SITE" is added at the front.
1437 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1438 printf("usage: %s line-to-send\n", argv[0]);
1442 quote1("SITE ", argc, argv);
1446 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1447 * Send the result as a one-line command and get response.
1450 quote1(initial, argc, argv)
1451 const char *initial;
1456 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1458 len = snprintf(buf, sizeof(buf), "%s", initial);
1459 if (len >= 0 && len < sizeof(buf)) {
1460 for (i = 1; i < argc; i++) {
1461 len1 = snprintf(&buf[len], sizeof(buf) - len,
1462 i == 1 ? "%s" : " %s", argv[i]);
1463 if (len1 < 0 || len1 > sizeof(buf) - len)
1468 if (command("%s", buf) == PRELIM) {
1469 while (getreply(0) == PRELIM)
1475 do_chmod(argc, argv)
1480 if (argc < 2 && !another(&argc, &argv, "mode"))
1482 if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) {
1484 printf("usage: %s mode file-name\n", argv[0]);
1488 (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1492 do_umask(argc, argv)
1496 int oldverbose = verbose;
1499 (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1500 verbose = oldverbose;
1508 int oldverbose = verbose;
1511 (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1512 verbose = oldverbose;
1516 * Ask the other side for help.
1523 int oldverbose = verbose;
1526 (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1527 verbose = oldverbose;
1531 * Terminate session and exit.
1550 * Terminate session, but don't exit.
1553 disconnect(argc, argv)
1560 (void)command("QUIT");
1580 printf("usage: %s [password]\n", argv[0]);
1587 ap = getpass("Account:");
1588 (void)command("ACCT %s", ap);
1609 longjmp(abortprox, 1);
1621 if (argc < 2 && !another(&argc, &argv, "command")) {
1622 printf("usage: %s command\n", argv[0]);
1626 c = getcmd(argv[1]);
1627 if (c == (struct cmd *) -1) {
1628 puts("?Ambiguous command.");
1629 (void)fflush(stdout);
1634 puts("?Invalid command.");
1635 (void)fflush(stdout);
1640 puts("?Invalid proxy command.");
1641 (void)fflush(stdout);
1645 if (setjmp(abortprox)) {
1649 oldintr = signal(SIGINT, proxabort);
1651 if (c->c_conn && !connected) {
1652 puts("Not connected.");
1653 (void)fflush(stdout);
1655 (void)signal(SIGINT, oldintr);
1659 cmdpos = strcspn(line, " \t");
1660 if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1661 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1662 (*c->c_handler)(argc-1, argv+1);
1670 (void)signal(SIGINT, oldintr);
1679 code = togglevar(argc, argv, &mcase, "Case mapping");
1688 code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1692 setntrans(argc, argv)
1698 puts("Ntrans off.");
1704 (void)strncpy(ntin, argv[1], sizeof(ntin) - 1);
1705 ntin[sizeof(ntin) - 1] = '\0';
1710 (void)strncpy(ntout, argv[2], sizeof(ntout) - 1);
1711 ntout[sizeof(ntout) - 1] = '\0';
1718 static char new[MAXPATHLEN];
1719 char *cp1, *cp2 = new;
1720 int i, ostop, found;
1722 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1724 for (cp1 = name; *cp1; cp1++) {
1726 for (i = 0; *(ntin + i) && i < 16; i++) {
1727 if (*cp1 == *(ntin + i)) {
1730 *cp2++ = *(ntout + i);
1756 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1757 printf("usage: %s [mapin mapout]\n", argv[0]);
1763 cp = strchr(altarg, ' ');
1768 cp = strchr(altarg, ' ');
1771 (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1772 while (*++cp == ' ')
1774 (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1781 static char new[MAXPATHLEN];
1782 char *cp1 = name, *cp2 = mapin;
1783 char *tp[9], *te[9];
1784 int i, toks[9], toknum = 0, match = 1;
1786 for (i=0; i < 9; ++i) {
1789 while (match && *cp1 && *cp2) {
1792 if (*++cp2 != *cp1) {
1797 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1798 if (*cp1 != *(++cp2+1)) {
1799 toks[toknum = *cp2 - '1']++;
1801 while (*++cp1 && *(cp2+1)
1815 if (match && *cp1) {
1818 if (match && *cp2) {
1822 if (!match && *cp1) /* last token mismatch */
1839 if (*++cp2 == '$' &&
1840 isdigit((unsigned char)*(cp2+1))) {
1841 if (*++cp2 == '0') {
1849 else if (toks[toknum = *cp2 - '1']) {
1850 char *cp3 = tp[toknum];
1852 while (cp3 != te[toknum]) {
1859 while (*cp2 && *cp2 != ',' &&
1864 else if (*cp2 == '$' &&
1865 isdigit((unsigned char)*(cp2+1))) {
1866 if (*++cp2 == '0') {
1873 else if (toks[toknum =
1875 char *cp3=tp[toknum];
1889 "nmap: unbalanced brackets.");
1896 while (*++cp2 && *cp2 != ']') {
1897 if (*cp2 == '\\' && *(cp2 + 1)) {
1903 "nmap: unbalanced brackets.");
1919 if (isdigit((unsigned char)*(cp2 + 1))) {
1920 if (*++cp2 == '0') {
1927 else if (toks[toknum = *cp2 - '1']) {
1928 char *cp3 = tp[toknum];
1930 while (cp3 != te[toknum]) {
1936 /* intentional drop through */
1951 setpassive(argc, argv)
1956 code = togglevar(argc, argv, &passivemode,
1957 verbose ? "Passive mode" : NULL);
1961 setepsv4(argc, argv)
1965 code = togglevar(argc, argv, &epsv4,
1966 verbose ? "Use of EPSV/EPRT on IPv4 ftp" : NULL);
1971 setsunique(argc, argv)
1976 code = togglevar(argc, argv, &sunique, "Store unique");
1980 setrunique(argc, argv)
1985 code = togglevar(argc, argv, &runique, "Receive unique");
1988 /* change directory to parent directory */
1996 r = command("CDUP");
1997 if (r == ERROR && code == 500) {
1999 puts("CDUP command not recognized, trying XCUP.");
2000 r = command("XCUP");
2007 * Restart transfer at specific point
2016 printf("usage: %s [restart_point]\n", argv[0]);
2024 rp = strtoq(argv[1], &ep, 10);
2025 if (rp < 0 || *ep != '\0')
2026 printf("restart: Invalid offset `%s'\n", argv[1]);
2030 if (restart_point == 0)
2031 puts("No restart point defined");
2033 printf("Restarting at %qd for next get, put or append\n",
2034 (long long)restart_point);
2038 * Show remote system type
2046 (void)command("SYST");
2058 puts("Limit of 16 macros have already been defined.");
2062 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
2063 printf("usage: %s macro_name\n", argv[0]);
2069 "Enter macro line by line, terminating it with a null line.");
2070 (void)strncpy(macros[macnum].mac_name, argv[1],
2071 sizeof(macros[macnum].mac_name) - 1);
2072 macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0';
2074 macros[macnum].mac_start = macbuf;
2076 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2077 tmp = macros[macnum].mac_start;
2078 while (tmp != macbuf+4096) {
2079 if ((c = getchar()) == EOF) {
2080 puts("macdef: end of file encountered.");
2084 if ((*tmp = c) == '\n') {
2085 if (tmp == macros[macnum].mac_start) {
2086 macros[macnum++].mac_end = tmp;
2090 if (*(tmp-1) == '\0') {
2091 macros[macnum++].mac_end = tmp - 1;
2100 while ((c = getchar()) != '\n' && c != EOF)
2102 if (c == EOF || getchar() == '\n') {
2103 puts("Macro not defined - 4K buffer exceeded.");
2111 * Restrict FTP data port range to a high group of "safe" ports
2114 setrestrict(argc, argv)
2118 code = togglevar(argc, argv, &restricted_data_ports,
2119 verbose ? "Restricted data ports" : NULL);
2123 * Get size of file on remote machine
2132 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2133 printf("usage: %s filename\n", argv[0]);
2137 size = remotesize(argv[1], 1);
2139 printf("%s\t%qd\n", argv[1], (long long)size);
2144 * Get last modification time of file on remote machine
2153 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2154 printf("usage: %s filename\n", argv[0]);
2158 mtime = remotemodtime(argv[1], 1);
2160 printf("%s\t%s", argv[1], asctime(localtime(&mtime)));
2165 * Show status on remote machine
2168 rmtstatus(argc, argv)
2173 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2177 * Get file if modtime is more recent than current file
2185 if (getit(argc, argv, -1, "w"))
2186 printf("Local file \"%s\" is newer than remote file \"%s\".\n",
2191 * Display one file through $PAGER (defaults to "more").
2198 int ohash, overbose;
2199 char *p, *pager, *oldargv1;
2201 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2202 printf("usage: %s filename\n", argv[0]);
2207 if (!globulize(&argv[1])) {
2211 p = getenv("PAGER");
2214 if ((pager = malloc(strlen(p) + 2)) == NULL)
2215 errx(1, "Can't allocate memory for $PAGER");
2216 (void)sprintf(pager, "|%s", p);
2221 recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
2225 if (oldargv1 != argv[1]) /* free up after globulize() */