1 /* $FreeBSD: src/usr.bin/ftp/cmds.c,v 1.16.2.3 2002/08/27 09:55:08 yar Exp $ */
2 /* $DragonFly: src/usr.bin/ftp/Attic/cmds.c,v 1.2 2003/06/17 04:29:26 dillon Exp $ */
3 /* $NetBSD: cmds.c,v 1.30.2.1 1997/11/18 00:58:26 mellon Exp $ */
6 * Copyright (c) 1985, 1989, 1993, 1994
7 * The Regents of the University of California. All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * @(#)cmds.c 8.6 (Berkeley) 10/9/94
38 * $NetBSD: cmds.c,v 1.30.2.1 1997/11/18 00:58:26 mellon Exp $
39 * $FreeBSD: src/usr.bin/ftp/cmds.c,v 1.16.2.3 2002/08/27 09:55:08 yar Exp $
42 #include <sys/cdefs.h>
45 * FTP User Program -- Command Routines.
47 #include <sys/types.h>
48 #include <sys/socket.h>
63 #include "pathnames.h"
75 { "ascii", "A", TYPE_A, 0 },
76 { "binary", "I", TYPE_I, 0 },
77 { "image", "I", TYPE_I, 0 },
78 { "ebcdic", "E", TYPE_E, 0 },
79 { "tenex", "L", TYPE_L, bytename },
97 printf("usage: %s [", argv[0]);
99 for (p = types; p->t_name; p++) {
100 printf("%s%s", sep, p->t_name);
108 printf("Using %s mode to transfer files.\n", typename);
112 for (p = types; p->t_name; p++)
113 if (strcmp(argv[1], p->t_name) == 0)
115 if (p->t_name == 0) {
116 printf("%s: unknown mode.\n", argv[1]);
120 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
121 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
123 comret = command("TYPE %s", p->t_mode);
124 if (comret == COMPLETE) {
125 (void)strcpy(typename, p->t_name);
126 curtype = type = p->t_type;
131 * Internal form of settype; changes current type in use with server
132 * without changing our notion of the type for data transfers.
133 * Used to change to and from ascii for listings.
136 changetype(newtype, show)
140 int comret, oldverbose = verbose;
144 if (newtype == curtype)
146 if (debug == 0 && show == 0)
148 for (p = types; p->t_name; p++)
149 if (newtype == p->t_type)
151 if (p->t_name == 0) {
152 warnx("internal error: unknown type %d.", newtype);
155 if (newtype == TYPE_L && bytename[0] != '\0')
156 comret = command("TYPE %s %s", p->t_mode, bytename);
158 comret = command("TYPE %s", p->t_mode);
159 if (comret == COMPLETE)
161 verbose = oldverbose;
171 * Set binary transfer type.
175 setbinary(argc, argv)
185 * Set ascii transfer type.
199 * Set tenex transfer type.
213 * Set file transfer mode.
217 setftmode(argc, argv)
222 printf("We only support %s mode, sorry.\n", modename);
227 * Set file transfer format.
236 printf("We only support %s format, sorry.\n", formname);
241 * Set file transfer structure.
245 setstruct(argc, argv)
250 printf("We only support %s structure, sorry.\n", structname);
255 * Send a single file.
264 char *oldargv1, *oldargv2;
271 if (argc < 2 && !another(&argc, &argv, "local-file"))
273 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
275 printf("usage: %s local-file [ remote-file ]\n", argv[0]);
281 if (!globulize(&argv[1])) {
286 * If "globulize" modifies argv[1], and argv[2] is a copy of
287 * the old argv[1], make it a copy of the new argv[1].
289 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
292 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
294 argv[2] = dotrans(argv[2]);
296 if (loc && mapflag) {
297 argv[2] = domap(argv[2]);
299 sendrequest(cmd, argv[1], argv[2],
300 argv[1] != oldargv1 || argv[2] != oldargv2);
301 if (oldargv1 != argv[1]) /* free up after globulize() */
306 * Send multiple files.
318 if (argc < 2 && !another(&argc, &argv, "local-files")) {
319 printf("usage: %s local-files\n", argv[0]);
325 oldintr = signal(SIGINT, mabort);
326 (void)setjmp(jabort);
328 char *cp, *tp2, tmpbuf[MAXPATHLEN];
330 while ((cp = remglob(argv, 0, NULL)) != NULL) {
335 if (mflag && confirm(argv[0], cp)) {
338 while (*tp && !islower((unsigned char)*tp)) {
344 while ((*tp2 = *tp) != '\0') {
345 if (isupper((unsigned char)*tp2))
346 *tp2 = tolower((unsigned char)*tp2);
359 sendrequest((sunique) ? "STOU" : "STOR",
360 cp, tp, cp != tp || !interactive);
361 if (!mflag && fromatty) {
362 ointer = interactive;
364 if (confirm("Continue with", "mput")) {
367 interactive = ointer;
371 (void)signal(SIGINT, oldintr);
375 for (i = 1; i < argc; i++) {
381 if (mflag && confirm(argv[0], argv[i])) {
382 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
383 tp = (mapflag) ? domap(tp) : tp;
384 sendrequest((sunique) ? "STOU" : "STOR",
385 argv[i], tp, tp != argv[i] || !interactive);
386 if (!mflag && fromatty) {
387 ointer = interactive;
389 if (confirm("Continue with", "mput")) {
392 interactive = ointer;
398 memset(&gl, 0, sizeof(gl));
399 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
400 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
401 warnx("%s: not found", argv[i]);
405 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
406 if (mflag && confirm(argv[0], *cpp)) {
407 tp = (ntflag) ? dotrans(*cpp) : *cpp;
408 tp = (mapflag) ? domap(tp) : tp;
409 sendrequest((sunique) ? "STOU" : "STOR",
410 *cpp, tp, *cpp != tp || !interactive);
411 if (!mflag && fromatty) {
412 ointer = interactive;
414 if (confirm("Continue with", "mput")) {
417 interactive = ointer;
423 (void)signal(SIGINT, oldintr);
433 (void)getit(argc, argv, 1, "r+w");
442 (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
449 getit(argc, argv, restartit, mode)
457 char *oldargv1, *oldargv2, *globargv2;
464 if (argc < 2 && !another(&argc, &argv, "remote-file"))
466 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
468 printf("usage: %s remote-file [ local-file ]\n", argv[0]);
474 if (!globulize(&argv[2])) {
480 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
482 while (*tp && !islower((unsigned char)*tp)) {
488 while ((*tp2 = *tp) != '\0') {
489 if (isupper((unsigned char)*tp2)) {
490 *tp2 = tolower((unsigned char)*tp2);
499 argv[2] = dotrans(argv[2]);
501 argv[2] = domap(argv[2]);
506 ret = stat(argv[2], &stbuf);
507 if (restartit == 1) {
509 warn("local: %s", argv[2]);
512 restart_point = stbuf.st_size;
517 mtime = remotemodtime(argv[1], 0);
520 if (stbuf.st_mtime >= mtime) {
528 recvrequest("RETR", argv[2], argv[1], mode,
529 argv[1] != oldargv1 || argv[2] != oldargv2, loc);
532 if (oldargv2 != globargv2) /* free up after globulize() */
546 (void)fflush(stdout);
547 if (mflag && fromatty) {
548 ointer = interactive;
552 if (confirm("Continue with", mname)) {
553 interactive = ointer;
557 interactive = ointer;
565 * Get multiple files.
574 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
576 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
577 printf("usage: %s remote-files\n", argv[0]);
583 oldintr = signal(SIGINT, mabort);
584 (void)setjmp(jabort);
585 while ((cp = remglob(argv, proxy, NULL)) != NULL) {
590 if (mflag && confirm(argv[0], cp)) {
593 for (tp2 = tmpbuf; (ch = *tp++) != 0; )
594 *tp2++ = isupper((unsigned char)ch) ?
595 tolower((unsigned char)ch) :
606 recvrequest("RETR", tp, cp, "w",
607 tp != cp || !interactive, 1);
608 if (!mflag && fromatty) {
609 ointer = interactive;
611 if (confirm("Continue with", "mget")) {
614 interactive = ointer;
618 (void)signal(SIGINT, oldintr);
627 return (bool ? "on" : "off");
642 printf("Connected %sto %s.\n",
643 connected == -1 ? "and logged in" : "", hostname);
645 puts("Not connected.");
649 printf("Connected for proxy commands to %s.\n",
653 puts("No proxy connection.");
657 printf("Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
658 *gateserver ? gateserver : "(none)", gateport);
659 printf("Passive mode: %s.\n", onoff(passivemode));
660 printf("Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
661 modename, typename, formname, structname);
662 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
663 onoff(verbose), onoff(bell), onoff(interactive),
665 printf("Store unique: %s; Receive unique: %s.\n", onoff(sunique),
667 printf("Preserve modification times: %s.\n", onoff(preserve));
668 printf("Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
670 printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
673 puts("Ntrans: off.");
676 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
681 printf("Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
682 onoff(hash), mark, onoff(progress));
683 printf("Use of PORT cmds: %s.\n", onoff(sendport));
684 printf("Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
685 (!try_epsv && epsv4) ? " (but disabled for this connection)" : "");
687 printf("Command line editing: %s.\n", onoff(editing));
691 for (i=0; i<macnum; i++) {
692 printf("\t%s\n", macros[i].mac_name);
702 togglevar(argc, argv, var, mesg)
710 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
712 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
715 printf("usage: %s [ on | off ]\n", argv[0]);
719 printf("%s %s.\n", mesg, onoff(*var));
724 * Set beep on cmd completed mode.
733 code = togglevar(argc, argv, &bell, "Bell mode");
738 * Set command line editing
747 code = togglevar(argc, argv, &editing, "Editing mode");
753 * Turn on packet tracing.
762 code = togglevar(argc, argv, &trace, "Packet tracing");
766 * Toggle hash mark printing during transfers, or set hash mark bytecount.
776 else if (argc != 2) {
777 printf("usage: %s [ on | off | bytecount ]\n", argv[0]);
780 } else if (strcasecmp(argv[1], "on") == 0)
782 else if (strcasecmp(argv[1], "off") == 0)
788 nmark = strtol(argv[1], &ep, 10);
789 if (nmark < 1 || *ep != '\0') {
790 printf("mark: bad bytecount value `%s'.\n", argv[1]);
797 printf("Hash mark printing %s", onoff(hash));
799 printf(" (%d bytes/hash mark)", mark);
805 * Turn on printing of server echo's.
809 setverbose(argc, argv)
814 code = togglevar(argc, argv, &verbose, "Verbose mode");
818 * Toggle PORT cmd use before each data connection.
827 code = togglevar(argc, argv, &sendport, "Use of PORT cmds");
831 * Toggle transfer progress bar.
835 setprogress(argc, argv)
840 code = togglevar(argc, argv, &progress, "Progress bar");
844 * Turn on interactive prompting during mget, mput, and mdelete.
848 setprompt(argc, argv)
853 code = togglevar(argc, argv, &interactive, "Interactive mode");
857 * Toggle gate-ftp mode, or set gate-ftp server
865 static char gsbuf[MAXHOSTNAMELEN];
868 printf("usage: %s [ on | off | gateserver [ port ] ]\n",
872 } else if (argc < 2) {
873 gatemode = !gatemode;
875 if (argc == 2 && strcasecmp(argv[1], "on") == 0)
877 else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
884 port = strtol(argv[2], &ep, 10);
885 if (port < 0 || port > 0xffff || *ep != '\0') {
886 printf("%s: bad gateport value.\n",
891 if (gateport != NULL)
893 asprintf(&gateport, "%ld", port);
895 strncpy(gsbuf, argv[1], sizeof(gsbuf) - 1);
896 gsbuf[sizeof(gsbuf) - 1] = '\0';
901 if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
903 "Disabling gate-ftp mode - no gate-ftp server defined.\n");
906 printf("Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
907 *gateserver ? gateserver : "(none)", gateport);
913 * Toggle metacharacter interpretation on local file names.
922 code = togglevar(argc, argv, &doglob, "Globbing");
926 * Toggle preserving modification times on retrieved files.
930 setpreserve(argc, argv)
935 code = togglevar(argc, argv, &preserve, "Preserve modification times");
939 * Set debugging mode on/off and/or set level of debugging.
948 printf("usage: %s [ on | off | debuglevel ]\n", argv[0]);
951 } else if (argc == 2) {
952 if (strcasecmp(argv[1], "on") == 0)
954 else if (strcasecmp(argv[1], "off") == 0)
960 val = strtol(argv[1], &ep, 10);
961 if (val < 0 || val > INT_MAX || *ep != '\0') {
962 printf("%s: bad debugging value.\n", argv[1]);
973 options &= ~SO_DEBUG;
974 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
979 * Set current working directory on remote machine.
988 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
990 printf("usage: %s remote-directory\n", argv[0]);
994 r = command("CWD %s", argv[1]);
995 if (r == ERROR && code == 500) {
997 puts("CWD command not recognized, trying XCWD.");
998 r = command("XCWD %s", argv[1]);
1005 * Set current working directory on local machine.
1012 char buf[MAXPATHLEN];
1016 argc++, argv[1] = home;
1018 printf("usage: %s local-directory\n", argv[0]);
1023 if (!globulize(&argv[1])) {
1027 if (chdir(argv[1]) < 0) {
1028 warn("local: %s", argv[1]);
1031 if (getcwd(buf, sizeof(buf)) != NULL)
1032 printf("Local directory now %s\n", buf);
1034 warn("getcwd: %s", argv[1]);
1037 if (oldargv1 != argv[1]) /* free up after globulize() */
1042 * Delete a single file.
1050 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
1051 printf("usage: %s remote-file\n", argv[0]);
1055 (void)command("DELE %s", argv[1]);
1059 * Delete multiple files.
1070 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1071 printf("usage: %s remote-files\n", argv[0]);
1077 oldintr = signal(SIGINT, mabort);
1078 (void)setjmp(jabort);
1079 while ((cp = remglob(argv, 0, NULL)) != NULL) {
1084 if (mflag && confirm(argv[0], cp)) {
1085 (void)command("DELE %s", cp);
1086 if (!mflag && fromatty) {
1087 ointer = interactive;
1089 if (confirm("Continue with", "mdelete")) {
1092 interactive = ointer;
1096 (void)signal(SIGINT, oldintr);
1101 * Rename a remote file.
1104 renamefile(argc, argv)
1109 if (argc < 2 && !another(&argc, &argv, "from-name"))
1111 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1113 printf("usage: %s from-name to-name\n", argv[0]);
1117 if (command("RNFR %s", argv[1]) == CONTINUE)
1118 (void)command("RNTO %s", argv[2]);
1122 * Get a directory listing of remote files.
1130 char *oldargv2, *globargv2;
1133 argc++, argv[1] = NULL;
1135 argc++, argv[2] = "-";
1137 printf("usage: %s remote-directory local-file\n", argv[0]);
1141 cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST";
1143 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1147 globargv2 = argv[2];
1148 if (strcmp(argv[2], "-") && *argv[2] != '|')
1149 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1154 recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
1156 /* flush results in case commands are coming from a pipe */
1159 if (argv[2] != globargv2) /* free up after globulize() */
1161 if (globargv2 != oldargv2)
1166 * Get a directory listing of multiple remote files.
1176 char mode[1], *dest, *odest;
1178 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1180 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1182 printf("usage: %s remote-files local-file\n", argv[0]);
1186 odest = dest = argv[argc - 1];
1187 argv[argc - 1] = NULL;
1188 if (strcmp(dest, "-") && *dest != '|')
1189 if (!globulize(&dest) ||
1190 !confirm("output to local-file:", dest)) {
1194 dolist = strcmp(argv[0], "mls");
1197 oldintr = signal(SIGINT, mabort);
1198 (void)setjmp(jabort);
1199 for (i = 1; mflag && i < argc-1; ++i) {
1200 *mode = (i == 1) ? 'w' : 'a';
1201 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
1203 if (!mflag && fromatty) {
1204 ointer = interactive;
1206 if (confirm("Continue with", argv[0])) {
1209 interactive = ointer;
1212 (void)signal(SIGINT, oldintr);
1214 if (dest != odest) /* free up after globulize() */
1229 char shellnam[MAXPATHLEN], *shell, *namep;
1232 old1 = signal (SIGINT, SIG_IGN);
1233 old2 = signal (SIGQUIT, SIG_IGN);
1234 if ((pid = fork()) == 0) {
1235 for (pid = 3; pid < 20; pid++)
1237 (void)signal(SIGINT, SIG_DFL);
1238 (void)signal(SIGQUIT, SIG_DFL);
1239 shell = getenv("SHELL");
1241 shell = _PATH_BSHELL;
1242 namep = strrchr(shell, '/');
1246 (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2);
1247 shellnam[sizeof(shellnam) - 1] = '\0';
1248 if (strcmp(namep, "sh") != 0)
1252 (void)fflush(stdout);
1255 execl(shell, shellnam, "-c", altarg, (char *)0);
1258 execl(shell, shellnam, (char *)0);
1265 while (wait(&wait_status) != pid)
1267 (void)signal(SIGINT, old1);
1268 (void)signal(SIGQUIT, old2);
1270 warn("Try again later");
1279 * Send new user information (re-login)
1290 (void)another(&argc, &argv, "username");
1291 if (argc < 2 || argc > 4) {
1292 printf("usage: %s username [password] [account]\n", argv[0]);
1296 n = command("USER %s", argv[1]);
1297 if (n == CONTINUE) {
1299 argv[2] = getpass("Password: "), argc++;
1300 n = command("PASS %s", argv[2]);
1302 if (n == CONTINUE) {
1304 (void)fputs("Account: ", stdout);
1305 (void)fflush(stdout);
1306 (void)fgets(acct, sizeof(acct) - 1, stdin);
1307 acct[strlen(acct) - 1] = '\0';
1308 argv[3] = acct; argc++;
1310 n = command("ACCT %s", argv[3]);
1313 if (n != COMPLETE) {
1314 puts("Login failed.");
1317 if (!aflag && argc == 4) {
1318 (void)command("ACCT %s", argv[3]);
1324 * Print working directory on remote machine.
1332 int oldverbose = verbose;
1335 * If we aren't verbose, this doesn't do anything!
1338 if (command("PWD") == ERROR && code == 500) {
1339 puts("PWD command not recognized, trying XPWD.");
1340 (void)command("XPWD");
1342 verbose = oldverbose;
1346 * Print working directory on local machine.
1353 char buf[MAXPATHLEN];
1355 if (getcwd(buf, sizeof(buf)) != NULL)
1356 printf("Local directory %s\n", buf);
1371 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1373 printf("usage: %s directory-name\n", argv[0]);
1377 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1379 puts("MKD command not recognized, trying XMKD.");
1380 (void)command("XMKD %s", argv[1]);
1385 * Remove a directory.
1388 removedir(argc, argv)
1393 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1395 printf("usage: %s directory-name\n", argv[0]);
1399 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1401 puts("RMD command not recognized, trying XRMD.");
1402 (void)command("XRMD %s", argv[1]);
1407 * Send a line, verbatim, to the remote machine.
1415 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1416 printf("usage: %s line-to-send\n", argv[0]);
1420 quote1("", argc, argv);
1424 * Send a SITE command to the remote machine. The line
1425 * is sent verbatim to the remote machine, except that the
1426 * word "SITE" is added at the front.
1434 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1435 printf("usage: %s line-to-send\n", argv[0]);
1439 quote1("SITE ", argc, argv);
1443 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1444 * Send the result as a one-line command and get response.
1447 quote1(initial, argc, argv)
1448 const char *initial;
1453 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1455 len = snprintf(buf, sizeof(buf), "%s", initial);
1456 if (len >= 0 && len < sizeof(buf)) {
1457 for (i = 1; i < argc; i++) {
1458 len1 = snprintf(&buf[len], sizeof(buf) - len,
1459 i == 1 ? "%s" : " %s", argv[i]);
1460 if (len1 < 0 || len1 > sizeof(buf) - len)
1465 if (command("%s", buf) == PRELIM) {
1466 while (getreply(0) == PRELIM)
1472 do_chmod(argc, argv)
1477 if (argc < 2 && !another(&argc, &argv, "mode"))
1479 if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) {
1481 printf("usage: %s mode file-name\n", argv[0]);
1485 (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1489 do_umask(argc, argv)
1493 int oldverbose = verbose;
1496 (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1497 verbose = oldverbose;
1505 int oldverbose = verbose;
1508 (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1509 verbose = oldverbose;
1513 * Ask the other side for help.
1520 int oldverbose = verbose;
1523 (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1524 verbose = oldverbose;
1528 * Terminate session and exit.
1547 * Terminate session, but don't exit.
1550 disconnect(argc, argv)
1557 (void)command("QUIT");
1577 printf("usage: %s [password]\n", argv[0]);
1584 ap = getpass("Account:");
1585 (void)command("ACCT %s", ap);
1606 longjmp(abortprox, 1);
1618 if (argc < 2 && !another(&argc, &argv, "command")) {
1619 printf("usage: %s command\n", argv[0]);
1623 c = getcmd(argv[1]);
1624 if (c == (struct cmd *) -1) {
1625 puts("?Ambiguous command.");
1626 (void)fflush(stdout);
1631 puts("?Invalid command.");
1632 (void)fflush(stdout);
1637 puts("?Invalid proxy command.");
1638 (void)fflush(stdout);
1642 if (setjmp(abortprox)) {
1646 oldintr = signal(SIGINT, proxabort);
1648 if (c->c_conn && !connected) {
1649 puts("Not connected.");
1650 (void)fflush(stdout);
1652 (void)signal(SIGINT, oldintr);
1656 cmdpos = strcspn(line, " \t");
1657 if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1658 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1659 (*c->c_handler)(argc-1, argv+1);
1667 (void)signal(SIGINT, oldintr);
1676 code = togglevar(argc, argv, &mcase, "Case mapping");
1685 code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1689 setntrans(argc, argv)
1695 puts("Ntrans off.");
1701 (void)strncpy(ntin, argv[1], sizeof(ntin) - 1);
1702 ntin[sizeof(ntin) - 1] = '\0';
1707 (void)strncpy(ntout, argv[2], sizeof(ntout) - 1);
1708 ntout[sizeof(ntout) - 1] = '\0';
1715 static char new[MAXPATHLEN];
1716 char *cp1, *cp2 = new;
1717 int i, ostop, found;
1719 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1721 for (cp1 = name; *cp1; cp1++) {
1723 for (i = 0; *(ntin + i) && i < 16; i++) {
1724 if (*cp1 == *(ntin + i)) {
1727 *cp2++ = *(ntout + i);
1753 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1754 printf("usage: %s [mapin mapout]\n", argv[0]);
1760 cp = strchr(altarg, ' ');
1765 cp = strchr(altarg, ' ');
1768 (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1769 while (*++cp == ' ')
1771 (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1778 static char new[MAXPATHLEN];
1779 char *cp1 = name, *cp2 = mapin;
1780 char *tp[9], *te[9];
1781 int i, toks[9], toknum = 0, match = 1;
1783 for (i=0; i < 9; ++i) {
1786 while (match && *cp1 && *cp2) {
1789 if (*++cp2 != *cp1) {
1794 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1795 if (*cp1 != *(++cp2+1)) {
1796 toks[toknum = *cp2 - '1']++;
1798 while (*++cp1 && *(cp2+1)
1812 if (match && *cp1) {
1815 if (match && *cp2) {
1819 if (!match && *cp1) /* last token mismatch */
1836 if (*++cp2 == '$' &&
1837 isdigit((unsigned char)*(cp2+1))) {
1838 if (*++cp2 == '0') {
1846 else if (toks[toknum = *cp2 - '1']) {
1847 char *cp3 = tp[toknum];
1849 while (cp3 != te[toknum]) {
1856 while (*cp2 && *cp2 != ',' &&
1861 else if (*cp2 == '$' &&
1862 isdigit((unsigned char)*(cp2+1))) {
1863 if (*++cp2 == '0') {
1870 else if (toks[toknum =
1872 char *cp3=tp[toknum];
1886 "nmap: unbalanced brackets.");
1893 while (*++cp2 && *cp2 != ']') {
1894 if (*cp2 == '\\' && *(cp2 + 1)) {
1900 "nmap: unbalanced brackets.");
1916 if (isdigit((unsigned char)*(cp2 + 1))) {
1917 if (*++cp2 == '0') {
1924 else if (toks[toknum = *cp2 - '1']) {
1925 char *cp3 = tp[toknum];
1927 while (cp3 != te[toknum]) {
1933 /* intentional drop through */
1948 setpassive(argc, argv)
1953 code = togglevar(argc, argv, &passivemode,
1954 verbose ? "Passive mode" : NULL);
1958 setepsv4(argc, argv)
1962 code = togglevar(argc, argv, &epsv4,
1963 verbose ? "Use of EPSV/EPRT on IPv4 ftp" : NULL);
1968 setsunique(argc, argv)
1973 code = togglevar(argc, argv, &sunique, "Store unique");
1977 setrunique(argc, argv)
1982 code = togglevar(argc, argv, &runique, "Receive unique");
1985 /* change directory to parent directory */
1993 r = command("CDUP");
1994 if (r == ERROR && code == 500) {
1996 puts("CDUP command not recognized, trying XCUP.");
1997 r = command("XCUP");
2004 * Restart transfer at specific point
2013 printf("usage: %s [restart_point]\n", argv[0]);
2021 rp = strtoq(argv[1], &ep, 10);
2022 if (rp < 0 || *ep != '\0')
2023 printf("restart: Invalid offset `%s'\n", argv[1]);
2027 if (restart_point == 0)
2028 puts("No restart point defined");
2030 printf("Restarting at %qd for next get, put or append\n",
2031 (long long)restart_point);
2035 * Show remote system type
2043 (void)command("SYST");
2055 puts("Limit of 16 macros have already been defined.");
2059 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
2060 printf("usage: %s macro_name\n", argv[0]);
2066 "Enter macro line by line, terminating it with a null line.");
2067 (void)strncpy(macros[macnum].mac_name, argv[1],
2068 sizeof(macros[macnum].mac_name) - 1);
2069 macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0';
2071 macros[macnum].mac_start = macbuf;
2073 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2074 tmp = macros[macnum].mac_start;
2075 while (tmp != macbuf+4096) {
2076 if ((c = getchar()) == EOF) {
2077 puts("macdef: end of file encountered.");
2081 if ((*tmp = c) == '\n') {
2082 if (tmp == macros[macnum].mac_start) {
2083 macros[macnum++].mac_end = tmp;
2087 if (*(tmp-1) == '\0') {
2088 macros[macnum++].mac_end = tmp - 1;
2097 while ((c = getchar()) != '\n' && c != EOF)
2099 if (c == EOF || getchar() == '\n') {
2100 puts("Macro not defined - 4K buffer exceeded.");
2108 * Restrict FTP data port range to a high group of "safe" ports
2111 setrestrict(argc, argv)
2115 code = togglevar(argc, argv, &restricted_data_ports,
2116 verbose ? "Restricted data ports" : NULL);
2120 * Get size of file on remote machine
2129 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2130 printf("usage: %s filename\n", argv[0]);
2134 size = remotesize(argv[1], 1);
2136 printf("%s\t%qd\n", argv[1], (long long)size);
2141 * Get last modification time of file on remote machine
2150 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2151 printf("usage: %s filename\n", argv[0]);
2155 mtime = remotemodtime(argv[1], 1);
2157 printf("%s\t%s", argv[1], asctime(localtime(&mtime)));
2162 * Show status on remote machine
2165 rmtstatus(argc, argv)
2170 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2174 * Get file if modtime is more recent than current file
2182 if (getit(argc, argv, -1, "w"))
2183 printf("Local file \"%s\" is newer than remote file \"%s\".\n",
2188 * Display one file through $PAGER (defaults to "more").
2195 int ohash, overbose;
2196 char *p, *pager, *oldargv1;
2198 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2199 printf("usage: %s filename\n", argv[0]);
2204 if (!globulize(&argv[1])) {
2208 p = getenv("PAGER");
2211 if ((pager = malloc(strlen(p) + 2)) == NULL)
2212 errx(1, "Can't allocate memory for $PAGER");
2213 (void)sprintf(pager, "|%s", p);
2218 recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
2222 if (oldargv1 != argv[1]) /* free up after globulize() */