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.3 2003/10/04 20:36:44 hmp 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 },
87 settype(int argc, char **argv)
95 printf("usage: %s [", argv[0]);
97 for (p = types; p->t_name; p++) {
98 printf("%s%s", sep, p->t_name);
106 printf("Using %s mode to transfer files.\n", typename);
110 for (p = types; p->t_name; p++)
111 if (strcmp(argv[1], p->t_name) == 0)
113 if (p->t_name == 0) {
114 printf("%s: unknown mode.\n", argv[1]);
118 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
119 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
121 comret = command("TYPE %s", p->t_mode);
122 if (comret == COMPLETE) {
123 (void)strcpy(typename, p->t_name);
124 curtype = type = p->t_type;
129 * Internal form of settype; changes current type in use with server
130 * without changing our notion of the type for data transfers.
131 * Used to change to and from ascii for listings.
134 changetype(int newtype, int show)
137 int comret, oldverbose = verbose;
141 if (newtype == curtype)
143 if (debug == 0 && show == 0)
145 for (p = types; p->t_name; p++)
146 if (newtype == p->t_type)
148 if (p->t_name == 0) {
149 warnx("internal error: unknown type %d.", newtype);
152 if (newtype == TYPE_L && bytename[0] != '\0')
153 comret = command("TYPE %s %s", p->t_mode, bytename);
155 comret = command("TYPE %s", p->t_mode);
156 if (comret == COMPLETE)
158 verbose = oldverbose;
168 * Set binary transfer type.
172 setbinary(int argc, char **argv)
180 * Set ascii transfer type.
184 setascii(int argc, char **argv)
192 * Set tenex transfer type.
196 settenex(int argc, char **argv)
204 * Set file transfer mode.
208 setftmode(int argc, char **argv)
211 printf("We only support %s mode, sorry.\n", modename);
216 * Set file transfer format.
220 setform(int argc, char **argv)
223 printf("We only support %s format, sorry.\n", formname);
228 * Set file transfer structure.
232 setstruct(int argc, char **argv)
235 printf("We only support %s structure, sorry.\n", structname);
240 * Send a single file.
243 put(int argc, char **argv)
247 char *oldargv1, *oldargv2;
254 if (argc < 2 && !another(&argc, &argv, "local-file"))
256 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
258 printf("usage: %s local-file [ remote-file ]\n", argv[0]);
264 if (!globulize(&argv[1])) {
269 * If "globulize" modifies argv[1], and argv[2] is a copy of
270 * the old argv[1], make it a copy of the new argv[1].
272 if (argv[1] != oldargv1 && argv[2] == oldargv1) {
275 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
277 argv[2] = dotrans(argv[2]);
279 if (loc && mapflag) {
280 argv[2] = domap(argv[2]);
282 sendrequest(cmd, argv[1], argv[2],
283 argv[1] != oldargv1 || argv[2] != oldargv2);
284 if (oldargv1 != argv[1]) /* free up after globulize() */
289 * Send multiple files.
292 mput(int argc, char **argv)
299 if (argc < 2 && !another(&argc, &argv, "local-files")) {
300 printf("usage: %s local-files\n", argv[0]);
306 oldintr = signal(SIGINT, mabort);
307 (void)setjmp(jabort);
309 char *cp, *tp2, tmpbuf[MAXPATHLEN];
311 while ((cp = remglob(argv, 0, NULL)) != NULL) {
316 if (mflag && confirm(argv[0], cp)) {
319 while (*tp && !islower((unsigned char)*tp)) {
325 while ((*tp2 = *tp) != '\0') {
326 if (isupper((unsigned char)*tp2))
327 *tp2 = tolower((unsigned char)*tp2);
340 sendrequest((sunique) ? "STOU" : "STOR",
341 cp, tp, cp != tp || !interactive);
342 if (!mflag && fromatty) {
343 ointer = interactive;
345 if (confirm("Continue with", "mput")) {
348 interactive = ointer;
352 (void)signal(SIGINT, oldintr);
356 for (i = 1; i < argc; i++) {
362 if (mflag && confirm(argv[0], argv[i])) {
363 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
364 tp = (mapflag) ? domap(tp) : tp;
365 sendrequest((sunique) ? "STOU" : "STOR",
366 argv[i], tp, tp != argv[i] || !interactive);
367 if (!mflag && fromatty) {
368 ointer = interactive;
370 if (confirm("Continue with", "mput")) {
373 interactive = ointer;
379 memset(&gl, 0, sizeof(gl));
380 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
381 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
382 warnx("%s: not found", argv[i]);
386 for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) {
387 if (mflag && confirm(argv[0], *cpp)) {
388 tp = (ntflag) ? dotrans(*cpp) : *cpp;
389 tp = (mapflag) ? domap(tp) : tp;
390 sendrequest((sunique) ? "STOU" : "STOR",
391 *cpp, tp, *cpp != tp || !interactive);
392 if (!mflag && fromatty) {
393 ointer = interactive;
395 if (confirm("Continue with", "mput")) {
398 interactive = ointer;
404 (void)signal(SIGINT, oldintr);
409 reget(int argc, char **argv)
412 (void)getit(argc, argv, 1, "r+w");
416 get(int argc, char **argv)
419 (void)getit(argc, argv, 0, restart_point ? "r+w" : "w" );
426 getit(int argc, char **argv, int restartit, const char *mode)
430 char *oldargv1, *oldargv2, *globargv2;
437 if (argc < 2 && !another(&argc, &argv, "remote-file"))
439 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
441 printf("usage: %s remote-file [ local-file ]\n", argv[0]);
447 if (!globulize(&argv[2])) {
453 char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
455 while (*tp && !islower((unsigned char)*tp)) {
461 while ((*tp2 = *tp) != '\0') {
462 if (isupper((unsigned char)*tp2)) {
463 *tp2 = tolower((unsigned char)*tp2);
472 argv[2] = dotrans(argv[2]);
474 argv[2] = domap(argv[2]);
479 ret = stat(argv[2], &stbuf);
480 if (restartit == 1) {
482 warn("local: %s", argv[2]);
485 restart_point = stbuf.st_size;
490 mtime = remotemodtime(argv[1], 0);
493 if (stbuf.st_mtime >= mtime) {
501 recvrequest("RETR", argv[2], argv[1], mode,
502 argv[1] != oldargv1 || argv[2] != oldargv2, loc);
505 if (oldargv2 != globargv2) /* free up after globulize() */
518 (void)fflush(stdout);
519 if (mflag && fromatty) {
520 ointer = interactive;
524 if (confirm("Continue with", mname)) {
525 interactive = ointer;
529 interactive = ointer;
537 * Get multiple files.
540 mget(int argc, char **argv)
544 char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
546 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
547 printf("usage: %s remote-files\n", argv[0]);
553 oldintr = signal(SIGINT, mabort);
554 (void)setjmp(jabort);
555 while ((cp = remglob(argv, proxy, NULL)) != NULL) {
560 if (mflag && confirm(argv[0], cp)) {
563 for (tp2 = tmpbuf; (ch = *tp++) != 0; )
564 *tp2++ = isupper((unsigned char)ch) ?
565 tolower((unsigned char)ch) :
576 recvrequest("RETR", tp, cp, "w",
577 tp != cp || !interactive, 1);
578 if (!mflag && fromatty) {
579 ointer = interactive;
581 if (confirm("Continue with", "mget")) {
584 interactive = ointer;
588 (void)signal(SIGINT, oldintr);
596 return (bool ? "on" : "off");
604 status(int argc, char **argv)
609 printf("Connected %sto %s.\n",
610 connected == -1 ? "and logged in" : "", hostname);
612 puts("Not connected.");
616 printf("Connected for proxy commands to %s.\n",
620 puts("No proxy connection.");
624 printf("Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
625 *gateserver ? gateserver : "(none)", gateport);
626 printf("Passive mode: %s.\n", onoff(passivemode));
627 printf("Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
628 modename, typename, formname, structname);
629 printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
630 onoff(verbose), onoff(bell), onoff(interactive),
632 printf("Store unique: %s; Receive unique: %s.\n", onoff(sunique),
634 printf("Preserve modification times: %s.\n", onoff(preserve));
635 printf("Case: %s; CR stripping: %s.\n", onoff(mcase), onoff(crflag));
637 printf("Ntrans: (in) %s (out) %s\n", ntin, ntout);
640 puts("Ntrans: off.");
643 printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
648 printf("Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
649 onoff(hash), mark, onoff(progress));
650 printf("Use of PORT cmds: %s.\n", onoff(sendport));
651 printf("Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
652 (!try_epsv && epsv4) ? " (but disabled for this connection)" : "");
654 printf("Command line editing: %s.\n", onoff(editing));
658 for (i=0; i<macnum; i++) {
659 printf("\t%s\n", macros[i].mac_name);
669 togglevar(int argc, char **argv, int *var, const char *mesg)
673 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
675 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
678 printf("usage: %s [ on | off ]\n", argv[0]);
682 printf("%s %s.\n", mesg, onoff(*var));
687 * Set beep on cmd completed mode.
691 setbell(int argc, char **argv)
694 code = togglevar(argc, argv, &bell, "Bell mode");
699 * Set command line editing
703 setedit(int argc, char **argv)
706 code = togglevar(argc, argv, &editing, "Editing mode");
712 * Turn on packet tracing.
716 settrace(int argc, char **argv)
719 code = togglevar(argc, argv, &trace, "Packet tracing");
723 * Toggle hash mark printing during transfers, or set hash mark bytecount.
727 sethash(int argc, char **argv)
731 else if (argc != 2) {
732 printf("usage: %s [ on | off | bytecount ]\n", argv[0]);
735 } else if (strcasecmp(argv[1], "on") == 0)
737 else if (strcasecmp(argv[1], "off") == 0)
743 nmark = strtol(argv[1], &ep, 10);
744 if (nmark < 1 || *ep != '\0') {
745 printf("mark: bad bytecount value `%s'.\n", argv[1]);
752 printf("Hash mark printing %s", onoff(hash));
754 printf(" (%d bytes/hash mark)", mark);
760 * Turn on printing of server echo's.
764 setverbose(int argc, char **argv)
767 code = togglevar(argc, argv, &verbose, "Verbose mode");
771 * Toggle PORT cmd use before each data connection.
775 setport(int argc, char **argv)
778 code = togglevar(argc, argv, &sendport, "Use of PORT cmds");
782 * Toggle transfer progress bar.
786 setprogress(int argc, char **argv)
789 code = togglevar(argc, argv, &progress, "Progress bar");
793 * Turn on interactive prompting during mget, mput, and mdelete.
797 setprompt(int argc, char **argv)
800 code = togglevar(argc, argv, &interactive, "Interactive mode");
804 * Toggle gate-ftp mode, or set gate-ftp server
808 setgate(int argc, char **argv)
810 static char gsbuf[MAXHOSTNAMELEN];
813 printf("usage: %s [ on | off | gateserver [ port ] ]\n",
817 } else if (argc < 2) {
818 gatemode = !gatemode;
820 if (argc == 2 && strcasecmp(argv[1], "on") == 0)
822 else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
829 port = strtol(argv[2], &ep, 10);
830 if (port < 0 || port > 0xffff || *ep != '\0') {
831 printf("%s: bad gateport value.\n",
836 if (gateport != NULL)
838 asprintf(&gateport, "%ld", port);
840 strncpy(gsbuf, argv[1], sizeof(gsbuf) - 1);
841 gsbuf[sizeof(gsbuf) - 1] = '\0';
846 if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
848 "Disabling gate-ftp mode - no gate-ftp server defined.\n");
851 printf("Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
852 *gateserver ? gateserver : "(none)", gateport);
858 * Toggle metacharacter interpretation on local file names.
862 setglob(int argc, char **argv)
865 code = togglevar(argc, argv, &doglob, "Globbing");
869 * Toggle preserving modification times on retrieved files.
873 setpreserve(int argc, char **argv)
876 code = togglevar(argc, argv, &preserve, "Preserve modification times");
880 * Set debugging mode on/off and/or set level of debugging.
884 setdebug(int argc, char **argv)
887 printf("usage: %s [ on | off | debuglevel ]\n", argv[0]);
890 } else if (argc == 2) {
891 if (strcasecmp(argv[1], "on") == 0)
893 else if (strcasecmp(argv[1], "off") == 0)
899 val = strtol(argv[1], &ep, 10);
900 if (val < 0 || val > INT_MAX || *ep != '\0') {
901 printf("%s: bad debugging value.\n", argv[1]);
912 options &= ~SO_DEBUG;
913 printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
918 * Set current working directory on remote machine.
921 cd(int argc, char **argv)
925 if ((argc < 2 && !another(&argc, &argv, "remote-directory")) ||
927 printf("usage: %s remote-directory\n", argv[0]);
931 r = command("CWD %s", argv[1]);
932 if (r == ERROR && code == 500) {
934 puts("CWD command not recognized, trying XCWD.");
935 r = command("XCWD %s", argv[1]);
942 * Set current working directory on local machine.
945 lcd(int argc, char **argv)
947 char buf[MAXPATHLEN];
951 argc++, argv[1] = home;
953 printf("usage: %s local-directory\n", argv[0]);
958 if (!globulize(&argv[1])) {
962 if (chdir(argv[1]) < 0) {
963 warn("local: %s", argv[1]);
966 if (getcwd(buf, sizeof(buf)) != NULL)
967 printf("Local directory now %s\n", buf);
969 warn("getcwd: %s", argv[1]);
972 if (oldargv1 != argv[1]) /* free up after globulize() */
977 * Delete a single file.
980 delete(int argc, char **argv)
983 if ((argc < 2 && !another(&argc, &argv, "remote-file")) || argc > 2) {
984 printf("usage: %s remote-file\n", argv[0]);
988 (void)command("DELE %s", argv[1]);
992 * Delete multiple files.
995 mdelete(int argc, char **argv)
1001 if (argc < 2 && !another(&argc, &argv, "remote-files")) {
1002 printf("usage: %s remote-files\n", argv[0]);
1008 oldintr = signal(SIGINT, mabort);
1009 (void)setjmp(jabort);
1010 while ((cp = remglob(argv, 0, NULL)) != NULL) {
1015 if (mflag && confirm(argv[0], cp)) {
1016 (void)command("DELE %s", cp);
1017 if (!mflag && fromatty) {
1018 ointer = interactive;
1020 if (confirm("Continue with", "mdelete")) {
1023 interactive = ointer;
1027 (void)signal(SIGINT, oldintr);
1032 * Rename a remote file.
1035 renamefile(int argc, char **argv)
1038 if (argc < 2 && !another(&argc, &argv, "from-name"))
1040 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1042 printf("usage: %s from-name to-name\n", argv[0]);
1046 if (command("RNFR %s", argv[1]) == CONTINUE)
1047 (void)command("RNTO %s", argv[2]);
1051 * Get a directory listing of remote files.
1054 ls(int argc, char **argv)
1057 char *oldargv2, *globargv2;
1060 argc++, argv[1] = NULL;
1062 argc++, argv[2] = "-";
1064 printf("usage: %s remote-directory local-file\n", argv[0]);
1068 cmd = strcmp(argv[0], "nlist") == 0 ? "NLST" : "LIST";
1070 if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
1074 globargv2 = argv[2];
1075 if (strcmp(argv[2], "-") && *argv[2] != '|')
1076 if (!globulize(&argv[2]) || !confirm("output to local-file:",
1081 recvrequest(cmd, argv[2], argv[1], "w", 0, 0);
1083 /* flush results in case commands are coming from a pipe */
1086 if (argv[2] != globargv2) /* free up after globulize() */
1088 if (globargv2 != oldargv2)
1093 * Get a directory listing of multiple remote files.
1096 mls(int argc, char **argv)
1101 char mode[1], *dest, *odest;
1103 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1105 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1107 printf("usage: %s remote-files local-file\n", argv[0]);
1111 odest = dest = argv[argc - 1];
1112 argv[argc - 1] = NULL;
1113 if (strcmp(dest, "-") && *dest != '|')
1114 if (!globulize(&dest) ||
1115 !confirm("output to local-file:", dest)) {
1119 dolist = strcmp(argv[0], "mls");
1122 oldintr = signal(SIGINT, mabort);
1123 (void)setjmp(jabort);
1124 for (i = 1; mflag && i < argc-1; ++i) {
1125 *mode = (i == 1) ? 'w' : 'a';
1126 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
1128 if (!mflag && fromatty) {
1129 ointer = interactive;
1131 if (confirm("Continue with", argv[0])) {
1134 interactive = ointer;
1137 (void)signal(SIGINT, oldintr);
1139 if (dest != odest) /* free up after globulize() */
1148 shell(int argc, char **argv)
1152 char shellnam[MAXPATHLEN], *shell, *namep;
1155 old1 = signal (SIGINT, SIG_IGN);
1156 old2 = signal (SIGQUIT, SIG_IGN);
1157 if ((pid = fork()) == 0) {
1158 for (pid = 3; pid < 20; pid++)
1160 (void)signal(SIGINT, SIG_DFL);
1161 (void)signal(SIGQUIT, SIG_DFL);
1162 shell = getenv("SHELL");
1164 shell = _PATH_BSHELL;
1165 namep = strrchr(shell, '/');
1169 (void)strncpy(shellnam + 1, ++namep, sizeof(shellnam) - 2);
1170 shellnam[sizeof(shellnam) - 1] = '\0';
1171 if (strcmp(namep, "sh") != 0)
1175 (void)fflush(stdout);
1178 execl(shell, shellnam, "-c", altarg, (char *)0);
1181 execl(shell, shellnam, (char *)0);
1188 while (wait(&wait_status) != pid)
1190 (void)signal(SIGINT, old1);
1191 (void)signal(SIGQUIT, old2);
1193 warn("Try again later");
1202 * Send new user information (re-login)
1205 user(int argc, char **argv)
1211 (void)another(&argc, &argv, "username");
1212 if (argc < 2 || argc > 4) {
1213 printf("usage: %s username [password] [account]\n", argv[0]);
1217 n = command("USER %s", argv[1]);
1218 if (n == CONTINUE) {
1220 argv[2] = getpass("Password: "), argc++;
1221 n = command("PASS %s", argv[2]);
1223 if (n == CONTINUE) {
1225 (void)fputs("Account: ", stdout);
1226 (void)fflush(stdout);
1227 (void)fgets(acct, sizeof(acct) - 1, stdin);
1228 acct[strlen(acct) - 1] = '\0';
1229 argv[3] = acct; argc++;
1231 n = command("ACCT %s", argv[3]);
1234 if (n != COMPLETE) {
1235 puts("Login failed.");
1238 if (!aflag && argc == 4) {
1239 (void)command("ACCT %s", argv[3]);
1245 * Print working directory on remote machine.
1249 pwd(int argc, char **argv)
1251 int oldverbose = verbose;
1254 * If we aren't verbose, this doesn't do anything!
1257 if (command("PWD") == ERROR && code == 500) {
1258 puts("PWD command not recognized, trying XPWD.");
1259 (void)command("XPWD");
1261 verbose = oldverbose;
1265 * Print working directory on local machine.
1268 lpwd(int argc, char **argv)
1270 char buf[MAXPATHLEN];
1272 if (getcwd(buf, sizeof(buf)) != NULL)
1273 printf("Local directory %s\n", buf);
1283 makedir(int argc, char **argv)
1286 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1288 printf("usage: %s directory-name\n", argv[0]);
1292 if (command("MKD %s", argv[1]) == ERROR && code == 500) {
1294 puts("MKD command not recognized, trying XMKD.");
1295 (void)command("XMKD %s", argv[1]);
1300 * Remove a directory.
1303 removedir(int argc, char **argv)
1306 if ((argc < 2 && !another(&argc, &argv, "directory-name")) ||
1308 printf("usage: %s directory-name\n", argv[0]);
1312 if (command("RMD %s", argv[1]) == ERROR && code == 500) {
1314 puts("RMD command not recognized, trying XRMD.");
1315 (void)command("XRMD %s", argv[1]);
1320 * Send a line, verbatim, to the remote machine.
1323 quote(int argc, char **argv)
1326 if (argc < 2 && !another(&argc, &argv, "command line to send")) {
1327 printf("usage: %s line-to-send\n", argv[0]);
1331 quote1("", argc, argv);
1335 * Send a SITE command to the remote machine. The line
1336 * is sent verbatim to the remote machine, except that the
1337 * word "SITE" is added at the front.
1340 site(int argc, char **argv)
1343 if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) {
1344 printf("usage: %s line-to-send\n", argv[0]);
1348 quote1("SITE ", argc, argv);
1352 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1353 * Send the result as a one-line command and get response.
1356 quote1(const char *initial, int argc, char **argv)
1359 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1361 len = snprintf(buf, sizeof(buf), "%s", initial);
1362 if (len >= 0 && len < sizeof(buf)) {
1363 for (i = 1; i < argc; i++) {
1364 len1 = snprintf(&buf[len], sizeof(buf) - len,
1365 i == 1 ? "%s" : " %s", argv[i]);
1366 if (len1 < 0 || len1 > sizeof(buf) - len)
1371 if (command("%s", buf) == PRELIM) {
1372 while (getreply(0) == PRELIM)
1378 do_chmod(int argc, char **argv)
1381 if (argc < 2 && !another(&argc, &argv, "mode"))
1383 if ((argc < 3 && !another(&argc, &argv, "file-name")) || argc > 3) {
1385 printf("usage: %s mode file-name\n", argv[0]);
1389 (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1393 do_umask(int argc, char **argv)
1395 int oldverbose = verbose;
1398 (void)command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
1399 verbose = oldverbose;
1403 idle(int argc, char **argv)
1405 int oldverbose = verbose;
1408 (void)command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
1409 verbose = oldverbose;
1413 * Ask the other side for help.
1416 rmthelp(int argc, char **argv)
1418 int oldverbose = verbose;
1421 (void)command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
1422 verbose = oldverbose;
1426 * Terminate session and exit.
1430 quit(int argc, char **argv)
1443 * Terminate session, but don't exit.
1446 disconnect(int argc, char **argv)
1451 (void)command("QUIT");
1464 account(int argc, char **argv)
1469 printf("usage: %s [password]\n", argv[0]);
1476 ap = getpass("Account:");
1477 (void)command("ACCT %s", ap);
1483 proxabort(int notused)
1497 longjmp(abortprox, 1);
1501 doproxy(int argc, char **argv)
1507 if (argc < 2 && !another(&argc, &argv, "command")) {
1508 printf("usage: %s command\n", argv[0]);
1512 c = getcmd(argv[1]);
1513 if (c == (struct cmd *) -1) {
1514 puts("?Ambiguous command.");
1515 (void)fflush(stdout);
1520 puts("?Invalid command.");
1521 (void)fflush(stdout);
1526 puts("?Invalid proxy command.");
1527 (void)fflush(stdout);
1531 if (setjmp(abortprox)) {
1535 oldintr = signal(SIGINT, proxabort);
1537 if (c->c_conn && !connected) {
1538 puts("Not connected.");
1539 (void)fflush(stdout);
1541 (void)signal(SIGINT, oldintr);
1545 cmdpos = strcspn(line, " \t");
1546 if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1547 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1548 (*c->c_handler)(argc-1, argv+1);
1556 (void)signal(SIGINT, oldintr);
1560 setcase(int argc, char **argv)
1563 code = togglevar(argc, argv, &mcase, "Case mapping");
1567 setcr(int argc, char **argv)
1570 code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1574 setntrans(int argc, char **argv)
1578 puts("Ntrans off.");
1584 (void)strncpy(ntin, argv[1], sizeof(ntin) - 1);
1585 ntin[sizeof(ntin) - 1] = '\0';
1590 (void)strncpy(ntout, argv[2], sizeof(ntout) - 1);
1591 ntout[sizeof(ntout) - 1] = '\0';
1597 static char new[MAXPATHLEN];
1598 char *cp1, *cp2 = new;
1599 int i, ostop, found;
1601 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1603 for (cp1 = name; *cp1; cp1++) {
1605 for (i = 0; *(ntin + i) && i < 16; i++) {
1606 if (*cp1 == *(ntin + i)) {
1609 *cp2++ = *(ntout + i);
1623 setnmap(int argc, char **argv)
1633 if ((argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1634 printf("usage: %s [mapin mapout]\n", argv[0]);
1640 cp = strchr(altarg, ' ');
1645 cp = strchr(altarg, ' ');
1648 (void)strncpy(mapin, altarg, MAXPATHLEN - 1);
1649 while (*++cp == ' ')
1651 (void)strncpy(mapout, cp, MAXPATHLEN - 1);
1657 static char new[MAXPATHLEN];
1658 char *cp1 = name, *cp2 = mapin;
1659 char *tp[9], *te[9];
1660 int i, toks[9], toknum = 0, match = 1;
1662 for (i=0; i < 9; ++i) {
1665 while (match && *cp1 && *cp2) {
1668 if (*++cp2 != *cp1) {
1673 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
1674 if (*cp1 != *(++cp2+1)) {
1675 toks[toknum = *cp2 - '1']++;
1677 while (*++cp1 && *(cp2+1)
1691 if (match && *cp1) {
1694 if (match && *cp2) {
1698 if (!match && *cp1) /* last token mismatch */
1715 if (*++cp2 == '$' &&
1716 isdigit((unsigned char)*(cp2+1))) {
1717 if (*++cp2 == '0') {
1725 else if (toks[toknum = *cp2 - '1']) {
1726 char *cp3 = tp[toknum];
1728 while (cp3 != te[toknum]) {
1735 while (*cp2 && *cp2 != ',' &&
1740 else if (*cp2 == '$' &&
1741 isdigit((unsigned char)*(cp2+1))) {
1742 if (*++cp2 == '0') {
1749 else if (toks[toknum =
1751 char *cp3=tp[toknum];
1765 "nmap: unbalanced brackets.");
1772 while (*++cp2 && *cp2 != ']') {
1773 if (*cp2 == '\\' && *(cp2 + 1)) {
1779 "nmap: unbalanced brackets.");
1795 if (isdigit((unsigned char)*(cp2 + 1))) {
1796 if (*++cp2 == '0') {
1803 else if (toks[toknum = *cp2 - '1']) {
1804 char *cp3 = tp[toknum];
1806 while (cp3 != te[toknum]) {
1812 /* intentional drop through */
1827 setpassive(int argc, char **argv)
1830 code = togglevar(argc, argv, &passivemode,
1831 verbose ? "Passive mode" : NULL);
1835 setepsv4(int argc, char **argv)
1837 code = togglevar(argc, argv, &epsv4,
1838 verbose ? "Use of EPSV/EPRT on IPv4 ftp" : NULL);
1843 setsunique(int argc, char **argv)
1846 code = togglevar(argc, argv, &sunique, "Store unique");
1850 setrunique(int argc, char **argv)
1853 code = togglevar(argc, argv, &runique, "Receive unique");
1856 /* change directory to parent directory */
1858 cdup(int argc, char **argv)
1862 r = command("CDUP");
1863 if (r == ERROR && code == 500) {
1865 puts("CDUP command not recognized, trying XCUP.");
1866 r = command("XCUP");
1873 * Restart transfer at specific point
1876 restart(int argc, char **argv)
1880 printf("usage: %s [restart_point]\n", argv[0]);
1888 rp = strtoq(argv[1], &ep, 10);
1889 if (rp < 0 || *ep != '\0')
1890 printf("restart: Invalid offset `%s'\n", argv[1]);
1894 if (restart_point == 0)
1895 puts("No restart point defined");
1897 printf("Restarting at %qd for next get, put or append\n",
1898 (long long)restart_point);
1902 * Show remote system type
1905 syst(int argc, char **argv)
1908 (void)command("SYST");
1912 macdef(int argc, char **argv)
1918 puts("Limit of 16 macros have already been defined.");
1922 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
1923 printf("usage: %s macro_name\n", argv[0]);
1929 "Enter macro line by line, terminating it with a null line.");
1930 (void)strncpy(macros[macnum].mac_name, argv[1],
1931 sizeof(macros[macnum].mac_name) - 1);
1932 macros[macnum].mac_name[sizeof(macros[macnum].mac_name) - 1] = '\0';
1934 macros[macnum].mac_start = macbuf;
1936 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
1937 tmp = macros[macnum].mac_start;
1938 while (tmp != macbuf+4096) {
1939 if ((c = getchar()) == EOF) {
1940 puts("macdef: end of file encountered.");
1944 if ((*tmp = c) == '\n') {
1945 if (tmp == macros[macnum].mac_start) {
1946 macros[macnum++].mac_end = tmp;
1950 if (*(tmp-1) == '\0') {
1951 macros[macnum++].mac_end = tmp - 1;
1960 while ((c = getchar()) != '\n' && c != EOF)
1962 if (c == EOF || getchar() == '\n') {
1963 puts("Macro not defined - 4K buffer exceeded.");
1971 * Restrict FTP data port range to a high group of "safe" ports
1974 setrestrict(int argc, char **argv)
1976 code = togglevar(argc, argv, &restricted_data_ports,
1977 verbose ? "Restricted data ports" : NULL);
1981 * Get size of file on remote machine
1984 sizecmd(int argc, char **argv)
1988 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
1989 printf("usage: %s filename\n", argv[0]);
1993 size = remotesize(argv[1], 1);
1995 printf("%s\t%qd\n", argv[1], (long long)size);
2000 * Get last modification time of file on remote machine
2003 modtime(int argc, char **argv)
2007 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2008 printf("usage: %s filename\n", argv[0]);
2012 mtime = remotemodtime(argv[1], 1);
2014 printf("%s\t%s", argv[1], asctime(localtime(&mtime)));
2019 * Show status on remote machine
2022 rmtstatus(int argc, char **argv)
2025 (void)command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
2029 * Get file if modtime is more recent than current file
2032 newer(int argc, char **argv)
2035 if (getit(argc, argv, -1, "w"))
2036 printf("Local file \"%s\" is newer than remote file \"%s\".\n",
2041 * Display one file through $PAGER (defaults to "more").
2044 page(int argc, char **argv)
2046 int ohash, overbose;
2047 char *p, *pager, *oldargv1;
2049 if ((argc < 2 && !another(&argc, &argv, "filename")) || argc > 2) {
2050 printf("usage: %s filename\n", argv[0]);
2055 if (!globulize(&argv[1])) {
2059 p = getenv("PAGER");
2062 if ((pager = malloc(strlen(p) + 2)) == NULL)
2063 errx(1, "Can't allocate memory for $PAGER");
2064 (void)sprintf(pager, "|%s", p);
2069 recvrequest("RETR", pager, argv[1], "r+w", 1, 0);
2073 if (oldargv1 != argv[1]) /* free up after globulize() */