1 /* $NetBSD: cmds.c,v 1.112 2005/04/11 01:49:31 lukem Exp $ */
4 * Copyright (c) 1996-2005 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
12 * NASA Ames Research Center.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 * must display the following acknowledgement:
24 * This product includes software developed by the NetBSD
25 * Foundation, Inc. and its contributors.
26 * 4. Neither the name of The NetBSD Foundation nor the names of its
27 * contributors may be used to endorse or promote products derived
28 * from this software without specific prior written permission.
30 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
31 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
32 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
34 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40 * POSSIBILITY OF SUCH DAMAGE.
44 * Copyright (c) 1985, 1989, 1993, 1994
45 * The Regents of the University of California. All rights reserved.
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 * Copyright (C) 1997 and 1998 WIDE Project.
74 * All rights reserved.
76 * Redistribution and use in source and binary forms, with or without
77 * modification, are permitted provided that the following conditions
79 * 1. Redistributions of source code must retain the above copyright
80 * notice, this list of conditions and the following disclaimer.
81 * 2. Redistributions in binary form must reproduce the above copyright
82 * notice, this list of conditions and the following disclaimer in the
83 * documentation and/or other materials provided with the distribution.
84 * 3. Neither the name of the project nor the names of its contributors
85 * may be used to endorse or promote products derived from this software
86 * without specific prior written permission.
88 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
89 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
92 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
101 #include <sys/cdefs.h>
104 static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94";
106 __RCSID("$NetBSD: cmds.c,v 1.112 2005/04/11 01:49:31 lukem Exp $");
108 #endif /* not lint */
111 * FTP User Program -- Command Routines.
113 #include <sys/types.h>
114 #include <sys/socket.h>
115 #include <sys/stat.h>
116 #include <sys/wait.h>
117 #include <arpa/ftp.h>
141 { "ascii", "A", TYPE_A, 0 },
142 { "binary", "I", TYPE_I, 0 },
143 { "image", "I", TYPE_I, 0 },
144 { "ebcdic", "E", TYPE_E, 0 },
145 { "tenex", "L", TYPE_L, bytename },
152 static int confirm(const char *, const char *);
154 static const char *doprocess(char *, size_t, const char *, int, int, int);
155 static const char *domap(char *, size_t, const char *);
156 static const char *docase(char *, size_t, const char *);
157 static const char *dotrans(char *, size_t, const char *);
160 confirm(const char *cmd, const char *file)
164 if (!interactive || confirmrest)
167 fprintf(ttyout, "%s %s [anpqy?]? ", cmd, file);
168 (void)fflush(ttyout);
169 if (fgets(line, sizeof(line), stdin) == NULL) {
171 fprintf(ttyout, "\nEOF received; %s aborted\n", mname);
175 switch (tolower((unsigned char)*line)) {
179 "Prompting off for duration of %s.\n", cmd);
183 fputs("Interactive mode: off.\n", ttyout);
187 fprintf(ttyout, "%s aborted.\n", mname);
193 " confirmation options:\n"
194 "\ta answer `yes' for the duration of %s\n"
195 "\tn answer `no' for this file\n"
196 "\tp turn off `prompt' mode\n"
197 "\tq stop the current %s\n"
198 "\ty answer `yes' for this file\n"
199 "\t? this help list\n",
201 continue; /* back to while(1) */
212 settype(int argc, char *argv[])
217 if (argc == 0 || argc > 2) {
220 fprintf(ttyout, "usage: %s [", argv[0]);
222 for (p = types; p->t_name; p++) {
223 fprintf(ttyout, "%s%s", sep, p->t_name);
226 fputs(" ]\n", ttyout);
231 fprintf(ttyout, "Using %s mode to transfer files.\n", typename);
235 for (p = types; p->t_name; p++)
236 if (strcmp(argv[1], p->t_name) == 0)
238 if (p->t_name == 0) {
239 fprintf(ttyout, "%s: unknown mode.\n", argv[1]);
243 if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
244 comret = command("TYPE %s %s", p->t_mode, p->t_arg);
246 comret = command("TYPE %s", p->t_mode);
247 if (comret == COMPLETE) {
248 (void)strlcpy(typename, p->t_name, sizeof(typename));
249 curtype = type = p->t_type;
254 * Internal form of settype; changes current type in use with server
255 * without changing our notion of the type for data transfers.
256 * Used to change to and from ascii for listings.
259 changetype(int newtype, int show)
262 int comret, oldverbose = verbose;
266 if (newtype == curtype)
268 if (debug == 0 && show == 0)
270 for (p = types; p->t_name; p++)
271 if (newtype == p->t_type)
273 if (p->t_name == 0) {
274 warnx("internal error: unknown type %d.", newtype);
277 if (newtype == TYPE_L && bytename[0] != '\0')
278 comret = command("TYPE %s %s", p->t_mode, bytename);
280 comret = command("TYPE %s", p->t_mode);
281 if (comret == COMPLETE)
283 verbose = oldverbose;
293 * Set binary transfer type.
297 setbinary(int argc, char *argv[])
301 fprintf(ttyout, "usage: %s\n", argv[0]);
310 * Set ascii transfer type.
314 setascii(int argc, char *argv[])
318 fprintf(ttyout, "usage: %s\n", argv[0]);
327 * Set tenex transfer type.
331 settenex(int argc, char *argv[])
335 fprintf(ttyout, "usage: %s\n", argv[0]);
344 * Set file transfer mode.
348 setftmode(int argc, char *argv[])
352 fprintf(ttyout, "usage: %s mode-name\n", argv[0]);
356 fprintf(ttyout, "We only support %s mode, sorry.\n", modename);
361 * Set file transfer format.
365 setform(int argc, char *argv[])
369 fprintf(ttyout, "usage: %s format\n", argv[0]);
373 fprintf(ttyout, "We only support %s format, sorry.\n", formname);
378 * Set file transfer structure.
382 setstruct(int argc, char *argv[])
386 fprintf(ttyout, "usage: %s struct-mode\n", argv[0]);
390 fprintf(ttyout, "We only support %s structure, sorry.\n", structname);
395 * Send a single file.
398 put(int argc, char *argv[])
400 char buf[MAXPATHLEN];
411 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file")))
413 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
415 fprintf(ttyout, "usage: %s local-file [remote-file]\n",
420 if ((locfile = globulize(argv[1])) == NULL) {
425 if (loc) /* If argv[2] is a copy of the old argv[1], update it */
427 cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
428 remfile = doprocess(buf, sizeof(buf), remfile,
429 0, loc && ntflag, loc && mapflag);
430 sendrequest(cmd, locfile, remfile,
431 locfile != argv[1] || remfile != argv[2]);
436 doprocess(char *dst, size_t dlen, const char *src,
437 int casef, int transf, int mapf)
440 src = docase(dst, dlen, src);
442 src = dotrans(dst, dlen, src);
444 src = domap(dst, dlen, src);
449 * Send multiple files.
452 mput(int argc, char *argv[])
459 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) {
460 fprintf(ttyout, "usage: %s local-files\n", argv[0]);
466 oldintr = xsignal(SIGINT, mintr);
467 if (sigsetjmp(jabort, 1))
472 while ((cp = remglob(argv, 0, NULL)) != NULL) {
473 if (*cp == '\0' || !connected) {
477 if (mflag && confirm(argv[0], cp)) {
478 char buf[MAXPATHLEN];
479 tp = doprocess(buf, sizeof(buf), cp,
480 mcase, ntflag, mapflag);
481 sendrequest((sunique) ? "STOU" : "STOR",
482 cp, tp, cp != tp || !interactive);
483 if (!mflag && fromatty) {
484 ointer = interactive;
486 if (confirm("Continue with", "mput")) {
489 interactive = ointer;
495 for (i = 1; i < argc && connected; i++) {
501 if (mflag && confirm(argv[0], argv[i])) {
502 char buf[MAXPATHLEN];
503 tp = doprocess(buf, sizeof(buf), argv[i],
505 sendrequest((sunique) ? "STOU" : "STOR",
506 argv[i], tp, tp != argv[i] || !interactive);
507 if (!mflag && fromatty) {
508 ointer = interactive;
510 if (confirm("Continue with", "mput")) {
513 interactive = ointer;
519 memset(&gl, 0, sizeof(gl));
520 flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE;
521 if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) {
522 warnx("%s: not found", argv[i]);
526 for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected;
528 if (mflag && confirm(argv[0], *cpp)) {
529 char buf[MAXPATHLEN];
531 tp = doprocess(buf, sizeof(buf), *cpp,
533 sendrequest((sunique) ? "STOU" : "STOR",
534 *cpp, tp, *cpp != tp || !interactive);
535 if (!mflag && fromatty) {
536 ointer = interactive;
538 if (confirm("Continue with", "mput")) {
541 interactive = ointer;
548 (void)xsignal(SIGINT, oldintr);
553 reget(int argc, char *argv[])
556 (void)getit(argc, argv, 1, "r+");
560 get(int argc, char *argv[])
563 (void)getit(argc, argv, 0, restart_point ? "r+" : "w" );
568 * If restartit is 1, restart the xfer always.
569 * If restartit is -1, restart the xfer only if the remote file is newer.
572 getit(int argc, char *argv[], int restartit, const char *mode)
575 char *remfile, *olocfile;
577 char buf[MAXPATHLEN];
585 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file")))
587 if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) {
589 fprintf(ttyout, "usage: %s remote-file [local-file]\n",
595 if ((olocfile = globulize(argv[2])) == NULL) {
599 locfile = doprocess(buf, sizeof(buf), olocfile,
600 loc && mcase, loc && ntflag, loc && mapflag);
605 if (! features[FEAT_REST_STREAM]) {
607 "Restart is not supported by the remote server.\n");
610 ret = stat(locfile, &stbuf);
611 if (restartit == 1) {
613 warn("local: %s", locfile);
616 restart_point = stbuf.st_size;
621 mtime = remotemodtime(argv[1], 0);
624 if (stbuf.st_mtime >= mtime) {
632 recvrequest("RETR", locfile, remfile, mode,
633 remfile != argv[1] || locfile != argv[2], loc);
636 (void)free(olocfile);
647 write(fileno(ttyout), "\n", 1);
648 siglongjmp(jabort, 1);
656 if (mflag && fromatty) {
657 ointer = interactive;
661 if (confirm("Continue with", mname)) {
662 interactive = ointer;
666 interactive = ointer;
673 * Get multiple files.
676 mget(int argc, char *argv[])
685 (argc == 1 && !another(&argc, &argv, "remote-files"))) {
686 fprintf(ttyout, "usage: %s remote-files\n", argv[0]);
694 if (strcmp(argv[0], "mreget") == 0) {
695 if (! features[FEAT_REST_STREAM]) {
697 "Restart is not supported by the remote server.\n");
702 oldintr = xsignal(SIGINT, mintr);
703 if (sigsetjmp(jabort, 1))
705 while ((cp = remglob(argv, proxy, NULL)) != NULL) {
706 char buf[MAXPATHLEN];
707 if (*cp == '\0' || !connected) {
713 if (! fileindir(cp, localcwd)) {
714 fprintf(ttyout, "Skipping non-relative filename `%s'\n",
718 if (!confirm(argv[0], cp))
720 tp = doprocess(buf, sizeof(buf), cp, mcase, ntflag, mapflag);
724 if (stat(tp, &stbuf) == 0)
725 restart_point = stbuf.st_size;
729 recvrequest("RETR", tp, cp, restart_point ? "r+" : "w",
730 tp != cp || !interactive, 1);
732 if (!mflag && fromatty) {
733 ointer = interactive;
735 if (confirm("Continue with", "mget"))
737 interactive = ointer;
740 (void)xsignal(SIGINT, oldintr);
745 * Read list of filenames from a local file and get those
748 fget(int argc, char *argv[])
754 fprintf(ttyout, "usage: %s localfile\n", argv[0]);
759 fp = fopen(argv[1], "r");
761 fprintf(ttyout, "Cannot open source file %s\n", argv[1]);
767 mode = restart_point ? "r+" : "w";
770 (buf = fparseln(fp, NULL, NULL, "\0\0\0", 0)) != NULL;
775 (void)getit(argc, argv, 0, mode);
784 return (bool ? "on" : "off");
792 status(int argc, char *argv[])
796 fprintf(ttyout, "usage: %s\n", argv[0]);
802 fprintf(ttyout, "Connected %sto %s.\n",
803 connected == -1 ? "and logged in" : "", hostname);
805 fputs("Not connected.\n", ttyout);
809 fprintf(ttyout, "Connected for proxy commands to %s.\n",
813 fputs("No proxy connection.\n", ttyout);
817 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode),
818 *gateserver ? gateserver : "(none)", gateport);
819 fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n",
820 onoff(passivemode), onoff(activefallback));
821 fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n",
822 modename, typename, formname, structname);
823 fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n",
824 onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob));
825 fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n",
826 onoff(sunique), onoff(runique));
827 fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve));
828 fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase),
831 fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout);
834 fputs("Ntrans: off.\n", ttyout);
837 fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout);
840 fputs("Nmap: off.\n", ttyout);
843 "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n",
844 onoff(hash), mark, onoff(progress));
846 "Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
847 onoff(rate_get), rate_get, rate_get_incr);
849 "Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
850 onoff(rate_put), rate_put, rate_put_incr);
852 "Socket buffer sizes: send %d, receive %d.\n",
853 sndbuf_size, rcvbuf_size);
854 fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport));
855 fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4),
856 epsv4bad ? " (disabled for this connection)" : "");
857 fprintf(ttyout, "Command line editing: %s.\n",
858 #ifdef NO_EDITCOMPLETE
859 "support not compiled in"
860 #else /* !def NO_EDITCOMPLETE */
862 #endif /* !def NO_EDITCOMPLETE */
867 fputs("Macros:\n", ttyout);
868 for (i=0; i<macnum; i++) {
869 fprintf(ttyout, "\t%s\n", macros[i].mac_name);
872 #endif /* !def NO_STATUS */
873 fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION);
881 togglevar(int argc, char *argv[], int *var, const char *mesg)
885 } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) {
887 } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) {
890 fprintf(ttyout, "usage: %s [ on | off ]\n", argv[0]);
894 fprintf(ttyout, "%s %s.\n", mesg, onoff(*var));
899 * Set beep on cmd completed mode.
903 setbell(int argc, char *argv[])
906 code = togglevar(argc, argv, &bell, "Bell mode");
910 * Set command line editing
914 setedit(int argc, char *argv[])
917 #ifdef NO_EDITCOMPLETE
919 fprintf(ttyout, "usage: %s\n", argv[0]);
924 fputs("Editing support not compiled in; ignoring command.\n",
926 #else /* !def NO_EDITCOMPLETE */
927 code = togglevar(argc, argv, &editing, "Editing mode");
929 #endif /* !def NO_EDITCOMPLETE */
933 * Turn on packet tracing.
937 settrace(int argc, char *argv[])
940 code = togglevar(argc, argv, &trace, "Packet tracing");
944 * Toggle hash mark printing during transfers, or set hash mark bytecount.
948 sethash(int argc, char *argv[])
952 else if (argc != 2) {
953 fprintf(ttyout, "usage: %s [ on | off | bytecount ]\n",
957 } else if (strcasecmp(argv[1], "on") == 0)
959 else if (strcasecmp(argv[1], "off") == 0)
964 nmark = strsuftoi(argv[1]);
966 fprintf(ttyout, "mark: bad bytecount value `%s'.\n",
974 fprintf(ttyout, "Hash mark printing %s", onoff(hash));
976 fprintf(ttyout, " (%d bytes/hash mark)", mark);
977 fputs(".\n", ttyout);
984 * Turn on printing of server echo's.
988 setverbose(int argc, char *argv[])
991 code = togglevar(argc, argv, &verbose, "Verbose mode");
995 * Toggle PORT/LPRT cmd use before each data connection.
999 setport(int argc, char *argv[])
1002 code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds");
1006 * Toggle transfer progress bar.
1010 setprogress(int argc, char *argv[])
1013 code = togglevar(argc, argv, &progress, "Progress bar");
1019 * Turn on interactive prompting during mget, mput, and mdelete.
1023 setprompt(int argc, char *argv[])
1026 code = togglevar(argc, argv, &interactive, "Interactive mode");
1030 * Toggle gate-ftp mode, or set gate-ftp server
1034 setgate(int argc, char *argv[])
1036 static char gsbuf[MAXHOSTNAMELEN];
1038 if (argc == 0 || argc > 3) {
1040 "usage: %s [ on | off | gateserver [port] ]\n", argv[0]);
1043 } else if (argc < 2) {
1044 gatemode = !gatemode;
1046 if (argc == 2 && strcasecmp(argv[1], "on") == 0)
1048 else if (argc == 2 && strcasecmp(argv[1], "off") == 0)
1052 gateport = xstrdup(argv[2]);
1053 (void)strlcpy(gsbuf, argv[1], sizeof(gsbuf));
1058 if (gatemode && (gateserver == NULL || *gateserver == '\0')) {
1060 "Disabling gate-ftp mode - no gate-ftp server defined.\n");
1063 fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n",
1064 onoff(gatemode), *gateserver ? gateserver : "(none)",
1071 * Toggle metacharacter interpretation on local file names.
1075 setglob(int argc, char *argv[])
1078 code = togglevar(argc, argv, &doglob, "Globbing");
1082 * Toggle preserving modification times on retrieved files.
1086 setpreserve(int argc, char *argv[])
1089 code = togglevar(argc, argv, &preserve, "Preserve modification times");
1093 * Set debugging mode on/off and/or set level of debugging.
1097 setdebug(int argc, char *argv[])
1099 if (argc == 0 || argc > 2) {
1100 fprintf(ttyout, "usage: %s [ on | off | debuglevel ]\n",
1104 } else if (argc == 2) {
1105 if (strcasecmp(argv[1], "on") == 0)
1107 else if (strcasecmp(argv[1], "off") == 0)
1112 val = strsuftoi(argv[1]);
1114 fprintf(ttyout, "%s: bad debugging value.\n",
1124 options |= SO_DEBUG;
1126 options &= ~SO_DEBUG;
1127 fprintf(ttyout, "Debugging %s (debug=%d).\n", onoff(debug), debug);
1132 * Set current working directory on remote machine.
1135 cd(int argc, char *argv[])
1139 if (argc == 0 || argc > 2 ||
1140 (argc == 1 && !another(&argc, &argv, "remote-directory"))) {
1141 fprintf(ttyout, "usage: %s remote-directory\n", argv[0]);
1145 r = command("CWD %s", argv[1]);
1146 if (r == ERROR && code == 500) {
1148 fputs("CWD command not recognized, trying XCWD.\n",
1150 r = command("XCWD %s", argv[1]);
1152 if (r == COMPLETE) {
1159 * Set current working directory on local machine.
1162 lcd(int argc, char *argv[])
1169 argv[1] = localhome;
1172 fprintf(ttyout, "usage: %s [local-directory]\n", argv[0]);
1175 if ((locdir = globulize(argv[1])) == NULL)
1177 if (chdir(locdir) == -1)
1178 warn("lcd %s", locdir);
1182 fprintf(ttyout, "Local directory now: %s\n", localcwd);
1185 fprintf(ttyout, "Unable to determine local directory\n");
1192 * Delete a single file.
1195 delete(int argc, char *argv[])
1198 if (argc == 0 || argc > 2 ||
1199 (argc == 1 && !another(&argc, &argv, "remote-file"))) {
1200 fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
1204 if (command("DELE %s", argv[1]) == COMPLETE)
1209 * Delete multiple files.
1212 mdelete(int argc, char *argv[])
1219 (argc == 1 && !another(&argc, &argv, "remote-files"))) {
1220 fprintf(ttyout, "usage: %s [remote-files]\n", argv[0]);
1226 oldintr = xsignal(SIGINT, mintr);
1227 if (sigsetjmp(jabort, 1))
1229 while ((cp = remglob(argv, 0, NULL)) != NULL) {
1234 if (mflag && confirm(argv[0], cp)) {
1235 if (command("DELE %s", cp) == COMPLETE)
1237 if (!mflag && fromatty) {
1238 ointer = interactive;
1240 if (confirm("Continue with", "mdelete")) {
1243 interactive = ointer;
1247 (void)xsignal(SIGINT, oldintr);
1252 * Rename a remote file.
1255 renamefile(int argc, char *argv[])
1258 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name")))
1260 if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) {
1262 fprintf(ttyout, "usage: %s from-name to-name\n", argv[0]);
1266 if (command("RNFR %s", argv[1]) == CONTINUE &&
1267 command("RNTO %s", argv[2]) == COMPLETE)
1272 * Get a directory listing of remote files.
1273 * Supports being invoked as:
1279 * pdir, pls LIST |$PAGER
1280 * mmlsd MLSD |$PAGER
1283 ls(int argc, char *argv[])
1286 char *remdir, *locfile;
1287 int freelocfile, pagecmd, mlsdcmd;
1291 freelocfile = pagecmd = mlsdcmd = 0;
1293 * the only commands that start with `p' are
1294 * the `pager' versions.
1296 if (argv[0][0] == 'p')
1298 if (strcmp(argv[0] + pagecmd , "mlsd") == 0) {
1299 if (! features[FEAT_MLST]) {
1301 "MLSD is not supported by the remote server.\n");
1311 else if (strcmp(argv[0] + pagecmd, "nlist") == 0)
1320 if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) {
1322 if (pagecmd || mlsdcmd)
1324 "usage: %s [remote-path]\n", argv[0]);
1327 "usage: %s [remote-path [local-file]]\n",
1337 p = getoptionvalue("pager");
1340 len = strlen(p) + 2;
1341 locfile = xmalloc(len);
1343 (void)strlcpy(locfile + 1, p, len - 1);
1345 } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') {
1347 if ((locfile = globulize(locfile)) == NULL ||
1348 !confirm("output to local-file:", locfile)) {
1354 recvrequest(cmd, locfile, remdir, "w", 0, 0);
1356 if (freelocfile && locfile)
1357 (void)free(locfile);
1361 * Get a directory listing of multiple remote files.
1364 mls(int argc, char *argv[])
1369 char *mode, *dest, *odest;
1373 if (argc < 2 && !another(&argc, &argv, "remote-files"))
1375 if (argc < 3 && !another(&argc, &argv, "local-file")) {
1377 fprintf(ttyout, "usage: %s remote-files local-file\n", argv[0]);
1381 odest = dest = argv[argc - 1];
1382 argv[argc - 1] = NULL;
1384 if (strcmp(dest, "-") && *dest != '|')
1385 if (((dest = globulize(dest)) == NULL) ||
1386 !confirm("output to local-file:", dest)) {
1390 dolist = strcmp(argv[0], "mls");
1392 oldintr = xsignal(SIGINT, mintr);
1393 if (sigsetjmp(jabort, 1))
1395 for (i = 1; mflag && i < argc-1 && connected; i++) {
1396 mode = (i == 1) ? "w" : "a";
1397 recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], mode,
1399 if (!mflag && fromatty) {
1400 ointer = interactive;
1402 if (confirm("Continue with", argv[0])) {
1405 interactive = ointer;
1408 (void)xsignal(SIGINT, oldintr);
1410 if (dest != odest) /* free up after globulize() */
1419 shell(int argc, char *argv[])
1423 char shellnam[MAXPATHLEN], *shell, *namep;
1427 fprintf(ttyout, "usage: %s [command [args]]\n", argv[0]);
1431 oldintr = xsignal(SIGINT, SIG_IGN);
1432 if ((pid = fork()) == 0) {
1433 for (pid = 3; pid < 20; pid++)
1435 (void)xsignal(SIGINT, SIG_DFL);
1436 shell = getenv("SHELL");
1438 shell = _PATH_BSHELL;
1439 namep = strrchr(shell, '/');
1444 (void)strlcpy(shellnam, namep, sizeof(shellnam));
1446 fputs(shell, ttyout);
1450 execl(shell, shellnam, "-c", altarg, (char *)0);
1453 execl(shell, shellnam, (char *)0);
1460 while (wait(&wait_status) != pid)
1462 (void)xsignal(SIGINT, oldintr);
1464 warn("Try again later");
1471 * Send new user information (re-login)
1474 user(int argc, char *argv[])
1482 (void)another(&argc, &argv, "username");
1483 if (argc < 2 || argc > 4) {
1485 fprintf(ttyout, "usage: %s username [password [account]]\n",
1490 n = command("USER %s", argv[1]);
1491 if (n == CONTINUE) {
1493 argv[2] = getpass("Password: ");
1496 n = command("PASS %s", argv[2]);
1498 if (n == CONTINUE) {
1500 (void)fputs("Account: ", ttyout);
1501 (void)fflush(ttyout);
1502 if (fgets(acct, sizeof(acct) - 1, stdin) == NULL) {
1504 "\nEOF received; login aborted.\n");
1509 acct[strlen(acct) - 1] = '\0';
1510 argv[3] = acct; argc++;
1512 n = command("ACCT %s", argv[3]);
1515 if (n != COMPLETE) {
1516 fputs("Login failed.\n", ttyout);
1519 if (!aflag && argc == 4) {
1520 (void)command("ACCT %s", argv[3]);
1527 * Print working directory on remote machine.
1531 pwd(int argc, char *argv[])
1536 fprintf(ttyout, "usage: %s\n", argv[0]);
1542 fprintf(ttyout, "Unable to determine remote directory\n");
1544 fprintf(ttyout, "Remote directory: %s\n", remotecwd);
1550 * Print working directory on local machine.
1553 lpwd(int argc, char *argv[])
1558 fprintf(ttyout, "usage: %s\n", argv[0]);
1564 fprintf(ttyout, "Unable to determine local directory\n");
1566 fprintf(ttyout, "Local directory: %s\n", localcwd);
1575 makedir(int argc, char *argv[])
1579 if (argc == 0 || argc > 2 ||
1580 (argc == 1 && !another(&argc, &argv, "directory-name"))) {
1581 fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1585 r = command("MKD %s", argv[1]);
1586 if (r == ERROR && code == 500) {
1588 fputs("MKD command not recognized, trying XMKD.\n",
1590 r = command("XMKD %s", argv[1]);
1597 * Remove a directory.
1600 removedir(int argc, char *argv[])
1604 if (argc == 0 || argc > 2 ||
1605 (argc == 1 && !another(&argc, &argv, "directory-name"))) {
1606 fprintf(ttyout, "usage: %s directory-name\n", argv[0]);
1610 r = command("RMD %s", argv[1]);
1611 if (r == ERROR && code == 500) {
1613 fputs("RMD command not recognized, trying XRMD.\n",
1615 r = command("XRMD %s", argv[1]);
1622 * Send a line, verbatim, to the remote machine.
1625 quote(int argc, char *argv[])
1629 (argc == 1 && !another(&argc, &argv, "command line to send"))) {
1630 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]);
1634 quote1("", argc, argv);
1638 * Send a SITE command to the remote machine. The line
1639 * is sent verbatim to the remote machine, except that the
1640 * word "SITE" is added at the front.
1643 site(int argc, char *argv[])
1647 (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){
1648 fprintf(ttyout, "usage: %s line-to-send\n", argv[0]);
1652 quote1("SITE ", argc, argv);
1656 * Turn argv[1..argc) into a space-separated string, then prepend initial text.
1657 * Send the result as a one-line command and get response.
1660 quote1(const char *initial, int argc, char *argv[])
1663 char buf[BUFSIZ]; /* must be >= sizeof(line) */
1665 (void)strlcpy(buf, initial, sizeof(buf));
1666 for (i = 1; i < argc; i++) {
1667 (void)strlcat(buf, argv[i], sizeof(buf));
1669 (void)strlcat(buf, " ", sizeof(buf));
1671 if (command("%s", buf) == PRELIM) {
1672 while (getreply(0) == PRELIM)
1679 do_chmod(int argc, char *argv[])
1682 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode")))
1684 if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) {
1686 fprintf(ttyout, "usage: %s mode remote-file\n", argv[0]);
1690 (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
1693 #define COMMAND_1ARG(argc, argv, cmd) \
1697 command(cmd " %s", argv[1])
1700 do_umask(int argc, char *argv[])
1702 int oldverbose = verbose;
1705 fprintf(ttyout, "usage: %s [umask]\n", argv[0]);
1710 COMMAND_1ARG(argc, argv, "SITE UMASK");
1711 verbose = oldverbose;
1715 idlecmd(int argc, char *argv[])
1717 int oldverbose = verbose;
1719 if (argc < 1 || argc > 2) {
1720 fprintf(ttyout, "usage: %s [seconds]\n", argv[0]);
1725 COMMAND_1ARG(argc, argv, "SITE IDLE");
1726 verbose = oldverbose;
1730 * Ask the other side for help.
1733 rmthelp(int argc, char *argv[])
1735 int oldverbose = verbose;
1738 fprintf(ttyout, "usage: %s\n", argv[0]);
1743 COMMAND_1ARG(argc, argv, "HELP");
1744 verbose = oldverbose;
1748 * Terminate session and exit.
1749 * May be called with 0, NULL.
1753 quit(int argc, char *argv[])
1756 /* this may be called with argc == 0, argv == NULL */
1757 if (argc == 0 && argv != NULL) {
1758 fprintf(ttyout, "usage: %s\n", argv[0]);
1763 disconnect(0, NULL);
1766 disconnect(0, NULL);
1771 * Terminate session, but don't exit.
1772 * May be called with 0, NULL.
1775 disconnect(int argc, char *argv[])
1778 /* this may be called with argc == 0, argv == NULL */
1779 if (argc == 0 && argv != NULL) {
1780 fprintf(ttyout, "usage: %s\n", argv[0]);
1786 (void)command("QUIT");
1791 account(int argc, char *argv[])
1795 if (argc == 0 || argc > 2) {
1796 fprintf(ttyout, "usage: %s [password]\n", argv[0]);
1803 ap = getpass("Account:");
1804 (void)command("ACCT %s", ap);
1807 sigjmp_buf abortprox;
1810 proxabort(int notused)
1825 siglongjmp(abortprox, 1);
1829 doproxy(int argc, char *argv[])
1835 if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) {
1836 fprintf(ttyout, "usage: %s command\n", argv[0]);
1840 c = getcmd(argv[1]);
1841 if (c == (struct cmd *) -1) {
1842 fputs("?Ambiguous command.\n", ttyout);
1847 fputs("?Invalid command.\n", ttyout);
1852 fputs("?Invalid proxy command.\n", ttyout);
1856 if (sigsetjmp(abortprox, 1)) {
1860 oldintr = xsignal(SIGINT, proxabort);
1862 if (c->c_conn && !connected) {
1863 fputs("Not connected.\n", ttyout);
1865 (void)xsignal(SIGINT, oldintr);
1869 cmdpos = strcspn(line, " \t");
1870 if (cmdpos > 0) /* remove leading "proxy " from input buffer */
1871 memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1);
1872 argv[1] = c->c_name;
1873 (*c->c_handler)(argc-1, argv+1);
1881 (void)xsignal(SIGINT, oldintr);
1885 setcase(int argc, char *argv[])
1888 code = togglevar(argc, argv, &mcase, "Case mapping");
1892 * convert the given name to lower case if it's all upper case, into
1893 * a static buffer which is returned to the caller
1896 docase(char *dst, size_t dlen, const char *src)
1901 for (i = 0; src[i] != '\0' && i < dlen - 1; i++) {
1903 if (islower((unsigned char)dst[i]))
1909 for (i = 0; dst[i] != '\0'; i++)
1910 if (isupper((unsigned char)dst[i]))
1911 dst[i] = tolower((unsigned char)dst[i]);
1917 setcr(int argc, char *argv[])
1920 code = togglevar(argc, argv, &crflag, "Carriage Return stripping");
1924 setntrans(int argc, char *argv[])
1927 if (argc == 0 || argc > 3) {
1928 fprintf(ttyout, "usage: %s [inchars [outchars]]\n", argv[0]);
1934 fputs("Ntrans off.\n", ttyout);
1940 (void)strlcpy(ntin, argv[1], sizeof(ntin));
1945 (void)strlcpy(ntout, argv[2], sizeof(ntout));
1949 dotrans(char *dst, size_t dlen, const char *src)
1955 for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++)
1957 for (cp1 = src; *cp1; cp1++) {
1959 for (i = 0; *(ntin + i) && i < 16; i++) {
1960 if (*cp1 == *(ntin + i)) {
1963 *cp2++ = *(ntout + i);
1964 if (cp2 - dst >= dlen - 1)
1980 setnmap(int argc, char *argv[])
1986 fputs("Nmap off.\n", ttyout);
1991 (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) {
1992 fprintf(ttyout, "usage: %s [mapin mapout]\n", argv[0]);
1998 cp = strchr(altarg, ' ');
2003 cp = strchr(altarg, ' ');
2006 (void)strlcpy(mapin, altarg, MAXPATHLEN);
2007 while (*++cp == ' ')
2009 (void)strlcpy(mapout, cp, MAXPATHLEN);
2013 domap(char *dst, size_t dlen, const char *src)
2015 const char *cp1 = src;
2017 const char *tp[9], *te[9];
2018 int i, toks[9], toknum = 0, match = 1;
2020 for (i=0; i < 9; ++i) {
2023 while (match && *cp1 && *cp2) {
2026 if (*++cp2 != *cp1) {
2031 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
2032 if (*cp1 != *(++cp2+1)) {
2033 toks[toknum = *cp2 - '1']++;
2035 while (*++cp1 && *(cp2+1)
2049 if (match && *cp1) {
2052 if (match && *cp2) {
2056 if (!match && *cp1) /* last token mismatch */
2073 if (*++cp1 == '$' &&
2074 isdigit((unsigned char)*(cp1+1))) {
2075 if (*++cp1 == '0') {
2076 const char *cp3 = src;
2083 else if (toks[toknum = *cp1 - '1']) {
2084 const char *cp3 = tp[toknum];
2086 while (cp3 != te[toknum]) {
2093 while (*cp1 && *cp1 != ',' &&
2098 else if (*cp1 == '$' &&
2099 isdigit((unsigned char)*(cp1+1))) {
2100 if (*++cp1 == '0') {
2101 const char *cp3 = src;
2107 else if (toks[toknum =
2109 const char *cp3=tp[toknum];
2123 "nmap: unbalanced brackets.\n",
2131 while (*++cp1 && *cp1 != ']') {
2132 if (*cp1 == '\\' && *(cp1 + 1)) {
2138 "nmap: unbalanced brackets.\n",
2155 if (isdigit((unsigned char)*(cp1 + 1))) {
2156 if (*++cp1 == '0') {
2157 const char *cp3 = src;
2163 else if (toks[toknum = *cp1 - '1']) {
2164 const char *cp3 = tp[toknum];
2166 while (cp3 != te[toknum]) {
2172 /* intentional drop through */
2180 return *dst ? dst : src;
2184 setpassive(int argc, char *argv[])
2188 passivemode = !passivemode;
2189 activefallback = passivemode;
2190 } else if (argc != 2) {
2192 fprintf(ttyout, "usage: %s [ on | off | auto ]\n", argv[0]);
2195 } else if (strcasecmp(argv[1], "on") == 0) {
2198 } else if (strcasecmp(argv[1], "off") == 0) {
2201 } else if (strcasecmp(argv[1], "auto") == 0) {
2206 fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n",
2207 onoff(passivemode), onoff(activefallback));
2212 setepsv4(int argc, char *argv[])
2215 code = togglevar(argc, argv, &epsv4,
2216 verbose ? "EPSV/EPRT on IPv4" : NULL);
2221 setsunique(int argc, char *argv[])
2224 code = togglevar(argc, argv, &sunique, "Store unique");
2228 setrunique(int argc, char *argv[])
2231 code = togglevar(argc, argv, &runique, "Receive unique");
2235 parserate(int argc, char *argv[], int cmdlineopt)
2237 int dir, max, incr, showonly;
2238 sigfunc oldusr1, oldusr2;
2240 if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) {
2244 "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n",
2248 "usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n",
2252 dir = max = incr = showonly = 0;
2255 #define RATE_ALL (RATE_GET | RATE_PUT)
2257 if (strcasecmp(argv[1], "all") == 0)
2259 else if (strcasecmp(argv[1], "get") == 0)
2261 else if (strcasecmp(argv[1], "put") == 0)
2267 if ((max = strsuftoi(argv[2])) < 0)
2273 if ((incr = strsuftoi(argv[3])) <= 0)
2278 oldusr1 = xsignal(SIGUSR1, SIG_IGN);
2279 oldusr2 = xsignal(SIGUSR2, SIG_IGN);
2280 if (dir & RATE_GET) {
2283 rate_get_incr = incr;
2285 if (!cmdlineopt || verbose)
2287 "Get transfer rate throttle: %s; maximum: %d; increment %d.\n",
2288 onoff(rate_get), rate_get, rate_get_incr);
2290 if (dir & RATE_PUT) {
2293 rate_put_incr = incr;
2295 if (!cmdlineopt || verbose)
2297 "Put transfer rate throttle: %s; maximum: %d; increment %d.\n",
2298 onoff(rate_put), rate_put, rate_put_incr);
2300 (void)xsignal(SIGUSR1, oldusr1);
2301 (void)xsignal(SIGUSR2, oldusr2);
2306 setrate(int argc, char *argv[])
2309 code = parserate(argc, argv, 0);
2312 /* change directory to parent directory */
2314 cdup(int argc, char *argv[])
2319 fprintf(ttyout, "usage: %s\n", argv[0]);
2323 r = command("CDUP");
2324 if (r == ERROR && code == 500) {
2326 fputs("CDUP command not recognized, trying XCUP.\n",
2328 r = command("XCUP");
2330 if (r == COMPLETE) {
2337 * Restart transfer at specific point
2340 restart(int argc, char *argv[])
2343 if (argc == 0 || argc > 2) {
2344 fprintf(ttyout, "usage: %s [restart-point]\n", argv[0]);
2348 if (! features[FEAT_REST_STREAM]) {
2350 "Restart is not supported by the remote server.\n");
2357 rp = STRTOLL(argv[1], &ep, 10);
2358 if (rp < 0 || *ep != '\0')
2359 fprintf(ttyout, "restart: Invalid offset `%s'\n",
2364 if (restart_point == 0)
2365 fputs("No restart point defined.\n", ttyout);
2368 "Restarting at " LLF " for next get, put or append\n",
2369 (LLT)restart_point);
2373 * Show remote system type
2376 syst(int argc, char *argv[])
2378 int oldverbose = verbose;
2381 fprintf(ttyout, "usage: %s\n", argv[0]);
2385 verbose = 1; /* If we aren't verbose, this doesn't do anything! */
2386 (void)command("SYST");
2387 verbose = oldverbose;
2391 macdef(int argc, char *argv[])
2399 fputs("Limit of 16 macros have already been defined.\n",
2404 if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) {
2406 fprintf(ttyout, "usage: %s macro_name\n", argv[0]);
2412 "Enter macro line by line, terminating it with a null line.\n",
2414 (void)strlcpy(macros[macnum].mac_name, argv[1],
2415 sizeof(macros[macnum].mac_name));
2417 macros[macnum].mac_start = macbuf;
2419 macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
2420 tmp = macros[macnum].mac_start;
2421 while (tmp != macbuf+4096) {
2422 if ((c = getchar()) == EOF) {
2423 fputs("macdef: end of file encountered.\n", ttyout);
2427 if ((*tmp = c) == '\n') {
2428 if (tmp == macros[macnum].mac_start) {
2429 macros[macnum++].mac_end = tmp;
2433 if (*(tmp-1) == '\0') {
2434 macros[macnum++].mac_end = tmp - 1;
2443 while ((c = getchar()) != '\n' && c != EOF)
2445 if (c == EOF || getchar() == '\n') {
2446 fputs("Macro not defined - 4K buffer exceeded.\n",
2455 * Get size of file on remote machine
2458 sizecmd(int argc, char *argv[])
2462 if (argc == 0 || argc > 2 ||
2463 (argc == 1 && !another(&argc, &argv, "remote-file"))) {
2464 fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
2468 size = remotesize(argv[1], 1);
2471 "%s\t" LLF "\n", argv[1], (LLT)size);
2476 * Get last modification time of file on remote machine
2479 modtime(int argc, char *argv[])
2483 if (argc == 0 || argc > 2 ||
2484 (argc == 1 && !another(&argc, &argv, "remote-file"))) {
2485 fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
2489 mtime = remotemodtime(argv[1], 1);
2491 fprintf(ttyout, "%s\t%s", argv[1], asctime(localtime(&mtime)));
2496 * Show status on remote machine
2499 rmtstatus(int argc, char *argv[])
2503 fprintf(ttyout, "usage: %s [remote-file]\n", argv[0]);
2507 COMMAND_1ARG(argc, argv, "STAT");
2511 * Get file if modtime is more recent than current file
2514 newer(int argc, char *argv[])
2517 if (getit(argc, argv, -1, "w"))
2519 "Local file \"%s\" is newer than remote file \"%s\".\n",
2524 * Display one local file through $PAGER.
2527 lpage(int argc, char *argv[])
2530 char *p, *pager, *locfile;
2532 if (argc == 0 || argc > 2 ||
2533 (argc == 1 && !another(&argc, &argv, "local-file"))) {
2534 fprintf(ttyout, "usage: %s local-file\n", argv[0]);
2538 if ((locfile = globulize(argv[1])) == NULL) {
2542 p = getoptionvalue("pager");
2545 len = strlen(p) + strlen(locfile) + 2;
2546 pager = xmalloc(len);
2547 (void)strlcpy(pager, p, len);
2548 (void)strlcat(pager, " ", len);
2549 (void)strlcat(pager, locfile, len);
2553 (void)free(locfile);
2557 * Display one remote file through $PAGER.
2560 page(int argc, char *argv[])
2562 int ohash, orestart_point, overbose, len;
2565 if (argc == 0 || argc > 2 ||
2566 (argc == 1 && !another(&argc, &argv, "remote-file"))) {
2567 fprintf(ttyout, "usage: %s remote-file\n", argv[0]);
2571 p = getoptionvalue("pager");
2574 len = strlen(p) + 2;
2575 pager = xmalloc(len);
2577 (void)strlcpy(pager + 1, p, len - 1);
2580 orestart_point = restart_point;
2582 hash = restart_point = verbose = 0;
2583 recvrequest("RETR", pager, argv[1], "r+", 1, 0);
2585 restart_point = orestart_point;
2591 * Set the socket send or receive buffer size.
2594 setxferbuf(int argc, char *argv[])
2600 fprintf(ttyout, "usage: %s size\n", argv[0]);
2604 if (strcasecmp(argv[0], "sndbuf") == 0)
2606 else if (strcasecmp(argv[0], "rcvbuf") == 0)
2608 else if (strcasecmp(argv[0], "xferbuf") == 0)
2613 if ((size = strsuftoi(argv[1])) == -1)
2617 fprintf(ttyout, "%s: size must be positive.\n", argv[0]);
2625 fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n",
2626 sndbuf_size, rcvbuf_size);
2631 * Set or display options (defaults are provided by various env vars)
2634 setoption(int argc, char *argv[])
2639 if (argc == 0 || (argc != 1 && argc != 3)) {
2640 fprintf(ttyout, "usage: %s [option value]\n", argv[0]);
2644 #define OPTIONINDENT ((int) sizeof("http_proxy"))
2646 for (o = optiontab; o->name != NULL; o++) {
2647 fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT,
2648 o->name, o->value ? o->value : "");
2651 o = getoption(argv[1]);
2653 fprintf(ttyout, "No such option `%s'.\n", argv[1]);
2657 o->value = xstrdup(argv[2]);
2659 fprintf(ttyout, "Setting `%s' to `%s'.\n",
2669 unsetoption(int argc, char *argv[])
2674 if (argc == 0 || argc != 2) {
2675 fprintf(ttyout, "usage: %s option\n", argv[0]);
2679 o = getoption(argv[1]);
2681 fprintf(ttyout, "No such option `%s'.\n", argv[1]);
2685 fprintf(ttyout, "Unsetting `%s'.\n", o->name);
2690 * Display features supported by the remote host.
2693 feat(int argc, char *argv[])
2695 int oldverbose = verbose;
2698 fprintf(ttyout, "usage: %s\n", argv[0]);
2702 if (! features[FEAT_FEAT]) {
2704 "FEAT is not supported by the remote server.\n");
2707 verbose = 1; /* If we aren't verbose, this doesn't do anything! */
2708 (void)command("FEAT");
2709 verbose = oldverbose;
2713 mlst(int argc, char *argv[])
2715 int oldverbose = verbose;
2717 if (argc < 1 || argc > 2) {
2718 fprintf(ttyout, "usage: %s [remote-path]\n", argv[0]);
2722 if (! features[FEAT_MLST]) {
2724 "MLST is not supported by the remote server.\n");
2727 verbose = 1; /* If we aren't verbose, this doesn't do anything! */
2728 COMMAND_1ARG(argc, argv, "MLST");
2729 verbose = oldverbose;
2733 opts(int argc, char *argv[])
2735 int oldverbose = verbose;
2737 if (argc < 2 || argc > 3) {
2738 fprintf(ttyout, "usage: %s command [options]\n", argv[0]);
2742 if (! features[FEAT_FEAT]) {
2744 "OPTS is not supported by the remote server.\n");
2747 verbose = 1; /* If we aren't verbose, this doesn't do anything! */
2749 command("OPTS %s", argv[1]);
2751 command("OPTS %s %s", argv[1], argv[2]);
2752 verbose = oldverbose;