1223328Sgavin/* $NetBSD: cmds.c,v 1.17 2010/01/12 06:55:47 lukem Exp $ */ 2223328Sgavin/* from NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp */ 379971Sobrien 479971Sobrien/*- 5223328Sgavin * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. 679971Sobrien * All rights reserved. 779971Sobrien * 879971Sobrien * This code is derived from software contributed to The NetBSD Foundation 979971Sobrien * by Luke Mewburn. 1079971Sobrien * 1179971Sobrien * This code is derived from software contributed to The NetBSD Foundation 1279971Sobrien * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 1379971Sobrien * NASA Ames Research Center. 1479971Sobrien * 1579971Sobrien * Redistribution and use in source and binary forms, with or without 1679971Sobrien * modification, are permitted provided that the following conditions 1779971Sobrien * are met: 1879971Sobrien * 1. Redistributions of source code must retain the above copyright 1979971Sobrien * notice, this list of conditions and the following disclaimer. 2079971Sobrien * 2. Redistributions in binary form must reproduce the above copyright 2179971Sobrien * notice, this list of conditions and the following disclaimer in the 2279971Sobrien * documentation and/or other materials provided with the distribution. 2379971Sobrien * 2479971Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 2579971Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 2679971Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2779971Sobrien * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 2879971Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2979971Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3079971Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 3179971Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 3279971Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 3379971Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 3479971Sobrien * POSSIBILITY OF SUCH DAMAGE. 3579971Sobrien */ 3679971Sobrien 3779971Sobrien/* 3879971Sobrien * Copyright (c) 1985, 1989, 1993, 1994 3979971Sobrien * The Regents of the University of California. All rights reserved. 4079971Sobrien * 4179971Sobrien * Redistribution and use in source and binary forms, with or without 4279971Sobrien * modification, are permitted provided that the following conditions 4379971Sobrien * are met: 4479971Sobrien * 1. Redistributions of source code must retain the above copyright 4579971Sobrien * notice, this list of conditions and the following disclaimer. 4679971Sobrien * 2. Redistributions in binary form must reproduce the above copyright 4779971Sobrien * notice, this list of conditions and the following disclaimer in the 4879971Sobrien * documentation and/or other materials provided with the distribution. 49121966Smikeh * 3. Neither the name of the University nor the names of its contributors 5079971Sobrien * may be used to endorse or promote products derived from this software 5179971Sobrien * without specific prior written permission. 5279971Sobrien * 5379971Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5479971Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5579971Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5679971Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5779971Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5879971Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5979971Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6079971Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6179971Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6279971Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6379971Sobrien * SUCH DAMAGE. 6479971Sobrien */ 6579971Sobrien 6679971Sobrien/* 6779971Sobrien * Copyright (C) 1997 and 1998 WIDE Project. 6879971Sobrien * All rights reserved. 69146309Smikeh * 7079971Sobrien * Redistribution and use in source and binary forms, with or without 7179971Sobrien * modification, are permitted provided that the following conditions 7279971Sobrien * are met: 7379971Sobrien * 1. Redistributions of source code must retain the above copyright 7479971Sobrien * notice, this list of conditions and the following disclaimer. 7579971Sobrien * 2. Redistributions in binary form must reproduce the above copyright 7679971Sobrien * notice, this list of conditions and the following disclaimer in the 7779971Sobrien * documentation and/or other materials provided with the distribution. 7879971Sobrien * 3. Neither the name of the project nor the names of its contributors 7979971Sobrien * may be used to endorse or promote products derived from this software 8079971Sobrien * without specific prior written permission. 81146309Smikeh * 8279971Sobrien * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 8379971Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8479971Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 8579971Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 8679971Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 8779971Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 8879971Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 8979971Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 9079971Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 9179971Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 9279971Sobrien * SUCH DAMAGE. 9379971Sobrien */ 9479971Sobrien 95223328Sgavin#include "tnftp.h" 96223328Sgavin 97223328Sgavin#if 0 /* tnftp */ 98223328Sgavin 99116424Smikeh#include <sys/cdefs.h> 100116424Smikeh#ifndef lint 101116424Smikeh#if 0 102116424Smikehstatic char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94"; 103116424Smikeh#else 104223328Sgavin__RCSID(" NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp "); 105116424Smikeh#endif 106116424Smikeh#endif /* not lint */ 107116424Smikeh 10879971Sobrien/* 10979971Sobrien * FTP User Program -- Command Routines. 11079971Sobrien */ 111116424Smikeh#include <sys/types.h> 112116424Smikeh#include <sys/socket.h> 113116424Smikeh#include <sys/stat.h> 114116424Smikeh#include <sys/wait.h> 115116424Smikeh#include <arpa/ftp.h> 11679971Sobrien 117116424Smikeh#include <ctype.h> 118116424Smikeh#include <err.h> 119116424Smikeh#include <glob.h> 120116424Smikeh#include <limits.h> 121116424Smikeh#include <netdb.h> 122116424Smikeh#include <paths.h> 123223328Sgavin#include <stddef.h> 124116424Smikeh#include <stdio.h> 125116424Smikeh#include <stdlib.h> 126116424Smikeh#include <string.h> 127116424Smikeh#include <time.h> 128116424Smikeh#include <unistd.h> 12979971Sobrien 130223328Sgavin#endif /* tnftp */ 131223328Sgavin 13279971Sobrien#include "ftp_var.h" 13379971Sobrien#include "version.h" 13479971Sobrien 135223328Sgavinstatic struct types { 136223328Sgavin const char *t_name; 137223328Sgavin const char *t_mode; 138223328Sgavin int t_type; 139223328Sgavin const char *t_arg; 14079971Sobrien} types[] = { 14179971Sobrien { "ascii", "A", TYPE_A, 0 }, 14279971Sobrien { "binary", "I", TYPE_I, 0 }, 14379971Sobrien { "image", "I", TYPE_I, 0 }, 14479971Sobrien { "ebcdic", "E", TYPE_E, 0 }, 14579971Sobrien { "tenex", "L", TYPE_L, bytename }, 146223328Sgavin { NULL, NULL, 0, NULL } 14779971Sobrien}; 14879971Sobrien 149223328Sgavinstatic sigjmp_buf jabort; 15079971Sobrien 15179971Sobrienstatic int confirm(const char *, const char *); 152223328Sgavinstatic void mintr(int); 153223328Sgavinstatic void mabort(const char *); 154223328Sgavinstatic void set_type(const char *); 15579971Sobrien 156142129Smikehstatic const char *doprocess(char *, size_t, const char *, int, int, int); 157142129Smikehstatic const char *domap(char *, size_t, const char *); 158142129Smikehstatic const char *docase(char *, size_t, const char *); 159142129Smikehstatic const char *dotrans(char *, size_t, const char *); 160142129Smikeh 161223328Sgavin/* 162223328Sgavin * Confirm if "cmd" is to be performed upon "file". 163223328Sgavin * If "file" is NULL, generate a "Continue with" prompt instead. 164223328Sgavin */ 16579971Sobrienstatic int 16679971Sobrienconfirm(const char *cmd, const char *file) 16779971Sobrien{ 168223328Sgavin const char *errormsg; 169223328Sgavin char cline[BUFSIZ]; 170223328Sgavin const char *promptleft, *promptright; 17179971Sobrien 17279971Sobrien if (!interactive || confirmrest) 17379971Sobrien return (1); 174223328Sgavin if (file == NULL) { 175223328Sgavin promptleft = "Continue with"; 176223328Sgavin promptright = cmd; 177223328Sgavin } else { 178223328Sgavin promptleft = cmd; 179223328Sgavin promptright = file; 180223328Sgavin } 18179971Sobrien while (1) { 182223328Sgavin fprintf(ttyout, "%s %s [anpqy?]? ", promptleft, promptright); 18379971Sobrien (void)fflush(ttyout); 184223328Sgavin if (get_line(stdin, cline, sizeof(cline), &errormsg) < 0) { 18579971Sobrien mflag = 0; 186223328Sgavin fprintf(ttyout, "%s; %s aborted\n", errormsg, cmd); 18779971Sobrien return (0); 18879971Sobrien } 189223328Sgavin switch (tolower((unsigned char)*cline)) { 19079971Sobrien case 'a': 19179971Sobrien confirmrest = 1; 19279971Sobrien fprintf(ttyout, 19379971Sobrien "Prompting off for duration of %s.\n", cmd); 19479971Sobrien break; 19579971Sobrien case 'p': 19679971Sobrien interactive = 0; 19779971Sobrien fputs("Interactive mode: off.\n", ttyout); 19879971Sobrien break; 19979971Sobrien case 'q': 20079971Sobrien mflag = 0; 201223328Sgavin fprintf(ttyout, "%s aborted.\n", cmd); 20279971Sobrien /* FALLTHROUGH */ 20379971Sobrien case 'n': 20479971Sobrien return (0); 20579971Sobrien case '?': 20679971Sobrien fprintf(ttyout, 20779971Sobrien " confirmation options:\n" 20879971Sobrien "\ta answer `yes' for the duration of %s\n" 20979971Sobrien "\tn answer `no' for this file\n" 21079971Sobrien "\tp turn off `prompt' mode\n" 21179971Sobrien "\tq stop the current %s\n" 21279971Sobrien "\ty answer `yes' for this file\n" 21379971Sobrien "\t? this help list\n", 21479971Sobrien cmd, cmd); 21579971Sobrien continue; /* back to while(1) */ 21679971Sobrien } 21779971Sobrien return (1); 21879971Sobrien } 21979971Sobrien /* NOTREACHED */ 22079971Sobrien} 22179971Sobrien 22279971Sobrien/* 22379971Sobrien * Set transfer type. 22479971Sobrien */ 22579971Sobrienvoid 22679971Sobriensettype(int argc, char *argv[]) 22779971Sobrien{ 22879971Sobrien struct types *p; 22979971Sobrien 23079971Sobrien if (argc == 0 || argc > 2) { 231223328Sgavin const char *sep; 23279971Sobrien 233223328Sgavin UPRINTF("usage: %s [", argv[0]); 23479971Sobrien sep = " "; 23579971Sobrien for (p = types; p->t_name; p++) { 23679971Sobrien fprintf(ttyout, "%s%s", sep, p->t_name); 23779971Sobrien sep = " | "; 23879971Sobrien } 23979971Sobrien fputs(" ]\n", ttyout); 24079971Sobrien code = -1; 24179971Sobrien return; 24279971Sobrien } 24379971Sobrien if (argc < 2) { 24479971Sobrien fprintf(ttyout, "Using %s mode to transfer files.\n", typename); 24579971Sobrien code = 0; 24679971Sobrien return; 24779971Sobrien } 248223328Sgavin set_type(argv[1]); 249223328Sgavin} 250223328Sgavin 251223328Sgavinvoid 252223328Sgavinset_type(const char *ttype) 253223328Sgavin{ 254223328Sgavin struct types *p; 255223328Sgavin int comret; 256223328Sgavin 25779971Sobrien for (p = types; p->t_name; p++) 258223328Sgavin if (strcmp(ttype, p->t_name) == 0) 25979971Sobrien break; 26079971Sobrien if (p->t_name == 0) { 261223328Sgavin fprintf(ttyout, "%s: unknown mode.\n", ttype); 26279971Sobrien code = -1; 26379971Sobrien return; 26479971Sobrien } 26579971Sobrien if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 26679971Sobrien comret = command("TYPE %s %s", p->t_mode, p->t_arg); 26779971Sobrien else 26879971Sobrien comret = command("TYPE %s", p->t_mode); 26979971Sobrien if (comret == COMPLETE) { 27079971Sobrien (void)strlcpy(typename, p->t_name, sizeof(typename)); 27179971Sobrien curtype = type = p->t_type; 27279971Sobrien } 27379971Sobrien} 27479971Sobrien 27579971Sobrien/* 27679971Sobrien * Internal form of settype; changes current type in use with server 27779971Sobrien * without changing our notion of the type for data transfers. 27879971Sobrien * Used to change to and from ascii for listings. 27979971Sobrien */ 28079971Sobrienvoid 28179971Sobrienchangetype(int newtype, int show) 28279971Sobrien{ 28379971Sobrien struct types *p; 28479971Sobrien int comret, oldverbose = verbose; 28579971Sobrien 28679971Sobrien if (newtype == 0) 28779971Sobrien newtype = TYPE_I; 28879971Sobrien if (newtype == curtype) 28979971Sobrien return; 290223328Sgavin if (ftp_debug == 0 && show == 0) 29179971Sobrien verbose = 0; 29279971Sobrien for (p = types; p->t_name; p++) 29379971Sobrien if (newtype == p->t_type) 29479971Sobrien break; 29579971Sobrien if (p->t_name == 0) { 296223328Sgavin errx(1, "changetype: unknown type %d", newtype); 29779971Sobrien } 29879971Sobrien if (newtype == TYPE_L && bytename[0] != '\0') 29979971Sobrien comret = command("TYPE %s %s", p->t_mode, bytename); 30079971Sobrien else 30179971Sobrien comret = command("TYPE %s", p->t_mode); 30279971Sobrien if (comret == COMPLETE) 30379971Sobrien curtype = newtype; 30479971Sobrien verbose = oldverbose; 30579971Sobrien} 30679971Sobrien 30779971Sobrien/* 30879971Sobrien * Set binary transfer type. 30979971Sobrien */ 31079971Sobrien/*VARARGS*/ 31179971Sobrienvoid 31279971Sobriensetbinary(int argc, char *argv[]) 31379971Sobrien{ 31479971Sobrien 31579971Sobrien if (argc == 0) { 316223328Sgavin UPRINTF("usage: %s\n", argv[0]); 31779971Sobrien code = -1; 31879971Sobrien return; 31979971Sobrien } 320223328Sgavin set_type("binary"); 32179971Sobrien} 32279971Sobrien 32379971Sobrien/* 32479971Sobrien * Set ascii transfer type. 32579971Sobrien */ 32679971Sobrien/*VARARGS*/ 32779971Sobrienvoid 32879971Sobriensetascii(int argc, char *argv[]) 32979971Sobrien{ 33079971Sobrien 33179971Sobrien if (argc == 0) { 332223328Sgavin UPRINTF("usage: %s\n", argv[0]); 33379971Sobrien code = -1; 33479971Sobrien return; 33579971Sobrien } 336223328Sgavin set_type("ascii"); 33779971Sobrien} 33879971Sobrien 33979971Sobrien/* 34079971Sobrien * Set tenex transfer type. 34179971Sobrien */ 34279971Sobrien/*VARARGS*/ 34379971Sobrienvoid 34479971Sobriensettenex(int argc, char *argv[]) 34579971Sobrien{ 34679971Sobrien 34779971Sobrien if (argc == 0) { 348223328Sgavin UPRINTF("usage: %s\n", argv[0]); 34979971Sobrien code = -1; 35079971Sobrien return; 35179971Sobrien } 352223328Sgavin set_type("tenex"); 35379971Sobrien} 35479971Sobrien 35579971Sobrien/* 35679971Sobrien * Set file transfer mode. 35779971Sobrien */ 35879971Sobrien/*ARGSUSED*/ 35979971Sobrienvoid 36079971Sobriensetftmode(int argc, char *argv[]) 36179971Sobrien{ 36279971Sobrien 36379971Sobrien if (argc != 2) { 364223328Sgavin UPRINTF("usage: %s mode-name\n", argv[0]); 36579971Sobrien code = -1; 36679971Sobrien return; 36779971Sobrien } 36879971Sobrien fprintf(ttyout, "We only support %s mode, sorry.\n", modename); 36979971Sobrien code = -1; 37079971Sobrien} 37179971Sobrien 37279971Sobrien/* 37379971Sobrien * Set file transfer format. 37479971Sobrien */ 37579971Sobrien/*ARGSUSED*/ 37679971Sobrienvoid 37779971Sobriensetform(int argc, char *argv[]) 37879971Sobrien{ 37979971Sobrien 38079971Sobrien if (argc != 2) { 381223328Sgavin UPRINTF("usage: %s format\n", argv[0]); 38279971Sobrien code = -1; 38379971Sobrien return; 38479971Sobrien } 38579971Sobrien fprintf(ttyout, "We only support %s format, sorry.\n", formname); 38679971Sobrien code = -1; 38779971Sobrien} 38879971Sobrien 38979971Sobrien/* 39079971Sobrien * Set file transfer structure. 39179971Sobrien */ 39279971Sobrien/*ARGSUSED*/ 39379971Sobrienvoid 39479971Sobriensetstruct(int argc, char *argv[]) 39579971Sobrien{ 39679971Sobrien 39779971Sobrien if (argc != 2) { 398223328Sgavin UPRINTF("usage: %s struct-mode\n", argv[0]); 39979971Sobrien code = -1; 40079971Sobrien return; 40179971Sobrien } 40279971Sobrien fprintf(ttyout, "We only support %s structure, sorry.\n", structname); 40379971Sobrien code = -1; 40479971Sobrien} 40579971Sobrien 40679971Sobrien/* 40779971Sobrien * Send a single file. 40879971Sobrien */ 40979971Sobrienvoid 41079971Sobrienput(int argc, char *argv[]) 41179971Sobrien{ 412142129Smikeh char buf[MAXPATHLEN]; 413223328Sgavin const char *cmd; 41479971Sobrien int loc = 0; 415142129Smikeh char *locfile; 416142129Smikeh const char *remfile; 41779971Sobrien 41879971Sobrien if (argc == 2) { 41979971Sobrien argc++; 42079971Sobrien argv[2] = argv[1]; 42179971Sobrien loc++; 42279971Sobrien } 42379971Sobrien if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file"))) 42479971Sobrien goto usage; 42579971Sobrien if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 42679971Sobrien usage: 427223328Sgavin UPRINTF("usage: %s local-file [remote-file]\n", argv[0]); 42879971Sobrien code = -1; 42979971Sobrien return; 43079971Sobrien } 43179971Sobrien if ((locfile = globulize(argv[1])) == NULL) { 43279971Sobrien code = -1; 43379971Sobrien return; 43479971Sobrien } 43579971Sobrien remfile = argv[2]; 43679971Sobrien if (loc) /* If argv[2] is a copy of the old argv[1], update it */ 43779971Sobrien remfile = locfile; 43879971Sobrien cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 439142129Smikeh remfile = doprocess(buf, sizeof(buf), remfile, 440142129Smikeh 0, loc && ntflag, loc && mapflag); 44179971Sobrien sendrequest(cmd, locfile, remfile, 44279971Sobrien locfile != argv[1] || remfile != argv[2]); 44379971Sobrien free(locfile); 44479971Sobrien} 44579971Sobrien 446142129Smikehstatic const char * 447142129Smikehdoprocess(char *dst, size_t dlen, const char *src, 448142129Smikeh int casef, int transf, int mapf) 449142129Smikeh{ 450142129Smikeh if (casef) 451142129Smikeh src = docase(dst, dlen, src); 452142129Smikeh if (transf) 453142129Smikeh src = dotrans(dst, dlen, src); 454142129Smikeh if (mapf) 455142129Smikeh src = domap(dst, dlen, src); 456142129Smikeh return src; 457142129Smikeh} 458142129Smikeh 45979971Sobrien/* 46079971Sobrien * Send multiple files. 46179971Sobrien */ 46279971Sobrienvoid 46379971Sobrienmput(int argc, char *argv[]) 46479971Sobrien{ 46579971Sobrien int i; 46679971Sobrien sigfunc oldintr; 46779971Sobrien int ointer; 468142129Smikeh const char *tp; 46979971Sobrien 47079971Sobrien if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) { 471223328Sgavin UPRINTF("usage: %s local-files\n", argv[0]); 47279971Sobrien code = -1; 47379971Sobrien return; 47479971Sobrien } 47579971Sobrien mflag = 1; 47679971Sobrien oldintr = xsignal(SIGINT, mintr); 47779971Sobrien if (sigsetjmp(jabort, 1)) 478223328Sgavin mabort(argv[0]); 47979971Sobrien if (proxy) { 48079971Sobrien char *cp; 48179971Sobrien 48279971Sobrien while ((cp = remglob(argv, 0, NULL)) != NULL) { 48379971Sobrien if (*cp == '\0' || !connected) { 48479971Sobrien mflag = 0; 48579971Sobrien continue; 48679971Sobrien } 48779971Sobrien if (mflag && confirm(argv[0], cp)) { 488142129Smikeh char buf[MAXPATHLEN]; 489142129Smikeh tp = doprocess(buf, sizeof(buf), cp, 490142129Smikeh mcase, ntflag, mapflag); 49179971Sobrien sendrequest((sunique) ? "STOU" : "STOR", 49279971Sobrien cp, tp, cp != tp || !interactive); 49379971Sobrien if (!mflag && fromatty) { 49479971Sobrien ointer = interactive; 49579971Sobrien interactive = 1; 496223328Sgavin if (confirm(argv[0], NULL)) { 49779971Sobrien mflag++; 49879971Sobrien } 49979971Sobrien interactive = ointer; 50079971Sobrien } 50179971Sobrien } 50279971Sobrien } 50379971Sobrien goto cleanupmput; 50479971Sobrien } 50579971Sobrien for (i = 1; i < argc && connected; i++) { 50679971Sobrien char **cpp; 50779971Sobrien glob_t gl; 50879971Sobrien int flags; 50979971Sobrien 51079971Sobrien if (!doglob) { 51179971Sobrien if (mflag && confirm(argv[0], argv[i])) { 512142129Smikeh char buf[MAXPATHLEN]; 513142129Smikeh tp = doprocess(buf, sizeof(buf), argv[i], 514142129Smikeh 0, ntflag, mapflag); 51579971Sobrien sendrequest((sunique) ? "STOU" : "STOR", 51679971Sobrien argv[i], tp, tp != argv[i] || !interactive); 51779971Sobrien if (!mflag && fromatty) { 51879971Sobrien ointer = interactive; 51979971Sobrien interactive = 1; 520223328Sgavin if (confirm(argv[0], NULL)) { 52179971Sobrien mflag++; 52279971Sobrien } 52379971Sobrien interactive = ointer; 52479971Sobrien } 52579971Sobrien } 52679971Sobrien continue; 52779971Sobrien } 52879971Sobrien 52979971Sobrien memset(&gl, 0, sizeof(gl)); 53079971Sobrien flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 53179971Sobrien if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { 532223328Sgavin warnx("Glob pattern `%s' not found", argv[i]); 53379971Sobrien globfree(&gl); 53479971Sobrien continue; 53579971Sobrien } 53679971Sobrien for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected; 53779971Sobrien cpp++) { 53879971Sobrien if (mflag && confirm(argv[0], *cpp)) { 539142129Smikeh char buf[MAXPATHLEN]; 540142129Smikeh tp = *cpp; 541142129Smikeh tp = doprocess(buf, sizeof(buf), *cpp, 542142129Smikeh 0, ntflag, mapflag); 54379971Sobrien sendrequest((sunique) ? "STOU" : "STOR", 54479971Sobrien *cpp, tp, *cpp != tp || !interactive); 54579971Sobrien if (!mflag && fromatty) { 54679971Sobrien ointer = interactive; 54779971Sobrien interactive = 1; 548223328Sgavin if (confirm(argv[0], NULL)) { 54979971Sobrien mflag++; 55079971Sobrien } 55179971Sobrien interactive = ointer; 55279971Sobrien } 55379971Sobrien } 55479971Sobrien } 55579971Sobrien globfree(&gl); 55679971Sobrien } 55779971Sobrien cleanupmput: 55879971Sobrien (void)xsignal(SIGINT, oldintr); 55979971Sobrien mflag = 0; 56079971Sobrien} 56179971Sobrien 56279971Sobrienvoid 56379971Sobrienreget(int argc, char *argv[]) 56479971Sobrien{ 56579971Sobrien 56698247Smikeh (void)getit(argc, argv, 1, "r+"); 56779971Sobrien} 56879971Sobrien 56979971Sobrienvoid 57079971Sobrienget(int argc, char *argv[]) 57179971Sobrien{ 57279971Sobrien 57398247Smikeh (void)getit(argc, argv, 0, restart_point ? "r+" : "w" ); 57479971Sobrien} 57579971Sobrien 57679971Sobrien/* 57779971Sobrien * Receive one file. 57898247Smikeh * If restartit is 1, restart the xfer always. 57998247Smikeh * If restartit is -1, restart the xfer only if the remote file is newer. 58079971Sobrien */ 58179971Sobrienint 582223328Sgavingetit(int argc, char *argv[], int restartit, const char *gmode) 58379971Sobrien{ 584146309Smikeh int loc, rval; 585142129Smikeh char *remfile, *olocfile; 586142129Smikeh const char *locfile; 587146309Smikeh char buf[MAXPATHLEN]; 58879971Sobrien 58998247Smikeh loc = rval = 0; 59079971Sobrien if (argc == 2) { 59179971Sobrien argc++; 59279971Sobrien argv[2] = argv[1]; 59379971Sobrien loc++; 59479971Sobrien } 59579971Sobrien if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file"))) 59679971Sobrien goto usage; 59779971Sobrien if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) { 59879971Sobrien usage: 599223328Sgavin UPRINTF("usage: %s remote-file [local-file]\n", argv[0]); 60079971Sobrien code = -1; 60179971Sobrien return (0); 60279971Sobrien } 60379971Sobrien remfile = argv[1]; 60479971Sobrien if ((olocfile = globulize(argv[2])) == NULL) { 60579971Sobrien code = -1; 60679971Sobrien return (0); 60779971Sobrien } 608142129Smikeh locfile = doprocess(buf, sizeof(buf), olocfile, 609142129Smikeh loc && mcase, loc && ntflag, loc && mapflag); 61079971Sobrien if (restartit) { 61179971Sobrien struct stat stbuf; 61279971Sobrien int ret; 61379971Sobrien 61479971Sobrien if (! features[FEAT_REST_STREAM]) { 61579971Sobrien fprintf(ttyout, 61679971Sobrien "Restart is not supported by the remote server.\n"); 61779971Sobrien return (0); 61879971Sobrien } 61979971Sobrien ret = stat(locfile, &stbuf); 62079971Sobrien if (restartit == 1) { 62179971Sobrien if (ret < 0) { 622223328Sgavin warn("Can't stat `%s'", locfile); 62379971Sobrien goto freegetit; 62479971Sobrien } 62579971Sobrien restart_point = stbuf.st_size; 62679971Sobrien } else { 62779971Sobrien if (ret == 0) { 62879971Sobrien time_t mtime; 62979971Sobrien 63079971Sobrien mtime = remotemodtime(argv[1], 0); 63179971Sobrien if (mtime == -1) 63279971Sobrien goto freegetit; 63379971Sobrien if (stbuf.st_mtime >= mtime) { 63479971Sobrien rval = 1; 63579971Sobrien goto freegetit; 63679971Sobrien } 63779971Sobrien } 63879971Sobrien } 63979971Sobrien } 64079971Sobrien 641223328Sgavin recvrequest("RETR", locfile, remfile, gmode, 64279971Sobrien remfile != argv[1] || locfile != argv[2], loc); 64379971Sobrien restart_point = 0; 64479971Sobrien freegetit: 64579971Sobrien (void)free(olocfile); 64679971Sobrien return (rval); 64779971Sobrien} 64879971Sobrien 64979971Sobrien/* ARGSUSED */ 650223328Sgavinstatic void 65179971Sobrienmintr(int signo) 65279971Sobrien{ 65379971Sobrien 65479971Sobrien alarmtimer(0); 65579971Sobrien if (fromatty) 65679971Sobrien write(fileno(ttyout), "\n", 1); 65779971Sobrien siglongjmp(jabort, 1); 65879971Sobrien} 65979971Sobrien 660223328Sgavinstatic void 661223328Sgavinmabort(const char *cmd) 66279971Sobrien{ 66379971Sobrien int ointer, oconf; 66479971Sobrien 66579971Sobrien if (mflag && fromatty) { 66679971Sobrien ointer = interactive; 66779971Sobrien oconf = confirmrest; 66879971Sobrien interactive = 1; 66979971Sobrien confirmrest = 0; 670223328Sgavin if (confirm(cmd, NULL)) { 67179971Sobrien interactive = ointer; 67279971Sobrien confirmrest = oconf; 67379971Sobrien return; 67479971Sobrien } 67579971Sobrien interactive = ointer; 67679971Sobrien confirmrest = oconf; 67779971Sobrien } 67879971Sobrien mflag = 0; 67979971Sobrien} 68079971Sobrien 68179971Sobrien/* 68279971Sobrien * Get multiple files. 68379971Sobrien */ 68479971Sobrienvoid 68579971Sobrienmget(int argc, char *argv[]) 68679971Sobrien{ 68779971Sobrien sigfunc oldintr; 68898247Smikeh int ointer; 689142129Smikeh char *cp; 690142129Smikeh const char *tp; 691223328Sgavin int volatile restartit; 69279971Sobrien 69379971Sobrien if (argc == 0 || 69479971Sobrien (argc == 1 && !another(&argc, &argv, "remote-files"))) { 695223328Sgavin UPRINTF("usage: %s remote-files\n", argv[0]); 69679971Sobrien code = -1; 69779971Sobrien return; 69879971Sobrien } 69979971Sobrien mflag = 1; 70098247Smikeh restart_point = 0; 70198247Smikeh restartit = 0; 70298247Smikeh if (strcmp(argv[0], "mreget") == 0) { 70398247Smikeh if (! features[FEAT_REST_STREAM]) { 70498247Smikeh fprintf(ttyout, 70598247Smikeh "Restart is not supported by the remote server.\n"); 70698247Smikeh return; 70798247Smikeh } 70898247Smikeh restartit = 1; 70998247Smikeh } 71079971Sobrien oldintr = xsignal(SIGINT, mintr); 71179971Sobrien if (sigsetjmp(jabort, 1)) 712223328Sgavin mabort(argv[0]); 71379971Sobrien while ((cp = remglob(argv, proxy, NULL)) != NULL) { 714142129Smikeh char buf[MAXPATHLEN]; 71579971Sobrien if (*cp == '\0' || !connected) { 71679971Sobrien mflag = 0; 71779971Sobrien continue; 71879971Sobrien } 719142129Smikeh if (! mflag) 72098247Smikeh continue; 721142129Smikeh if (! fileindir(cp, localcwd)) { 722142129Smikeh fprintf(ttyout, "Skipping non-relative filename `%s'\n", 723142129Smikeh cp); 724142129Smikeh continue; 725142129Smikeh } 726142129Smikeh if (!confirm(argv[0], cp)) 727142129Smikeh continue; 728142129Smikeh tp = doprocess(buf, sizeof(buf), cp, mcase, ntflag, mapflag); 72998247Smikeh if (restartit) { 73098247Smikeh struct stat stbuf; 73198247Smikeh 73298247Smikeh if (stat(tp, &stbuf) == 0) 73398247Smikeh restart_point = stbuf.st_size; 73498247Smikeh else 735223328Sgavin warn("Can't stat `%s'", tp); 73679971Sobrien } 73798247Smikeh recvrequest("RETR", tp, cp, restart_point ? "r+" : "w", 73898247Smikeh tp != cp || !interactive, 1); 73998247Smikeh restart_point = 0; 74098247Smikeh if (!mflag && fromatty) { 74198247Smikeh ointer = interactive; 74298247Smikeh interactive = 1; 743223328Sgavin if (confirm(argv[0], NULL)) 74498247Smikeh mflag++; 74598247Smikeh interactive = ointer; 74698247Smikeh } 74779971Sobrien } 74879971Sobrien (void)xsignal(SIGINT, oldintr); 74979971Sobrien mflag = 0; 75079971Sobrien} 75179971Sobrien 75279971Sobrien/* 75379971Sobrien * Read list of filenames from a local file and get those 75479971Sobrien */ 75579971Sobrienvoid 75679971Sobrienfget(int argc, char *argv[]) 75779971Sobrien{ 758223328Sgavin const char *gmode; 75979971Sobrien FILE *fp; 760223328Sgavin char buf[MAXPATHLEN], cmdbuf[MAX_C_NAME]; 76179971Sobrien 76279971Sobrien if (argc != 2) { 763223328Sgavin UPRINTF("usage: %s localfile\n", argv[0]); 76479971Sobrien code = -1; 76579971Sobrien return; 76679971Sobrien } 76779971Sobrien 76879971Sobrien fp = fopen(argv[1], "r"); 76979971Sobrien if (fp == NULL) { 770223328Sgavin fprintf(ttyout, "Can't open source file %s\n", argv[1]); 77179971Sobrien code = -1; 77279971Sobrien return; 77379971Sobrien } 77479971Sobrien 775223328Sgavin (void)strlcpy(cmdbuf, "get", sizeof(cmdbuf)); 776223328Sgavin argv[0] = cmdbuf; 777223328Sgavin gmode = restart_point ? "r+" : "w"; 77879971Sobrien 779223328Sgavin while (get_line(fp, buf, sizeof(buf), NULL) >= 0) { 78079971Sobrien if (buf[0] == '\0') 78179971Sobrien continue; 78279971Sobrien argv[1] = buf; 783223328Sgavin (void)getit(argc, argv, 0, gmode); 78479971Sobrien } 78579971Sobrien fclose(fp); 78679971Sobrien} 78779971Sobrien 788223328Sgavinconst char * 789223328Sgavinonoff(int val) 79079971Sobrien{ 79179971Sobrien 792223328Sgavin return (val ? "on" : "off"); 79379971Sobrien} 79479971Sobrien 79579971Sobrien/* 79679971Sobrien * Show status. 79779971Sobrien */ 79879971Sobrien/*ARGSUSED*/ 79979971Sobrienvoid 80079971Sobrienstatus(int argc, char *argv[]) 80179971Sobrien{ 80279971Sobrien 80379971Sobrien if (argc == 0) { 804223328Sgavin UPRINTF("usage: %s\n", argv[0]); 80579971Sobrien code = -1; 80679971Sobrien return; 80779971Sobrien } 808142129Smikeh#ifndef NO_STATUS 80979971Sobrien if (connected) 81079971Sobrien fprintf(ttyout, "Connected %sto %s.\n", 81179971Sobrien connected == -1 ? "and logged in" : "", hostname); 81279971Sobrien else 81379971Sobrien fputs("Not connected.\n", ttyout); 81479971Sobrien if (!proxy) { 81579971Sobrien pswitch(1); 81679971Sobrien if (connected) { 81779971Sobrien fprintf(ttyout, "Connected for proxy commands to %s.\n", 81879971Sobrien hostname); 81979971Sobrien } 82079971Sobrien else { 82179971Sobrien fputs("No proxy connection.\n", ttyout); 82279971Sobrien } 82379971Sobrien pswitch(0); 82479971Sobrien } 82579971Sobrien fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode), 82679971Sobrien *gateserver ? gateserver : "(none)", gateport); 82779971Sobrien fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 82879971Sobrien onoff(passivemode), onoff(activefallback)); 82979971Sobrien fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n", 83079971Sobrien modename, typename, formname, structname); 83179971Sobrien fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n", 83279971Sobrien onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob)); 83379971Sobrien fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", 83479971Sobrien onoff(sunique), onoff(runique)); 83579971Sobrien fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve)); 83679971Sobrien fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), 83779971Sobrien onoff(crflag)); 83879971Sobrien if (ntflag) { 83979971Sobrien fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout); 84079971Sobrien } 84179971Sobrien else { 84279971Sobrien fputs("Ntrans: off.\n", ttyout); 84379971Sobrien } 84479971Sobrien if (mapflag) { 84579971Sobrien fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout); 84679971Sobrien } 84779971Sobrien else { 84879971Sobrien fputs("Nmap: off.\n", ttyout); 84979971Sobrien } 85079971Sobrien fprintf(ttyout, 85179971Sobrien "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n", 85279971Sobrien onoff(hash), mark, onoff(progress)); 85379971Sobrien fprintf(ttyout, 85479971Sobrien "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 85579971Sobrien onoff(rate_get), rate_get, rate_get_incr); 85679971Sobrien fprintf(ttyout, 85779971Sobrien "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 85879971Sobrien onoff(rate_put), rate_put, rate_put_incr); 85979971Sobrien fprintf(ttyout, 86079971Sobrien "Socket buffer sizes: send %d, receive %d.\n", 86179971Sobrien sndbuf_size, rcvbuf_size); 86279971Sobrien fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport)); 86379971Sobrien fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4), 86479971Sobrien epsv4bad ? " (disabled for this connection)" : ""); 865223328Sgavin fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv6: %s%s.\n", onoff(epsv6), 866223328Sgavin epsv6bad ? " (disabled for this connection)" : ""); 86779971Sobrien fprintf(ttyout, "Command line editing: %s.\n", 86879971Sobrien#ifdef NO_EDITCOMPLETE 86979971Sobrien "support not compiled in" 87079971Sobrien#else /* !def NO_EDITCOMPLETE */ 87179971Sobrien onoff(editing) 87279971Sobrien#endif /* !def NO_EDITCOMPLETE */ 87379971Sobrien ); 87479971Sobrien if (macnum > 0) { 875142129Smikeh int i; 876142129Smikeh 87779971Sobrien fputs("Macros:\n", ttyout); 87879971Sobrien for (i=0; i<macnum; i++) { 87979971Sobrien fprintf(ttyout, "\t%s\n", macros[i].mac_name); 88079971Sobrien } 88179971Sobrien } 882142129Smikeh#endif /* !def NO_STATUS */ 883142129Smikeh fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION); 88479971Sobrien code = 0; 88579971Sobrien} 88679971Sobrien 88779971Sobrien/* 88879971Sobrien * Toggle a variable 88979971Sobrien */ 89079971Sobrienint 89179971Sobrientogglevar(int argc, char *argv[], int *var, const char *mesg) 89279971Sobrien{ 89379971Sobrien if (argc == 1) { 89479971Sobrien *var = !*var; 89579971Sobrien } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) { 89679971Sobrien *var = 1; 89779971Sobrien } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) { 89879971Sobrien *var = 0; 89979971Sobrien } else { 900223328Sgavin UPRINTF("usage: %s [ on | off ]\n", argv[0]); 90179971Sobrien return (-1); 90279971Sobrien } 90379971Sobrien if (mesg) 90479971Sobrien fprintf(ttyout, "%s %s.\n", mesg, onoff(*var)); 90579971Sobrien return (*var); 90679971Sobrien} 90779971Sobrien 90879971Sobrien/* 90979971Sobrien * Set beep on cmd completed mode. 91079971Sobrien */ 91179971Sobrien/*VARARGS*/ 91279971Sobrienvoid 91379971Sobriensetbell(int argc, char *argv[]) 91479971Sobrien{ 91579971Sobrien 91679971Sobrien code = togglevar(argc, argv, &bell, "Bell mode"); 91779971Sobrien} 91879971Sobrien 91979971Sobrien/* 92079971Sobrien * Set command line editing 92179971Sobrien */ 92279971Sobrien/*VARARGS*/ 92379971Sobrienvoid 92479971Sobriensetedit(int argc, char *argv[]) 92579971Sobrien{ 92679971Sobrien 92779971Sobrien#ifdef NO_EDITCOMPLETE 92879971Sobrien if (argc == 0) { 929223328Sgavin UPRINTF("usage: %s\n", argv[0]); 93079971Sobrien code = -1; 93179971Sobrien return; 93279971Sobrien } 93379971Sobrien if (verbose) 93479971Sobrien fputs("Editing support not compiled in; ignoring command.\n", 93579971Sobrien ttyout); 93679971Sobrien#else /* !def NO_EDITCOMPLETE */ 93779971Sobrien code = togglevar(argc, argv, &editing, "Editing mode"); 93879971Sobrien controlediting(); 93979971Sobrien#endif /* !def NO_EDITCOMPLETE */ 94079971Sobrien} 94179971Sobrien 94279971Sobrien/* 94379971Sobrien * Turn on packet tracing. 94479971Sobrien */ 94579971Sobrien/*VARARGS*/ 94679971Sobrienvoid 94779971Sobriensettrace(int argc, char *argv[]) 94879971Sobrien{ 94979971Sobrien 95079971Sobrien code = togglevar(argc, argv, &trace, "Packet tracing"); 95179971Sobrien} 95279971Sobrien 95379971Sobrien/* 95479971Sobrien * Toggle hash mark printing during transfers, or set hash mark bytecount. 95579971Sobrien */ 95679971Sobrien/*VARARGS*/ 95779971Sobrienvoid 95879971Sobriensethash(int argc, char *argv[]) 95979971Sobrien{ 96079971Sobrien if (argc == 1) 96179971Sobrien hash = !hash; 96279971Sobrien else if (argc != 2) { 963223328Sgavin UPRINTF("usage: %s [ on | off | bytecount ]\n", 96479971Sobrien argv[0]); 96579971Sobrien code = -1; 96679971Sobrien return; 96779971Sobrien } else if (strcasecmp(argv[1], "on") == 0) 96879971Sobrien hash = 1; 96979971Sobrien else if (strcasecmp(argv[1], "off") == 0) 97079971Sobrien hash = 0; 97179971Sobrien else { 97279971Sobrien int nmark; 97379971Sobrien 97479971Sobrien nmark = strsuftoi(argv[1]); 97579971Sobrien if (nmark < 1) { 97679971Sobrien fprintf(ttyout, "mark: bad bytecount value `%s'.\n", 97779971Sobrien argv[1]); 97879971Sobrien code = -1; 97979971Sobrien return; 98079971Sobrien } 98179971Sobrien mark = nmark; 98279971Sobrien hash = 1; 98379971Sobrien } 98479971Sobrien fprintf(ttyout, "Hash mark printing %s", onoff(hash)); 98579971Sobrien if (hash) 98679971Sobrien fprintf(ttyout, " (%d bytes/hash mark)", mark); 98779971Sobrien fputs(".\n", ttyout); 98879971Sobrien if (hash) 98979971Sobrien progress = 0; 99079971Sobrien code = hash; 99179971Sobrien} 99279971Sobrien 99379971Sobrien/* 99479971Sobrien * Turn on printing of server echo's. 99579971Sobrien */ 99679971Sobrien/*VARARGS*/ 99779971Sobrienvoid 99879971Sobriensetverbose(int argc, char *argv[]) 99979971Sobrien{ 100079971Sobrien 100179971Sobrien code = togglevar(argc, argv, &verbose, "Verbose mode"); 100279971Sobrien} 100379971Sobrien 100479971Sobrien/* 100579971Sobrien * Toggle PORT/LPRT cmd use before each data connection. 100679971Sobrien */ 100779971Sobrien/*VARARGS*/ 100879971Sobrienvoid 100979971Sobriensetport(int argc, char *argv[]) 101079971Sobrien{ 101179971Sobrien 101279971Sobrien code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds"); 101379971Sobrien} 101479971Sobrien 101579971Sobrien/* 101679971Sobrien * Toggle transfer progress bar. 101779971Sobrien */ 101879971Sobrien/*VARARGS*/ 101979971Sobrienvoid 102079971Sobriensetprogress(int argc, char *argv[]) 102179971Sobrien{ 102279971Sobrien 102379971Sobrien code = togglevar(argc, argv, &progress, "Progress bar"); 102479971Sobrien if (progress) 102579971Sobrien hash = 0; 102679971Sobrien} 102779971Sobrien 102879971Sobrien/* 102979971Sobrien * Turn on interactive prompting during mget, mput, and mdelete. 103079971Sobrien */ 103179971Sobrien/*VARARGS*/ 103279971Sobrienvoid 103379971Sobriensetprompt(int argc, char *argv[]) 103479971Sobrien{ 103579971Sobrien 103679971Sobrien code = togglevar(argc, argv, &interactive, "Interactive mode"); 103779971Sobrien} 103879971Sobrien 103979971Sobrien/* 104079971Sobrien * Toggle gate-ftp mode, or set gate-ftp server 104179971Sobrien */ 104279971Sobrien/*VARARGS*/ 104379971Sobrienvoid 104479971Sobriensetgate(int argc, char *argv[]) 104579971Sobrien{ 104679971Sobrien static char gsbuf[MAXHOSTNAMELEN]; 104779971Sobrien 104879971Sobrien if (argc == 0 || argc > 3) { 1049223328Sgavin UPRINTF( 105079971Sobrien "usage: %s [ on | off | gateserver [port] ]\n", argv[0]); 105179971Sobrien code = -1; 105279971Sobrien return; 105379971Sobrien } else if (argc < 2) { 105479971Sobrien gatemode = !gatemode; 105579971Sobrien } else { 105679971Sobrien if (argc == 2 && strcasecmp(argv[1], "on") == 0) 105779971Sobrien gatemode = 1; 105879971Sobrien else if (argc == 2 && strcasecmp(argv[1], "off") == 0) 105979971Sobrien gatemode = 0; 106079971Sobrien else { 106179971Sobrien if (argc == 3) 1062223328Sgavin gateport = ftp_strdup(argv[2]); 106379971Sobrien (void)strlcpy(gsbuf, argv[1], sizeof(gsbuf)); 106479971Sobrien gateserver = gsbuf; 106579971Sobrien gatemode = 1; 106679971Sobrien } 106779971Sobrien } 106879971Sobrien if (gatemode && (gateserver == NULL || *gateserver == '\0')) { 106979971Sobrien fprintf(ttyout, 107079971Sobrien "Disabling gate-ftp mode - no gate-ftp server defined.\n"); 107179971Sobrien gatemode = 0; 107279971Sobrien } else { 107379971Sobrien fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", 107479971Sobrien onoff(gatemode), *gateserver ? gateserver : "(none)", 107579971Sobrien gateport); 107679971Sobrien } 107779971Sobrien code = gatemode; 107879971Sobrien} 107979971Sobrien 108079971Sobrien/* 108179971Sobrien * Toggle metacharacter interpretation on local file names. 108279971Sobrien */ 108379971Sobrien/*VARARGS*/ 108479971Sobrienvoid 108579971Sobriensetglob(int argc, char *argv[]) 108679971Sobrien{ 108779971Sobrien 108879971Sobrien code = togglevar(argc, argv, &doglob, "Globbing"); 108979971Sobrien} 109079971Sobrien 109179971Sobrien/* 109279971Sobrien * Toggle preserving modification times on retrieved files. 109379971Sobrien */ 109479971Sobrien/*VARARGS*/ 109579971Sobrienvoid 109679971Sobriensetpreserve(int argc, char *argv[]) 109779971Sobrien{ 109879971Sobrien 109979971Sobrien code = togglevar(argc, argv, &preserve, "Preserve modification times"); 110079971Sobrien} 110179971Sobrien 110279971Sobrien/* 110379971Sobrien * Set debugging mode on/off and/or set level of debugging. 110479971Sobrien */ 110579971Sobrien/*VARARGS*/ 110679971Sobrienvoid 110779971Sobriensetdebug(int argc, char *argv[]) 110879971Sobrien{ 110979971Sobrien if (argc == 0 || argc > 2) { 1110223328Sgavin UPRINTF("usage: %s [ on | off | debuglevel ]\n", argv[0]); 111179971Sobrien code = -1; 111279971Sobrien return; 111379971Sobrien } else if (argc == 2) { 111479971Sobrien if (strcasecmp(argv[1], "on") == 0) 1115223328Sgavin ftp_debug = 1; 111679971Sobrien else if (strcasecmp(argv[1], "off") == 0) 1117223328Sgavin ftp_debug = 0; 111879971Sobrien else { 111979971Sobrien int val; 112079971Sobrien 112179971Sobrien val = strsuftoi(argv[1]); 112279971Sobrien if (val < 0) { 112379971Sobrien fprintf(ttyout, "%s: bad debugging value.\n", 112479971Sobrien argv[1]); 112579971Sobrien code = -1; 112679971Sobrien return; 112779971Sobrien } 1128223328Sgavin ftp_debug = val; 112979971Sobrien } 113079971Sobrien } else 1131223328Sgavin ftp_debug = !ftp_debug; 1132223328Sgavin if (ftp_debug) 113379971Sobrien options |= SO_DEBUG; 113479971Sobrien else 113579971Sobrien options &= ~SO_DEBUG; 1136223328Sgavin fprintf(ttyout, "Debugging %s (ftp_debug=%d).\n", onoff(ftp_debug), ftp_debug); 1137223328Sgavin code = ftp_debug > 0; 113879971Sobrien} 113979971Sobrien 114079971Sobrien/* 114179971Sobrien * Set current working directory on remote machine. 114279971Sobrien */ 114379971Sobrienvoid 114479971Sobriencd(int argc, char *argv[]) 114579971Sobrien{ 114679971Sobrien int r; 114779971Sobrien 114879971Sobrien if (argc == 0 || argc > 2 || 114979971Sobrien (argc == 1 && !another(&argc, &argv, "remote-directory"))) { 1150223328Sgavin UPRINTF("usage: %s remote-directory\n", argv[0]); 115179971Sobrien code = -1; 115279971Sobrien return; 115379971Sobrien } 115479971Sobrien r = command("CWD %s", argv[1]); 115579971Sobrien if (r == ERROR && code == 500) { 115679971Sobrien if (verbose) 115779971Sobrien fputs("CWD command not recognized, trying XCWD.\n", 115879971Sobrien ttyout); 115979971Sobrien r = command("XCWD %s", argv[1]); 116079971Sobrien } 116179971Sobrien if (r == COMPLETE) { 116279971Sobrien dirchange = 1; 1163142129Smikeh updateremotecwd(); 116479971Sobrien } 116579971Sobrien} 116679971Sobrien 116779971Sobrien/* 116879971Sobrien * Set current working directory on local machine. 116979971Sobrien */ 117079971Sobrienvoid 117179971Sobrienlcd(int argc, char *argv[]) 117279971Sobrien{ 117379971Sobrien char *locdir; 117479971Sobrien 117579971Sobrien code = -1; 117679971Sobrien if (argc == 1) { 117779971Sobrien argc++; 117898247Smikeh argv[1] = localhome; 117979971Sobrien } 118079971Sobrien if (argc != 2) { 1181223328Sgavin UPRINTF("usage: %s [local-directory]\n", argv[0]); 118279971Sobrien return; 118379971Sobrien } 118479971Sobrien if ((locdir = globulize(argv[1])) == NULL) 118579971Sobrien return; 1186142129Smikeh if (chdir(locdir) == -1) 1187223328Sgavin warn("Can't chdir `%s'", locdir); 118879971Sobrien else { 1189142129Smikeh updatelocalcwd(); 1190142129Smikeh if (localcwd[0]) { 1191142129Smikeh fprintf(ttyout, "Local directory now: %s\n", localcwd); 119279971Sobrien code = 0; 1193142129Smikeh } else { 1194142129Smikeh fprintf(ttyout, "Unable to determine local directory\n"); 1195142129Smikeh } 119679971Sobrien } 119779971Sobrien (void)free(locdir); 119879971Sobrien} 119979971Sobrien 120079971Sobrien/* 120179971Sobrien * Delete a single file. 120279971Sobrien */ 120379971Sobrienvoid 120479971Sobriendelete(int argc, char *argv[]) 120579971Sobrien{ 120679971Sobrien 120779971Sobrien if (argc == 0 || argc > 2 || 120879971Sobrien (argc == 1 && !another(&argc, &argv, "remote-file"))) { 1209223328Sgavin UPRINTF("usage: %s remote-file\n", argv[0]); 121079971Sobrien code = -1; 121179971Sobrien return; 121279971Sobrien } 1213121966Smikeh if (command("DELE %s", argv[1]) == COMPLETE) 1214121966Smikeh dirchange = 1; 121579971Sobrien} 121679971Sobrien 121779971Sobrien/* 121879971Sobrien * Delete multiple files. 121979971Sobrien */ 122079971Sobrienvoid 122179971Sobrienmdelete(int argc, char *argv[]) 122279971Sobrien{ 122379971Sobrien sigfunc oldintr; 122479971Sobrien int ointer; 122579971Sobrien char *cp; 122679971Sobrien 122779971Sobrien if (argc == 0 || 122879971Sobrien (argc == 1 && !another(&argc, &argv, "remote-files"))) { 1229223328Sgavin UPRINTF("usage: %s [remote-files]\n", argv[0]); 123079971Sobrien code = -1; 123179971Sobrien return; 123279971Sobrien } 123379971Sobrien mflag = 1; 123479971Sobrien oldintr = xsignal(SIGINT, mintr); 123579971Sobrien if (sigsetjmp(jabort, 1)) 1236223328Sgavin mabort(argv[0]); 123779971Sobrien while ((cp = remglob(argv, 0, NULL)) != NULL) { 123879971Sobrien if (*cp == '\0') { 123979971Sobrien mflag = 0; 124079971Sobrien continue; 124179971Sobrien } 124279971Sobrien if (mflag && confirm(argv[0], cp)) { 1243121966Smikeh if (command("DELE %s", cp) == COMPLETE) 1244121966Smikeh dirchange = 1; 124579971Sobrien if (!mflag && fromatty) { 124679971Sobrien ointer = interactive; 124779971Sobrien interactive = 1; 1248223328Sgavin if (confirm(argv[0], NULL)) { 124979971Sobrien mflag++; 125079971Sobrien } 125179971Sobrien interactive = ointer; 125279971Sobrien } 125379971Sobrien } 125479971Sobrien } 125579971Sobrien (void)xsignal(SIGINT, oldintr); 125679971Sobrien mflag = 0; 125779971Sobrien} 125879971Sobrien 125979971Sobrien/* 126079971Sobrien * Rename a remote file. 126179971Sobrien */ 126279971Sobrienvoid 126379971Sobrienrenamefile(int argc, char *argv[]) 126479971Sobrien{ 126579971Sobrien 126679971Sobrien if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name"))) 126779971Sobrien goto usage; 126879971Sobrien if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { 126979971Sobrien usage: 1270223328Sgavin UPRINTF("usage: %s from-name to-name\n", argv[0]); 127179971Sobrien code = -1; 127279971Sobrien return; 127379971Sobrien } 1274121966Smikeh if (command("RNFR %s", argv[1]) == CONTINUE && 1275121966Smikeh command("RNTO %s", argv[2]) == COMPLETE) 1276121966Smikeh dirchange = 1; 127779971Sobrien} 127879971Sobrien 127979971Sobrien/* 128079971Sobrien * Get a directory listing of remote files. 128179971Sobrien * Supports being invoked as: 128279971Sobrien * cmd runs 128379971Sobrien * --- ---- 128479971Sobrien * dir, ls LIST 128579971Sobrien * mlsd MLSD 128679971Sobrien * nlist NLST 128779971Sobrien * pdir, pls LIST |$PAGER 1288223328Sgavin * pmlsd MLSD |$PAGER 128979971Sobrien */ 129079971Sobrienvoid 129179971Sobrienls(int argc, char *argv[]) 129279971Sobrien{ 129379971Sobrien const char *cmd; 1294223328Sgavin char *remdir, *locbuf; 1295223328Sgavin const char *locfile; 1296223328Sgavin int pagecmd, mlsdcmd; 129779971Sobrien 129879971Sobrien remdir = NULL; 1299223328Sgavin locbuf = NULL; 130079971Sobrien locfile = "-"; 1301223328Sgavin pagecmd = mlsdcmd = 0; 130279971Sobrien /* 130379971Sobrien * the only commands that start with `p' are 130479971Sobrien * the `pager' versions. 130579971Sobrien */ 130679971Sobrien if (argv[0][0] == 'p') 130779971Sobrien pagecmd = 1; 130879971Sobrien if (strcmp(argv[0] + pagecmd , "mlsd") == 0) { 130979971Sobrien if (! features[FEAT_MLST]) { 131079971Sobrien fprintf(ttyout, 131179971Sobrien "MLSD is not supported by the remote server.\n"); 131279971Sobrien return; 131379971Sobrien } 131479971Sobrien mlsdcmd = 1; 131579971Sobrien } 131679971Sobrien if (argc == 0) 131779971Sobrien goto usage; 131879971Sobrien 131979971Sobrien if (mlsdcmd) 132079971Sobrien cmd = "MLSD"; 132179971Sobrien else if (strcmp(argv[0] + pagecmd, "nlist") == 0) 132279971Sobrien cmd = "NLST"; 132379971Sobrien else 132479971Sobrien cmd = "LIST"; 132579971Sobrien 132679971Sobrien if (argc > 1) 132779971Sobrien remdir = argv[1]; 132879971Sobrien if (argc > 2) 132979971Sobrien locfile = argv[2]; 133079971Sobrien if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) { 133179971Sobrien usage: 133279971Sobrien if (pagecmd || mlsdcmd) 1333223328Sgavin UPRINTF("usage: %s [remote-path]\n", argv[0]); 133479971Sobrien else 1335223328Sgavin UPRINTF("usage: %s [remote-path [local-file]]\n", 133679971Sobrien argv[0]); 133779971Sobrien code = -1; 133879971Sobrien goto freels; 133979971Sobrien } 134079971Sobrien 134179971Sobrien if (pagecmd) { 1342223328Sgavin const char *p; 1343223328Sgavin size_t len; 134479971Sobrien 134579971Sobrien p = getoptionvalue("pager"); 134679971Sobrien if (EMPTYSTRING(p)) 134779971Sobrien p = DEFAULTPAGER; 134879971Sobrien len = strlen(p) + 2; 1349223328Sgavin locbuf = ftp_malloc(len); 1350223328Sgavin locbuf[0] = '|'; 1351223328Sgavin (void)strlcpy(locbuf + 1, p, len - 1); 1352223328Sgavin locfile = locbuf; 135379971Sobrien } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') { 1354223328Sgavin if ((locbuf = globulize(locfile)) == NULL || 1355223328Sgavin !confirm("output to local-file:", locbuf)) { 135679971Sobrien code = -1; 135779971Sobrien goto freels; 135879971Sobrien } 1359223328Sgavin locfile = locbuf; 136079971Sobrien } 136179971Sobrien recvrequest(cmd, locfile, remdir, "w", 0, 0); 136279971Sobrien freels: 1363223328Sgavin if (locbuf) 1364223328Sgavin (void)free(locbuf); 136579971Sobrien} 136679971Sobrien 136779971Sobrien/* 136879971Sobrien * Get a directory listing of multiple remote files. 136979971Sobrien */ 137079971Sobrienvoid 137179971Sobrienmls(int argc, char *argv[]) 137279971Sobrien{ 137379971Sobrien sigfunc oldintr; 137479971Sobrien int ointer, i; 1375223328Sgavin int volatile dolist; 1376223328Sgavin char * volatile dest, *odest; 1377223328Sgavin const char *lmode; 137879971Sobrien 137979971Sobrien if (argc == 0) 138079971Sobrien goto usage; 138179971Sobrien if (argc < 2 && !another(&argc, &argv, "remote-files")) 138279971Sobrien goto usage; 138379971Sobrien if (argc < 3 && !another(&argc, &argv, "local-file")) { 138479971Sobrien usage: 1385223328Sgavin UPRINTF("usage: %s remote-files local-file\n", argv[0]); 138679971Sobrien code = -1; 138779971Sobrien return; 138879971Sobrien } 138979971Sobrien odest = dest = argv[argc - 1]; 139079971Sobrien argv[argc - 1] = NULL; 139179971Sobrien if (strcmp(dest, "-") && *dest != '|') 139279971Sobrien if (((dest = globulize(dest)) == NULL) || 139379971Sobrien !confirm("output to local-file:", dest)) { 139479971Sobrien code = -1; 139579971Sobrien return; 139679971Sobrien } 139779971Sobrien dolist = strcmp(argv[0], "mls"); 139879971Sobrien mflag = 1; 139979971Sobrien oldintr = xsignal(SIGINT, mintr); 140079971Sobrien if (sigsetjmp(jabort, 1)) 1401223328Sgavin mabort(argv[0]); 140279971Sobrien for (i = 1; mflag && i < argc-1 && connected; i++) { 1403223328Sgavin lmode = (i == 1) ? "w" : "a"; 1404223328Sgavin recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], lmode, 140579971Sobrien 0, 0); 140679971Sobrien if (!mflag && fromatty) { 140779971Sobrien ointer = interactive; 140879971Sobrien interactive = 1; 1409223328Sgavin if (confirm(argv[0], NULL)) { 1410142129Smikeh mflag++; 141179971Sobrien } 141279971Sobrien interactive = ointer; 141379971Sobrien } 141479971Sobrien } 141579971Sobrien (void)xsignal(SIGINT, oldintr); 141679971Sobrien mflag = 0; 141779971Sobrien if (dest != odest) /* free up after globulize() */ 141879971Sobrien free(dest); 141979971Sobrien} 142079971Sobrien 142179971Sobrien/* 142279971Sobrien * Do a shell escape 142379971Sobrien */ 142479971Sobrien/*ARGSUSED*/ 142579971Sobrienvoid 142679971Sobrienshell(int argc, char *argv[]) 142779971Sobrien{ 142879971Sobrien pid_t pid; 1429142129Smikeh sigfunc oldintr; 1430223328Sgavin char shellnam[MAXPATHLEN]; 1431223328Sgavin const char *shellp, *namep; 143279971Sobrien int wait_status; 143379971Sobrien 143479971Sobrien if (argc == 0) { 1435223328Sgavin UPRINTF("usage: %s [command [args]]\n", argv[0]); 143679971Sobrien code = -1; 143779971Sobrien return; 143879971Sobrien } 1439142129Smikeh oldintr = xsignal(SIGINT, SIG_IGN); 144079971Sobrien if ((pid = fork()) == 0) { 144179971Sobrien for (pid = 3; pid < 20; pid++) 144279971Sobrien (void)close(pid); 144379971Sobrien (void)xsignal(SIGINT, SIG_DFL); 1444223328Sgavin shellp = getenv("SHELL"); 1445223328Sgavin if (shellp == NULL) 1446223328Sgavin shellp = _PATH_BSHELL; 1447223328Sgavin namep = strrchr(shellp, '/'); 144879971Sobrien if (namep == NULL) 1449223328Sgavin namep = shellp; 145079971Sobrien else 145179971Sobrien namep++; 145279971Sobrien (void)strlcpy(shellnam, namep, sizeof(shellnam)); 1453223328Sgavin if (ftp_debug) { 1454223328Sgavin fputs(shellp, ttyout); 145579971Sobrien putc('\n', ttyout); 145679971Sobrien } 145779971Sobrien if (argc > 1) { 1458223328Sgavin execl(shellp, shellnam, "-c", altarg, (char *)0); 145979971Sobrien } 146079971Sobrien else { 1461223328Sgavin execl(shellp, shellnam, (char *)0); 146279971Sobrien } 1463223328Sgavin warn("Can't execute `%s'", shellp); 146479971Sobrien code = -1; 146579971Sobrien exit(1); 146679971Sobrien } 146779971Sobrien if (pid > 0) 146879971Sobrien while (wait(&wait_status) != pid) 146979971Sobrien ; 1470142129Smikeh (void)xsignal(SIGINT, oldintr); 147179971Sobrien if (pid == -1) { 1472223328Sgavin warn("Can't fork a subshell; try again later"); 147379971Sobrien code = -1; 147479971Sobrien } else 147579971Sobrien code = 0; 147679971Sobrien} 147779971Sobrien 147879971Sobrien/* 147979971Sobrien * Send new user information (re-login) 148079971Sobrien */ 148179971Sobrienvoid 148279971Sobrienuser(int argc, char *argv[]) 148379971Sobrien{ 1484223328Sgavin char *password; 1485223328Sgavin char emptypass[] = ""; 148679971Sobrien int n, aflag = 0; 148779971Sobrien 148879971Sobrien if (argc == 0) 148979971Sobrien goto usage; 149079971Sobrien if (argc < 2) 149179971Sobrien (void)another(&argc, &argv, "username"); 149279971Sobrien if (argc < 2 || argc > 4) { 149379971Sobrien usage: 1494223328Sgavin UPRINTF("usage: %s username [password [account]]\n", 149579971Sobrien argv[0]); 149679971Sobrien code = -1; 149779971Sobrien return; 149879971Sobrien } 149979971Sobrien n = command("USER %s", argv[1]); 150079971Sobrien if (n == CONTINUE) { 150179971Sobrien if (argc < 3) { 1502223328Sgavin password = getpass("Password: "); 1503223328Sgavin if (password == NULL) 1504223328Sgavin password = emptypass; 1505223328Sgavin } else { 1506223328Sgavin password = argv[2]; 150779971Sobrien } 1508223328Sgavin n = command("PASS %s", password); 1509223328Sgavin memset(password, 0, strlen(password)); 151079971Sobrien } 151179971Sobrien if (n == CONTINUE) { 1512223328Sgavin aflag++; 151379971Sobrien if (argc < 4) { 1514223328Sgavin password = getpass("Account: "); 1515223328Sgavin if (password == NULL) 1516223328Sgavin password = emptypass; 1517223328Sgavin } else { 1518223328Sgavin password = argv[3]; 151979971Sobrien } 1520223328Sgavin n = command("ACCT %s", password); 1521223328Sgavin memset(password, 0, strlen(password)); 152279971Sobrien } 152379971Sobrien if (n != COMPLETE) { 152479971Sobrien fputs("Login failed.\n", ttyout); 152579971Sobrien return; 152679971Sobrien } 152779971Sobrien if (!aflag && argc == 4) { 1528223328Sgavin password = argv[3]; 1529223328Sgavin (void)command("ACCT %s", password); 1530223328Sgavin memset(password, 0, strlen(password)); 153179971Sobrien } 153279971Sobrien connected = -1; 153379971Sobrien getremoteinfo(); 153479971Sobrien} 153579971Sobrien 153679971Sobrien/* 153779971Sobrien * Print working directory on remote machine. 153879971Sobrien */ 153979971Sobrien/*VARARGS*/ 154079971Sobrienvoid 154179971Sobrienpwd(int argc, char *argv[]) 154279971Sobrien{ 154379971Sobrien 1544142129Smikeh code = -1; 1545142129Smikeh if (argc != 1) { 1546223328Sgavin UPRINTF("usage: %s\n", argv[0]); 154779971Sobrien return; 154879971Sobrien } 1549142129Smikeh if (! remotecwd[0]) 1550142129Smikeh updateremotecwd(); 1551142129Smikeh if (! remotecwd[0]) 1552142129Smikeh fprintf(ttyout, "Unable to determine remote directory\n"); 1553142129Smikeh else { 1554142129Smikeh fprintf(ttyout, "Remote directory: %s\n", remotecwd); 1555142129Smikeh code = 0; 155679971Sobrien } 155779971Sobrien} 155879971Sobrien 155979971Sobrien/* 156079971Sobrien * Print working directory on local machine. 156179971Sobrien */ 156279971Sobrienvoid 156379971Sobrienlpwd(int argc, char *argv[]) 156479971Sobrien{ 156579971Sobrien 1566142129Smikeh code = -1; 1567142129Smikeh if (argc != 1) { 1568223328Sgavin UPRINTF("usage: %s\n", argv[0]); 156979971Sobrien return; 157079971Sobrien } 1571142129Smikeh if (! localcwd[0]) 1572142129Smikeh updatelocalcwd(); 1573142129Smikeh if (! localcwd[0]) 1574142129Smikeh fprintf(ttyout, "Unable to determine local directory\n"); 1575142129Smikeh else { 1576142129Smikeh fprintf(ttyout, "Local directory: %s\n", localcwd); 157779971Sobrien code = 0; 157879971Sobrien } 157979971Sobrien} 158079971Sobrien 158179971Sobrien/* 158279971Sobrien * Make a directory. 158379971Sobrien */ 158479971Sobrienvoid 158579971Sobrienmakedir(int argc, char *argv[]) 158679971Sobrien{ 1587121966Smikeh int r; 158879971Sobrien 158979971Sobrien if (argc == 0 || argc > 2 || 159079971Sobrien (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1591223328Sgavin UPRINTF("usage: %s directory-name\n", argv[0]); 159279971Sobrien code = -1; 159379971Sobrien return; 159479971Sobrien } 1595121966Smikeh r = command("MKD %s", argv[1]); 1596121966Smikeh if (r == ERROR && code == 500) { 159779971Sobrien if (verbose) 159879971Sobrien fputs("MKD command not recognized, trying XMKD.\n", 159979971Sobrien ttyout); 1600121966Smikeh r = command("XMKD %s", argv[1]); 160179971Sobrien } 1602121966Smikeh if (r == COMPLETE) 1603121966Smikeh dirchange = 1; 160479971Sobrien} 160579971Sobrien 160679971Sobrien/* 160779971Sobrien * Remove a directory. 160879971Sobrien */ 160979971Sobrienvoid 161079971Sobrienremovedir(int argc, char *argv[]) 161179971Sobrien{ 1612121966Smikeh int r; 161379971Sobrien 161479971Sobrien if (argc == 0 || argc > 2 || 161579971Sobrien (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1616223328Sgavin UPRINTF("usage: %s directory-name\n", argv[0]); 161779971Sobrien code = -1; 161879971Sobrien return; 161979971Sobrien } 1620121966Smikeh r = command("RMD %s", argv[1]); 1621121966Smikeh if (r == ERROR && code == 500) { 162279971Sobrien if (verbose) 162379971Sobrien fputs("RMD command not recognized, trying XRMD.\n", 162479971Sobrien ttyout); 1625121966Smikeh r = command("XRMD %s", argv[1]); 162679971Sobrien } 1627121966Smikeh if (r == COMPLETE) 1628121966Smikeh dirchange = 1; 162979971Sobrien} 163079971Sobrien 163179971Sobrien/* 163279971Sobrien * Send a line, verbatim, to the remote machine. 163379971Sobrien */ 163479971Sobrienvoid 163579971Sobrienquote(int argc, char *argv[]) 163679971Sobrien{ 163779971Sobrien 163879971Sobrien if (argc == 0 || 163979971Sobrien (argc == 1 && !another(&argc, &argv, "command line to send"))) { 1640223328Sgavin UPRINTF("usage: %s line-to-send\n", argv[0]); 164179971Sobrien code = -1; 164279971Sobrien return; 164379971Sobrien } 164479971Sobrien quote1("", argc, argv); 164579971Sobrien} 164679971Sobrien 164779971Sobrien/* 164879971Sobrien * Send a SITE command to the remote machine. The line 164979971Sobrien * is sent verbatim to the remote machine, except that the 165079971Sobrien * word "SITE" is added at the front. 165179971Sobrien */ 165279971Sobrienvoid 165379971Sobriensite(int argc, char *argv[]) 165479971Sobrien{ 165579971Sobrien 165679971Sobrien if (argc == 0 || 165779971Sobrien (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){ 1658223328Sgavin UPRINTF("usage: %s line-to-send\n", argv[0]); 165979971Sobrien code = -1; 166079971Sobrien return; 166179971Sobrien } 166279971Sobrien quote1("SITE ", argc, argv); 166379971Sobrien} 166479971Sobrien 166579971Sobrien/* 166679971Sobrien * Turn argv[1..argc) into a space-separated string, then prepend initial text. 166779971Sobrien * Send the result as a one-line command and get response. 166879971Sobrien */ 166979971Sobrienvoid 167079971Sobrienquote1(const char *initial, int argc, char *argv[]) 167179971Sobrien{ 167279971Sobrien int i; 167379971Sobrien char buf[BUFSIZ]; /* must be >= sizeof(line) */ 167479971Sobrien 167579971Sobrien (void)strlcpy(buf, initial, sizeof(buf)); 167679971Sobrien for (i = 1; i < argc; i++) { 167779971Sobrien (void)strlcat(buf, argv[i], sizeof(buf)); 167879971Sobrien if (i < (argc - 1)) 167979971Sobrien (void)strlcat(buf, " ", sizeof(buf)); 168079971Sobrien } 168179971Sobrien if (command("%s", buf) == PRELIM) { 168279971Sobrien while (getreply(0) == PRELIM) 168379971Sobrien continue; 168479971Sobrien } 1685121966Smikeh dirchange = 1; 168679971Sobrien} 168779971Sobrien 168879971Sobrienvoid 168979971Sobriendo_chmod(int argc, char *argv[]) 169079971Sobrien{ 169179971Sobrien 169279971Sobrien if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode"))) 169379971Sobrien goto usage; 169479971Sobrien if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 169579971Sobrien usage: 1696223328Sgavin UPRINTF("usage: %s mode remote-file\n", argv[0]); 169779971Sobrien code = -1; 169879971Sobrien return; 169979971Sobrien } 170079971Sobrien (void)command("SITE CHMOD %s %s", argv[1], argv[2]); 170179971Sobrien} 170279971Sobrien 1703146309Smikeh#define COMMAND_1ARG(argc, argv, cmd) \ 170498247Smikeh if (argc == 1) \ 170598247Smikeh command(cmd); \ 170698247Smikeh else \ 170798247Smikeh command(cmd " %s", argv[1]) 170898247Smikeh 170979971Sobrienvoid 171079971Sobriendo_umask(int argc, char *argv[]) 171179971Sobrien{ 171279971Sobrien int oldverbose = verbose; 171379971Sobrien 171479971Sobrien if (argc == 0) { 1715223328Sgavin UPRINTF("usage: %s [umask]\n", argv[0]); 171679971Sobrien code = -1; 171779971Sobrien return; 171879971Sobrien } 171979971Sobrien verbose = 1; 172098247Smikeh COMMAND_1ARG(argc, argv, "SITE UMASK"); 172179971Sobrien verbose = oldverbose; 172279971Sobrien} 172379971Sobrien 172479971Sobrienvoid 172579971Sobrienidlecmd(int argc, char *argv[]) 172679971Sobrien{ 172779971Sobrien int oldverbose = verbose; 172879971Sobrien 172979971Sobrien if (argc < 1 || argc > 2) { 1730223328Sgavin UPRINTF("usage: %s [seconds]\n", argv[0]); 173179971Sobrien code = -1; 173279971Sobrien return; 173379971Sobrien } 173479971Sobrien verbose = 1; 173598247Smikeh COMMAND_1ARG(argc, argv, "SITE IDLE"); 173679971Sobrien verbose = oldverbose; 173779971Sobrien} 173879971Sobrien 173979971Sobrien/* 174079971Sobrien * Ask the other side for help. 174179971Sobrien */ 174279971Sobrienvoid 174379971Sobrienrmthelp(int argc, char *argv[]) 174479971Sobrien{ 174579971Sobrien int oldverbose = verbose; 174679971Sobrien 174779971Sobrien if (argc == 0) { 1748223328Sgavin UPRINTF("usage: %s\n", argv[0]); 174979971Sobrien code = -1; 175079971Sobrien return; 175179971Sobrien } 175279971Sobrien verbose = 1; 175398247Smikeh COMMAND_1ARG(argc, argv, "HELP"); 175479971Sobrien verbose = oldverbose; 175579971Sobrien} 175679971Sobrien 175779971Sobrien/* 175879971Sobrien * Terminate session and exit. 175979971Sobrien * May be called with 0, NULL. 176079971Sobrien */ 176179971Sobrien/*VARARGS*/ 176279971Sobrienvoid 176379971Sobrienquit(int argc, char *argv[]) 176479971Sobrien{ 176579971Sobrien 176679971Sobrien /* this may be called with argc == 0, argv == NULL */ 176779971Sobrien if (argc == 0 && argv != NULL) { 1768223328Sgavin UPRINTF("usage: %s\n", argv[0]); 176979971Sobrien code = -1; 177079971Sobrien return; 177179971Sobrien } 177279971Sobrien if (connected) 177379971Sobrien disconnect(0, NULL); 177479971Sobrien pswitch(1); 177579971Sobrien if (connected) 177679971Sobrien disconnect(0, NULL); 177779971Sobrien exit(0); 177879971Sobrien} 177979971Sobrien 178079971Sobrien/* 178179971Sobrien * Terminate session, but don't exit. 178279971Sobrien * May be called with 0, NULL. 178379971Sobrien */ 178479971Sobrienvoid 178579971Sobriendisconnect(int argc, char *argv[]) 178679971Sobrien{ 178779971Sobrien 178879971Sobrien /* this may be called with argc == 0, argv == NULL */ 178979971Sobrien if (argc == 0 && argv != NULL) { 1790223328Sgavin UPRINTF("usage: %s\n", argv[0]); 179179971Sobrien code = -1; 179279971Sobrien return; 179379971Sobrien } 179479971Sobrien if (!connected) 179579971Sobrien return; 179679971Sobrien (void)command("QUIT"); 179779971Sobrien cleanuppeer(); 179879971Sobrien} 179979971Sobrien 180079971Sobrienvoid 180179971Sobrienaccount(int argc, char *argv[]) 180279971Sobrien{ 180379971Sobrien char *ap; 1804223328Sgavin char emptypass[] = ""; 180579971Sobrien 180679971Sobrien if (argc == 0 || argc > 2) { 1807223328Sgavin UPRINTF("usage: %s [password]\n", argv[0]); 180879971Sobrien code = -1; 180979971Sobrien return; 181079971Sobrien } 181179971Sobrien else if (argc == 2) 181279971Sobrien ap = argv[1]; 1813223328Sgavin else { 181479971Sobrien ap = getpass("Account:"); 1815223328Sgavin if (ap == NULL) 1816223328Sgavin ap = emptypass; 1817223328Sgavin } 181879971Sobrien (void)command("ACCT %s", ap); 1819223328Sgavin memset(ap, 0, strlen(ap)); 182079971Sobrien} 182179971Sobrien 182279971Sobriensigjmp_buf abortprox; 182379971Sobrien 182479971Sobrienvoid 182579971Sobrienproxabort(int notused) 182679971Sobrien{ 182779971Sobrien 1828142129Smikeh sigint_raised = 1; 182979971Sobrien alarmtimer(0); 183079971Sobrien if (!proxy) { 183179971Sobrien pswitch(1); 183279971Sobrien } 183379971Sobrien if (connected) { 183479971Sobrien proxflag = 1; 183579971Sobrien } 183679971Sobrien else { 183779971Sobrien proxflag = 0; 183879971Sobrien } 183979971Sobrien pswitch(0); 184079971Sobrien siglongjmp(abortprox, 1); 184179971Sobrien} 184279971Sobrien 184379971Sobrienvoid 184479971Sobriendoproxy(int argc, char *argv[]) 184579971Sobrien{ 184679971Sobrien struct cmd *c; 184779971Sobrien int cmdpos; 184879971Sobrien sigfunc oldintr; 1849223328Sgavin char cmdbuf[MAX_C_NAME]; 185079971Sobrien 185179971Sobrien if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) { 1852223328Sgavin UPRINTF("usage: %s command\n", argv[0]); 185379971Sobrien code = -1; 185479971Sobrien return; 185579971Sobrien } 185679971Sobrien c = getcmd(argv[1]); 185779971Sobrien if (c == (struct cmd *) -1) { 185879971Sobrien fputs("?Ambiguous command.\n", ttyout); 185979971Sobrien code = -1; 186079971Sobrien return; 186179971Sobrien } 186279971Sobrien if (c == 0) { 186379971Sobrien fputs("?Invalid command.\n", ttyout); 186479971Sobrien code = -1; 186579971Sobrien return; 186679971Sobrien } 186779971Sobrien if (!c->c_proxy) { 186879971Sobrien fputs("?Invalid proxy command.\n", ttyout); 186979971Sobrien code = -1; 187079971Sobrien return; 187179971Sobrien } 187279971Sobrien if (sigsetjmp(abortprox, 1)) { 187379971Sobrien code = -1; 187479971Sobrien return; 187579971Sobrien } 187679971Sobrien oldintr = xsignal(SIGINT, proxabort); 187779971Sobrien pswitch(1); 187879971Sobrien if (c->c_conn && !connected) { 187979971Sobrien fputs("Not connected.\n", ttyout); 188079971Sobrien pswitch(0); 188179971Sobrien (void)xsignal(SIGINT, oldintr); 188279971Sobrien code = -1; 188379971Sobrien return; 188479971Sobrien } 188579971Sobrien cmdpos = strcspn(line, " \t"); 188679971Sobrien if (cmdpos > 0) /* remove leading "proxy " from input buffer */ 188779971Sobrien memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); 1888223328Sgavin (void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf)); 1889223328Sgavin argv[1] = cmdbuf; 189079971Sobrien (*c->c_handler)(argc-1, argv+1); 189179971Sobrien if (connected) { 189279971Sobrien proxflag = 1; 189379971Sobrien } 189479971Sobrien else { 189579971Sobrien proxflag = 0; 189679971Sobrien } 189779971Sobrien pswitch(0); 189879971Sobrien (void)xsignal(SIGINT, oldintr); 189979971Sobrien} 190079971Sobrien 190179971Sobrienvoid 190279971Sobriensetcase(int argc, char *argv[]) 190379971Sobrien{ 190479971Sobrien 190579971Sobrien code = togglevar(argc, argv, &mcase, "Case mapping"); 190679971Sobrien} 190779971Sobrien 190879971Sobrien/* 190979971Sobrien * convert the given name to lower case if it's all upper case, into 191079971Sobrien * a static buffer which is returned to the caller 191179971Sobrien */ 1912142129Smikehstatic const char * 1913142129Smikehdocase(char *dst, size_t dlen, const char *src) 191479971Sobrien{ 1915142129Smikeh size_t i; 1916142129Smikeh int dochange = 1; 191779971Sobrien 1918142129Smikeh for (i = 0; src[i] != '\0' && i < dlen - 1; i++) { 1919142129Smikeh dst[i] = src[i]; 1920142129Smikeh if (islower((unsigned char)dst[i])) 192179971Sobrien dochange = 0; 192279971Sobrien } 1923142129Smikeh dst[i] = '\0'; 192479971Sobrien 192579971Sobrien if (dochange) { 1926142129Smikeh for (i = 0; dst[i] != '\0'; i++) 1927142129Smikeh if (isupper((unsigned char)dst[i])) 1928142129Smikeh dst[i] = tolower((unsigned char)dst[i]); 192979971Sobrien } 1930142129Smikeh return dst; 193179971Sobrien} 193279971Sobrien 193379971Sobrienvoid 193479971Sobriensetcr(int argc, char *argv[]) 193579971Sobrien{ 193679971Sobrien 193779971Sobrien code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); 193879971Sobrien} 193979971Sobrien 194079971Sobrienvoid 194179971Sobriensetntrans(int argc, char *argv[]) 194279971Sobrien{ 194379971Sobrien 194479971Sobrien if (argc == 0 || argc > 3) { 1945223328Sgavin UPRINTF("usage: %s [inchars [outchars]]\n", argv[0]); 194679971Sobrien code = -1; 194779971Sobrien return; 194879971Sobrien } 194979971Sobrien if (argc == 1) { 195079971Sobrien ntflag = 0; 195179971Sobrien fputs("Ntrans off.\n", ttyout); 195279971Sobrien code = ntflag; 195379971Sobrien return; 195479971Sobrien } 195579971Sobrien ntflag++; 195679971Sobrien code = ntflag; 195779971Sobrien (void)strlcpy(ntin, argv[1], sizeof(ntin)); 195879971Sobrien if (argc == 2) { 195979971Sobrien ntout[0] = '\0'; 196079971Sobrien return; 196179971Sobrien } 196279971Sobrien (void)strlcpy(ntout, argv[2], sizeof(ntout)); 196379971Sobrien} 196479971Sobrien 1965142129Smikehstatic const char * 1966142129Smikehdotrans(char *dst, size_t dlen, const char *src) 196779971Sobrien{ 1968142129Smikeh const char *cp1; 1969142129Smikeh char *cp2 = dst; 1970142129Smikeh size_t i, ostop; 197179971Sobrien 197279971Sobrien for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 197379971Sobrien continue; 1974142129Smikeh for (cp1 = src; *cp1; cp1++) { 1975142129Smikeh int found = 0; 197679971Sobrien for (i = 0; *(ntin + i) && i < 16; i++) { 197779971Sobrien if (*cp1 == *(ntin + i)) { 197879971Sobrien found++; 197979971Sobrien if (i < ostop) { 198079971Sobrien *cp2++ = *(ntout + i); 1981223328Sgavin if (cp2 - dst >= (ptrdiff_t)(dlen - 1)) 1982142129Smikeh goto out; 198379971Sobrien } 198479971Sobrien break; 198579971Sobrien } 198679971Sobrien } 198779971Sobrien if (!found) { 198879971Sobrien *cp2++ = *cp1; 198979971Sobrien } 199079971Sobrien } 1991142129Smikehout: 199279971Sobrien *cp2 = '\0'; 1993142129Smikeh return dst; 199479971Sobrien} 199579971Sobrien 199679971Sobrienvoid 199779971Sobriensetnmap(int argc, char *argv[]) 199879971Sobrien{ 199979971Sobrien char *cp; 200079971Sobrien 200179971Sobrien if (argc == 1) { 200279971Sobrien mapflag = 0; 200379971Sobrien fputs("Nmap off.\n", ttyout); 200479971Sobrien code = mapflag; 200579971Sobrien return; 200679971Sobrien } 200779971Sobrien if (argc == 0 || 200879971Sobrien (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) { 2009223328Sgavin UPRINTF("usage: %s [mapin mapout]\n", argv[0]); 201079971Sobrien code = -1; 201179971Sobrien return; 201279971Sobrien } 201379971Sobrien mapflag = 1; 201479971Sobrien code = 1; 201579971Sobrien cp = strchr(altarg, ' '); 201679971Sobrien if (proxy) { 201779971Sobrien while(*++cp == ' ') 201879971Sobrien continue; 201979971Sobrien altarg = cp; 202079971Sobrien cp = strchr(altarg, ' '); 202179971Sobrien } 202279971Sobrien *cp = '\0'; 202379971Sobrien (void)strlcpy(mapin, altarg, MAXPATHLEN); 202479971Sobrien while (*++cp == ' ') 202579971Sobrien continue; 202679971Sobrien (void)strlcpy(mapout, cp, MAXPATHLEN); 202779971Sobrien} 202879971Sobrien 2029142129Smikehstatic const char * 2030142129Smikehdomap(char *dst, size_t dlen, const char *src) 203179971Sobrien{ 2032142129Smikeh const char *cp1 = src; 2033142129Smikeh char *cp2 = mapin; 2034142129Smikeh const char *tp[9], *te[9]; 203579971Sobrien int i, toks[9], toknum = 0, match = 1; 203679971Sobrien 203779971Sobrien for (i=0; i < 9; ++i) { 203879971Sobrien toks[i] = 0; 203979971Sobrien } 204079971Sobrien while (match && *cp1 && *cp2) { 204179971Sobrien switch (*cp2) { 204279971Sobrien case '\\': 204379971Sobrien if (*++cp2 != *cp1) { 204479971Sobrien match = 0; 204579971Sobrien } 204679971Sobrien break; 204779971Sobrien case '$': 204879971Sobrien if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 204979971Sobrien if (*cp1 != *(++cp2+1)) { 205079971Sobrien toks[toknum = *cp2 - '1']++; 205179971Sobrien tp[toknum] = cp1; 205279971Sobrien while (*++cp1 && *(cp2+1) 205379971Sobrien != *cp1); 205479971Sobrien te[toknum] = cp1; 205579971Sobrien } 205679971Sobrien cp2++; 205779971Sobrien break; 205879971Sobrien } 205979971Sobrien /* FALLTHROUGH */ 206079971Sobrien default: 206179971Sobrien if (*cp2 != *cp1) { 206279971Sobrien match = 0; 206379971Sobrien } 206479971Sobrien break; 206579971Sobrien } 206679971Sobrien if (match && *cp1) { 206779971Sobrien cp1++; 206879971Sobrien } 206979971Sobrien if (match && *cp2) { 207079971Sobrien cp2++; 207179971Sobrien } 207279971Sobrien } 207379971Sobrien if (!match && *cp1) /* last token mismatch */ 207479971Sobrien { 207579971Sobrien toks[toknum] = 0; 207679971Sobrien } 2077142129Smikeh cp2 = dst; 2078142129Smikeh *cp2 = '\0'; 2079142129Smikeh cp1 = mapout; 2080142129Smikeh while (*cp1) { 208179971Sobrien match = 0; 2082142129Smikeh switch (*cp1) { 208379971Sobrien case '\\': 2084142129Smikeh if (*(cp1 + 1)) { 2085142129Smikeh *cp2++ = *++cp1; 208679971Sobrien } 208779971Sobrien break; 208879971Sobrien case '[': 208979971SobrienLOOP: 2090142129Smikeh if (*++cp1 == '$' && 2091142129Smikeh isdigit((unsigned char)*(cp1+1))) { 2092142129Smikeh if (*++cp1 == '0') { 2093142129Smikeh const char *cp3 = src; 209479971Sobrien 209579971Sobrien while (*cp3) { 2096142129Smikeh *cp2++ = *cp3++; 209779971Sobrien } 209879971Sobrien match = 1; 209979971Sobrien } 2100142129Smikeh else if (toks[toknum = *cp1 - '1']) { 2101142129Smikeh const char *cp3 = tp[toknum]; 210279971Sobrien 210379971Sobrien while (cp3 != te[toknum]) { 2104142129Smikeh *cp2++ = *cp3++; 210579971Sobrien } 210679971Sobrien match = 1; 210779971Sobrien } 210879971Sobrien } 210979971Sobrien else { 2110142129Smikeh while (*cp1 && *cp1 != ',' && 2111142129Smikeh *cp1 != ']') { 2112142129Smikeh if (*cp1 == '\\') { 2113142129Smikeh cp1++; 211479971Sobrien } 2115142129Smikeh else if (*cp1 == '$' && 2116142129Smikeh isdigit((unsigned char)*(cp1+1))) { 2117142129Smikeh if (*++cp1 == '0') { 2118142129Smikeh const char *cp3 = src; 211979971Sobrien 212079971Sobrien while (*cp3) { 2121142129Smikeh *cp2++ = *cp3++; 212279971Sobrien } 212379971Sobrien } 212479971Sobrien else if (toks[toknum = 2125142129Smikeh *cp1 - '1']) { 2126142129Smikeh const char *cp3=tp[toknum]; 212779971Sobrien 212879971Sobrien while (cp3 != 212979971Sobrien te[toknum]) { 2130142129Smikeh *cp2++ = *cp3++; 213179971Sobrien } 213279971Sobrien } 213379971Sobrien } 2134142129Smikeh else if (*cp1) { 2135142129Smikeh *cp2++ = *cp1++; 213679971Sobrien } 213779971Sobrien } 2138142129Smikeh if (!*cp1) { 213979971Sobrien fputs( 214079971Sobrien "nmap: unbalanced brackets.\n", 214179971Sobrien ttyout); 2142142129Smikeh return (src); 214379971Sobrien } 214479971Sobrien match = 1; 2145142129Smikeh cp1--; 214679971Sobrien } 214779971Sobrien if (match) { 2148142129Smikeh while (*++cp1 && *cp1 != ']') { 2149142129Smikeh if (*cp1 == '\\' && *(cp1 + 1)) { 2150142129Smikeh cp1++; 215179971Sobrien } 215279971Sobrien } 2153142129Smikeh if (!*cp1) { 215479971Sobrien fputs( 215579971Sobrien "nmap: unbalanced brackets.\n", 215679971Sobrien ttyout); 2157142129Smikeh return (src); 215879971Sobrien } 215979971Sobrien break; 216079971Sobrien } 2161142129Smikeh switch (*++cp1) { 216279971Sobrien case ',': 216379971Sobrien goto LOOP; 216479971Sobrien case ']': 216579971Sobrien break; 216679971Sobrien default: 2167142129Smikeh cp1--; 216879971Sobrien goto LOOP; 216979971Sobrien } 217079971Sobrien break; 217179971Sobrien case '$': 2172142129Smikeh if (isdigit((unsigned char)*(cp1 + 1))) { 2173142129Smikeh if (*++cp1 == '0') { 2174142129Smikeh const char *cp3 = src; 217579971Sobrien 217679971Sobrien while (*cp3) { 2177142129Smikeh *cp2++ = *cp3++; 217879971Sobrien } 217979971Sobrien } 2180142129Smikeh else if (toks[toknum = *cp1 - '1']) { 2181142129Smikeh const char *cp3 = tp[toknum]; 218279971Sobrien 218379971Sobrien while (cp3 != te[toknum]) { 2184142129Smikeh *cp2++ = *cp3++; 218579971Sobrien } 218679971Sobrien } 218779971Sobrien break; 218879971Sobrien } 218979971Sobrien /* intentional drop through */ 219079971Sobrien default: 2191142129Smikeh *cp2++ = *cp1; 219279971Sobrien break; 219379971Sobrien } 2194142129Smikeh cp1++; 219579971Sobrien } 2196142129Smikeh *cp2 = '\0'; 2197142129Smikeh return *dst ? dst : src; 219879971Sobrien} 219979971Sobrien 220079971Sobrienvoid 220179971Sobriensetpassive(int argc, char *argv[]) 220279971Sobrien{ 220379971Sobrien 220479971Sobrien if (argc == 1) { 220579971Sobrien passivemode = !passivemode; 220679971Sobrien activefallback = passivemode; 220779971Sobrien } else if (argc != 2) { 220879971Sobrien passiveusage: 2209223328Sgavin UPRINTF("usage: %s [ on | off | auto ]\n", argv[0]); 221079971Sobrien code = -1; 221179971Sobrien return; 221279971Sobrien } else if (strcasecmp(argv[1], "on") == 0) { 221379971Sobrien passivemode = 1; 221479971Sobrien activefallback = 0; 221579971Sobrien } else if (strcasecmp(argv[1], "off") == 0) { 221679971Sobrien passivemode = 0; 221779971Sobrien activefallback = 0; 221879971Sobrien } else if (strcasecmp(argv[1], "auto") == 0) { 221979971Sobrien passivemode = 1; 222079971Sobrien activefallback = 1; 222179971Sobrien } else 222279971Sobrien goto passiveusage; 222379971Sobrien fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 222479971Sobrien onoff(passivemode), onoff(activefallback)); 222579971Sobrien code = passivemode; 222679971Sobrien} 222779971Sobrien 2228223328Sgavin 222979971Sobrienvoid 223079971Sobriensetepsv4(int argc, char *argv[]) 223179971Sobrien{ 223279971Sobrien code = togglevar(argc, argv, &epsv4, 223379971Sobrien verbose ? "EPSV/EPRT on IPv4" : NULL); 223479971Sobrien epsv4bad = 0; 223579971Sobrien} 223679971Sobrien 223779971Sobrienvoid 2238223328Sgavinsetepsv6(int argc, char *argv[]) 2239223328Sgavin{ 2240223328Sgavin code = togglevar(argc, argv, &epsv6, 2241223328Sgavin verbose ? "EPSV/EPRT on IPv6" : NULL); 2242223328Sgavin epsv6bad = 0; 2243223328Sgavin} 2244223328Sgavin 2245223328Sgavinvoid 2246223328Sgavinsetepsv(int argc, char*argv[]) 2247223328Sgavin{ 2248223328Sgavin setepsv4(argc,argv); 2249223328Sgavin setepsv6(argc,argv); 2250223328Sgavin} 2251223328Sgavin 2252223328Sgavinvoid 225379971Sobriensetsunique(int argc, char *argv[]) 225479971Sobrien{ 225579971Sobrien 225679971Sobrien code = togglevar(argc, argv, &sunique, "Store unique"); 225779971Sobrien} 225879971Sobrien 225979971Sobrienvoid 226079971Sobriensetrunique(int argc, char *argv[]) 226179971Sobrien{ 226279971Sobrien 226379971Sobrien code = togglevar(argc, argv, &runique, "Receive unique"); 226479971Sobrien} 226579971Sobrien 226679971Sobrienint 226779971Sobrienparserate(int argc, char *argv[], int cmdlineopt) 226879971Sobrien{ 226979971Sobrien int dir, max, incr, showonly; 227079971Sobrien sigfunc oldusr1, oldusr2; 227179971Sobrien 227279971Sobrien if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) { 227379971Sobrien usage: 227479971Sobrien if (cmdlineopt) 2275223328Sgavin UPRINTF( 227679971Sobrien "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n", 227779971Sobrien argv[0]); 227879971Sobrien else 2279223328Sgavin UPRINTF( 228079971Sobrien "usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n", 228179971Sobrien argv[0]); 228279971Sobrien return -1; 228379971Sobrien } 228479971Sobrien dir = max = incr = showonly = 0; 228579971Sobrien#define RATE_GET 1 228679971Sobrien#define RATE_PUT 2 228779971Sobrien#define RATE_ALL (RATE_GET | RATE_PUT) 228879971Sobrien 228979971Sobrien if (strcasecmp(argv[1], "all") == 0) 229079971Sobrien dir = RATE_ALL; 229179971Sobrien else if (strcasecmp(argv[1], "get") == 0) 229279971Sobrien dir = RATE_GET; 229379971Sobrien else if (strcasecmp(argv[1], "put") == 0) 229479971Sobrien dir = RATE_PUT; 229579971Sobrien else 229679971Sobrien goto usage; 229779971Sobrien 229879971Sobrien if (argc >= 3) { 229979971Sobrien if ((max = strsuftoi(argv[2])) < 0) 230079971Sobrien goto usage; 230179971Sobrien } else 230279971Sobrien showonly = 1; 230379971Sobrien 230479971Sobrien if (argc == 4) { 230579971Sobrien if ((incr = strsuftoi(argv[3])) <= 0) 230679971Sobrien goto usage; 230779971Sobrien } else 230879971Sobrien incr = DEFAULTINCR; 230979971Sobrien 231079971Sobrien oldusr1 = xsignal(SIGUSR1, SIG_IGN); 231179971Sobrien oldusr2 = xsignal(SIGUSR2, SIG_IGN); 231279971Sobrien if (dir & RATE_GET) { 231379971Sobrien if (!showonly) { 231479971Sobrien rate_get = max; 231579971Sobrien rate_get_incr = incr; 231679971Sobrien } 231779971Sobrien if (!cmdlineopt || verbose) 231879971Sobrien fprintf(ttyout, 231979971Sobrien "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 232079971Sobrien onoff(rate_get), rate_get, rate_get_incr); 232179971Sobrien } 232279971Sobrien if (dir & RATE_PUT) { 232379971Sobrien if (!showonly) { 232479971Sobrien rate_put = max; 232579971Sobrien rate_put_incr = incr; 232679971Sobrien } 232779971Sobrien if (!cmdlineopt || verbose) 232879971Sobrien fprintf(ttyout, 232979971Sobrien "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 233079971Sobrien onoff(rate_put), rate_put, rate_put_incr); 233179971Sobrien } 233279971Sobrien (void)xsignal(SIGUSR1, oldusr1); 233379971Sobrien (void)xsignal(SIGUSR2, oldusr2); 233479971Sobrien return 0; 233579971Sobrien} 233679971Sobrien 233779971Sobrienvoid 233879971Sobriensetrate(int argc, char *argv[]) 233979971Sobrien{ 234079971Sobrien 234179971Sobrien code = parserate(argc, argv, 0); 234279971Sobrien} 234379971Sobrien 234479971Sobrien/* change directory to parent directory */ 234579971Sobrienvoid 234679971Sobriencdup(int argc, char *argv[]) 234779971Sobrien{ 234879971Sobrien int r; 234979971Sobrien 235079971Sobrien if (argc == 0) { 2351223328Sgavin UPRINTF("usage: %s\n", argv[0]); 235279971Sobrien code = -1; 235379971Sobrien return; 235479971Sobrien } 235579971Sobrien r = command("CDUP"); 235679971Sobrien if (r == ERROR && code == 500) { 235779971Sobrien if (verbose) 235879971Sobrien fputs("CDUP command not recognized, trying XCUP.\n", 235979971Sobrien ttyout); 236079971Sobrien r = command("XCUP"); 236179971Sobrien } 236279971Sobrien if (r == COMPLETE) { 236379971Sobrien dirchange = 1; 2364142129Smikeh updateremotecwd(); 236579971Sobrien } 236679971Sobrien} 236779971Sobrien 236879971Sobrien/* 236979971Sobrien * Restart transfer at specific point 237079971Sobrien */ 237179971Sobrienvoid 237279971Sobrienrestart(int argc, char *argv[]) 237379971Sobrien{ 237479971Sobrien 237579971Sobrien if (argc == 0 || argc > 2) { 2376223328Sgavin UPRINTF("usage: %s [restart-point]\n", argv[0]); 237779971Sobrien code = -1; 237879971Sobrien return; 237979971Sobrien } 238079971Sobrien if (! features[FEAT_REST_STREAM]) { 238179971Sobrien fprintf(ttyout, 238279971Sobrien "Restart is not supported by the remote server.\n"); 238379971Sobrien return; 238479971Sobrien } 238579971Sobrien if (argc == 2) { 238679971Sobrien off_t rp; 238779971Sobrien char *ep; 238879971Sobrien 238979971Sobrien rp = STRTOLL(argv[1], &ep, 10); 239079971Sobrien if (rp < 0 || *ep != '\0') 239179971Sobrien fprintf(ttyout, "restart: Invalid offset `%s'\n", 239279971Sobrien argv[1]); 239379971Sobrien else 239479971Sobrien restart_point = rp; 239579971Sobrien } 239679971Sobrien if (restart_point == 0) 239779971Sobrien fputs("No restart point defined.\n", ttyout); 239879971Sobrien else 239979971Sobrien fprintf(ttyout, 240079971Sobrien "Restarting at " LLF " for next get, put or append\n", 240179971Sobrien (LLT)restart_point); 240279971Sobrien} 240379971Sobrien 240479971Sobrien/* 240579971Sobrien * Show remote system type 240679971Sobrien */ 240779971Sobrienvoid 240879971Sobriensyst(int argc, char *argv[]) 240979971Sobrien{ 241079971Sobrien int oldverbose = verbose; 241179971Sobrien 241279971Sobrien if (argc == 0) { 2413223328Sgavin UPRINTF("usage: %s\n", argv[0]); 241479971Sobrien code = -1; 241579971Sobrien return; 241679971Sobrien } 241779971Sobrien verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 241879971Sobrien (void)command("SYST"); 241979971Sobrien verbose = oldverbose; 242079971Sobrien} 242179971Sobrien 242279971Sobrienvoid 242379971Sobrienmacdef(int argc, char *argv[]) 242479971Sobrien{ 242579971Sobrien char *tmp; 242679971Sobrien int c; 242779971Sobrien 242879971Sobrien if (argc == 0) 242979971Sobrien goto usage; 243079971Sobrien if (macnum == 16) { 243179971Sobrien fputs("Limit of 16 macros have already been defined.\n", 243279971Sobrien ttyout); 243379971Sobrien code = -1; 243479971Sobrien return; 243579971Sobrien } 243679971Sobrien if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) { 243779971Sobrien usage: 2438223328Sgavin UPRINTF("usage: %s macro_name\n", argv[0]); 243979971Sobrien code = -1; 244079971Sobrien return; 244179971Sobrien } 244279971Sobrien if (interactive) 244379971Sobrien fputs( 244479971Sobrien "Enter macro line by line, terminating it with a null line.\n", 244579971Sobrien ttyout); 244679971Sobrien (void)strlcpy(macros[macnum].mac_name, argv[1], 244779971Sobrien sizeof(macros[macnum].mac_name)); 244879971Sobrien if (macnum == 0) 244979971Sobrien macros[macnum].mac_start = macbuf; 245079971Sobrien else 245179971Sobrien macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 245279971Sobrien tmp = macros[macnum].mac_start; 245379971Sobrien while (tmp != macbuf+4096) { 245479971Sobrien if ((c = getchar()) == EOF) { 245579971Sobrien fputs("macdef: end of file encountered.\n", ttyout); 245679971Sobrien code = -1; 245779971Sobrien return; 245879971Sobrien } 245979971Sobrien if ((*tmp = c) == '\n') { 246079971Sobrien if (tmp == macros[macnum].mac_start) { 246179971Sobrien macros[macnum++].mac_end = tmp; 246279971Sobrien code = 0; 246379971Sobrien return; 246479971Sobrien } 246579971Sobrien if (*(tmp-1) == '\0') { 246679971Sobrien macros[macnum++].mac_end = tmp - 1; 246779971Sobrien code = 0; 246879971Sobrien return; 246979971Sobrien } 247079971Sobrien *tmp = '\0'; 247179971Sobrien } 247279971Sobrien tmp++; 247379971Sobrien } 247479971Sobrien while (1) { 247579971Sobrien while ((c = getchar()) != '\n' && c != EOF) 247679971Sobrien /* LOOP */; 247779971Sobrien if (c == EOF || getchar() == '\n') { 247879971Sobrien fputs("Macro not defined - 4K buffer exceeded.\n", 247979971Sobrien ttyout); 248079971Sobrien code = -1; 248179971Sobrien return; 248279971Sobrien } 248379971Sobrien } 248479971Sobrien} 248579971Sobrien 248679971Sobrien/* 248779971Sobrien * Get size of file on remote machine 248879971Sobrien */ 248979971Sobrienvoid 249079971Sobriensizecmd(int argc, char *argv[]) 249179971Sobrien{ 249279971Sobrien off_t size; 249379971Sobrien 249479971Sobrien if (argc == 0 || argc > 2 || 249579971Sobrien (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2496223328Sgavin UPRINTF("usage: %s remote-file\n", argv[0]); 249779971Sobrien code = -1; 249879971Sobrien return; 249979971Sobrien } 250079971Sobrien size = remotesize(argv[1], 1); 250179971Sobrien if (size != -1) 250279971Sobrien fprintf(ttyout, 250379971Sobrien "%s\t" LLF "\n", argv[1], (LLT)size); 250479971Sobrien code = (size > 0); 250579971Sobrien} 250679971Sobrien 250779971Sobrien/* 250879971Sobrien * Get last modification time of file on remote machine 250979971Sobrien */ 251079971Sobrienvoid 251179971Sobrienmodtime(int argc, char *argv[]) 251279971Sobrien{ 251379971Sobrien time_t mtime; 251479971Sobrien 251579971Sobrien if (argc == 0 || argc > 2 || 251679971Sobrien (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2517223328Sgavin UPRINTF("usage: %s remote-file\n", argv[0]); 251879971Sobrien code = -1; 251979971Sobrien return; 252079971Sobrien } 252179971Sobrien mtime = remotemodtime(argv[1], 1); 252279971Sobrien if (mtime != -1) 2523223328Sgavin fprintf(ttyout, "%s\t%s", argv[1], 2524223328Sgavin rfc2822time(localtime(&mtime))); 252579971Sobrien code = (mtime > 0); 252679971Sobrien} 252779971Sobrien 252879971Sobrien/* 252979971Sobrien * Show status on remote machine 253079971Sobrien */ 253179971Sobrienvoid 253279971Sobrienrmtstatus(int argc, char *argv[]) 253379971Sobrien{ 253479971Sobrien 253579971Sobrien if (argc == 0) { 2536223328Sgavin UPRINTF("usage: %s [remote-file]\n", argv[0]); 253779971Sobrien code = -1; 253879971Sobrien return; 253979971Sobrien } 254098247Smikeh COMMAND_1ARG(argc, argv, "STAT"); 254179971Sobrien} 254279971Sobrien 254379971Sobrien/* 254479971Sobrien * Get file if modtime is more recent than current file 254579971Sobrien */ 254679971Sobrienvoid 254779971Sobriennewer(int argc, char *argv[]) 254879971Sobrien{ 254979971Sobrien 255079971Sobrien if (getit(argc, argv, -1, "w")) 255179971Sobrien fprintf(ttyout, 255279971Sobrien "Local file \"%s\" is newer than remote file \"%s\".\n", 255379971Sobrien argv[2], argv[1]); 255479971Sobrien} 255579971Sobrien 255679971Sobrien/* 255779971Sobrien * Display one local file through $PAGER. 255879971Sobrien */ 255979971Sobrienvoid 256079971Sobrienlpage(int argc, char *argv[]) 256179971Sobrien{ 2562223328Sgavin size_t len; 2563223328Sgavin const char *p; 2564223328Sgavin char *pager, *locfile; 256579971Sobrien 256679971Sobrien if (argc == 0 || argc > 2 || 256779971Sobrien (argc == 1 && !another(&argc, &argv, "local-file"))) { 2568223328Sgavin UPRINTF("usage: %s local-file\n", argv[0]); 256979971Sobrien code = -1; 257079971Sobrien return; 257179971Sobrien } 257279971Sobrien if ((locfile = globulize(argv[1])) == NULL) { 257379971Sobrien code = -1; 257479971Sobrien return; 257579971Sobrien } 257679971Sobrien p = getoptionvalue("pager"); 257779971Sobrien if (EMPTYSTRING(p)) 257879971Sobrien p = DEFAULTPAGER; 257979971Sobrien len = strlen(p) + strlen(locfile) + 2; 2580223328Sgavin pager = ftp_malloc(len); 258179971Sobrien (void)strlcpy(pager, p, len); 258279971Sobrien (void)strlcat(pager, " ", len); 258379971Sobrien (void)strlcat(pager, locfile, len); 258479971Sobrien system(pager); 258579971Sobrien code = 0; 258679971Sobrien (void)free(pager); 258779971Sobrien (void)free(locfile); 258879971Sobrien} 258979971Sobrien 259079971Sobrien/* 259179971Sobrien * Display one remote file through $PAGER. 259279971Sobrien */ 259379971Sobrienvoid 259479971Sobrienpage(int argc, char *argv[]) 259579971Sobrien{ 2596223328Sgavin int ohash, orestart_point, overbose; 2597223328Sgavin size_t len; 2598223328Sgavin const char *p; 2599223328Sgavin char *pager; 260079971Sobrien 260179971Sobrien if (argc == 0 || argc > 2 || 260279971Sobrien (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2603223328Sgavin UPRINTF("usage: %s remote-file\n", argv[0]); 260479971Sobrien code = -1; 260579971Sobrien return; 260679971Sobrien } 260779971Sobrien p = getoptionvalue("pager"); 260879971Sobrien if (EMPTYSTRING(p)) 260979971Sobrien p = DEFAULTPAGER; 261079971Sobrien len = strlen(p) + 2; 2611223328Sgavin pager = ftp_malloc(len); 261279971Sobrien pager[0] = '|'; 261379971Sobrien (void)strlcpy(pager + 1, p, len - 1); 261479971Sobrien 261579971Sobrien ohash = hash; 261679971Sobrien orestart_point = restart_point; 261779971Sobrien overbose = verbose; 261879971Sobrien hash = restart_point = verbose = 0; 261998247Smikeh recvrequest("RETR", pager, argv[1], "r+", 1, 0); 262079971Sobrien hash = ohash; 262179971Sobrien restart_point = orestart_point; 262279971Sobrien verbose = overbose; 262379971Sobrien (void)free(pager); 262479971Sobrien} 262579971Sobrien 262679971Sobrien/* 262779971Sobrien * Set the socket send or receive buffer size. 262879971Sobrien */ 262979971Sobrienvoid 263079971Sobriensetxferbuf(int argc, char *argv[]) 263179971Sobrien{ 263279971Sobrien int size, dir; 263379971Sobrien 263479971Sobrien if (argc != 2) { 263579971Sobrien usage: 2636223328Sgavin UPRINTF("usage: %s size\n", argv[0]); 263779971Sobrien code = -1; 263879971Sobrien return; 263979971Sobrien } 264079971Sobrien if (strcasecmp(argv[0], "sndbuf") == 0) 264179971Sobrien dir = RATE_PUT; 264279971Sobrien else if (strcasecmp(argv[0], "rcvbuf") == 0) 264379971Sobrien dir = RATE_GET; 264479971Sobrien else if (strcasecmp(argv[0], "xferbuf") == 0) 264579971Sobrien dir = RATE_ALL; 264679971Sobrien else 264779971Sobrien goto usage; 264879971Sobrien 264979971Sobrien if ((size = strsuftoi(argv[1])) == -1) 265079971Sobrien goto usage; 265179971Sobrien 265279971Sobrien if (size == 0) { 265379971Sobrien fprintf(ttyout, "%s: size must be positive.\n", argv[0]); 265479971Sobrien goto usage; 265579971Sobrien } 265679971Sobrien 265779971Sobrien if (dir & RATE_PUT) 265879971Sobrien sndbuf_size = size; 265979971Sobrien if (dir & RATE_GET) 266079971Sobrien rcvbuf_size = size; 266179971Sobrien fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n", 266279971Sobrien sndbuf_size, rcvbuf_size); 266379971Sobrien code = 0; 266479971Sobrien} 266579971Sobrien 266679971Sobrien/* 266779971Sobrien * Set or display options (defaults are provided by various env vars) 266879971Sobrien */ 266979971Sobrienvoid 267079971Sobriensetoption(int argc, char *argv[]) 267179971Sobrien{ 267279971Sobrien struct option *o; 267379971Sobrien 267479971Sobrien code = -1; 267579971Sobrien if (argc == 0 || (argc != 1 && argc != 3)) { 2676223328Sgavin UPRINTF("usage: %s [option value]\n", argv[0]); 267779971Sobrien return; 267879971Sobrien } 267979971Sobrien 268079971Sobrien#define OPTIONINDENT ((int) sizeof("http_proxy")) 268179971Sobrien if (argc == 1) { 268279971Sobrien for (o = optiontab; o->name != NULL; o++) { 268379971Sobrien fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT, 268479971Sobrien o->name, o->value ? o->value : ""); 268579971Sobrien } 268679971Sobrien } else { 2687223328Sgavin set_option(argv[1], argv[2], 1); 268879971Sobrien } 268979971Sobrien code = 0; 269079971Sobrien} 269179971Sobrien 2692223328Sgavinvoid 2693223328Sgavinset_option(const char * option, const char * value, int doverbose) 2694223328Sgavin{ 2695223328Sgavin struct option *o; 2696223328Sgavin 2697223328Sgavin o = getoption(option); 2698223328Sgavin if (o == NULL) { 2699223328Sgavin fprintf(ttyout, "No such option `%s'.\n", option); 2700223328Sgavin return; 2701223328Sgavin } 2702223328Sgavin FREEPTR(o->value); 2703223328Sgavin o->value = ftp_strdup(value); 2704223328Sgavin if (verbose && doverbose) 2705223328Sgavin fprintf(ttyout, "Setting `%s' to `%s'.\n", 2706223328Sgavin o->name, o->value); 2707223328Sgavin} 2708223328Sgavin 270979971Sobrien/* 271079971Sobrien * Unset an option 271179971Sobrien */ 271279971Sobrienvoid 271379971Sobrienunsetoption(int argc, char *argv[]) 271479971Sobrien{ 271579971Sobrien struct option *o; 271679971Sobrien 271779971Sobrien code = -1; 271879971Sobrien if (argc == 0 || argc != 2) { 2719223328Sgavin UPRINTF("usage: %s option\n", argv[0]); 272079971Sobrien return; 272179971Sobrien } 272279971Sobrien 272379971Sobrien o = getoption(argv[1]); 272479971Sobrien if (o == NULL) { 272579971Sobrien fprintf(ttyout, "No such option `%s'.\n", argv[1]); 272679971Sobrien return; 272779971Sobrien } 272879971Sobrien FREEPTR(o->value); 272979971Sobrien fprintf(ttyout, "Unsetting `%s'.\n", o->name); 273079971Sobrien code = 0; 273179971Sobrien} 273279971Sobrien 273379971Sobrien/* 273479971Sobrien * Display features supported by the remote host. 273579971Sobrien */ 273679971Sobrienvoid 273779971Sobrienfeat(int argc, char *argv[]) 273879971Sobrien{ 273979971Sobrien int oldverbose = verbose; 274079971Sobrien 274179971Sobrien if (argc == 0) { 2742223328Sgavin UPRINTF("usage: %s\n", argv[0]); 274379971Sobrien code = -1; 274479971Sobrien return; 274579971Sobrien } 274679971Sobrien if (! features[FEAT_FEAT]) { 274779971Sobrien fprintf(ttyout, 274879971Sobrien "FEAT is not supported by the remote server.\n"); 274979971Sobrien return; 275079971Sobrien } 275179971Sobrien verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 275279971Sobrien (void)command("FEAT"); 275379971Sobrien verbose = oldverbose; 275479971Sobrien} 275579971Sobrien 275679971Sobrienvoid 275779971Sobrienmlst(int argc, char *argv[]) 275879971Sobrien{ 275979971Sobrien int oldverbose = verbose; 276079971Sobrien 276179971Sobrien if (argc < 1 || argc > 2) { 2762223328Sgavin UPRINTF("usage: %s [remote-path]\n", argv[0]); 276379971Sobrien code = -1; 276479971Sobrien return; 276579971Sobrien } 276679971Sobrien if (! features[FEAT_MLST]) { 276779971Sobrien fprintf(ttyout, 276879971Sobrien "MLST is not supported by the remote server.\n"); 276979971Sobrien return; 277079971Sobrien } 277179971Sobrien verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 277298247Smikeh COMMAND_1ARG(argc, argv, "MLST"); 277379971Sobrien verbose = oldverbose; 277479971Sobrien} 277579971Sobrien 277679971Sobrienvoid 277779971Sobrienopts(int argc, char *argv[]) 277879971Sobrien{ 277979971Sobrien int oldverbose = verbose; 278079971Sobrien 278179971Sobrien if (argc < 2 || argc > 3) { 2782223328Sgavin UPRINTF("usage: %s command [options]\n", argv[0]); 278379971Sobrien code = -1; 278479971Sobrien return; 278579971Sobrien } 278679971Sobrien if (! features[FEAT_FEAT]) { 278779971Sobrien fprintf(ttyout, 278879971Sobrien "OPTS is not supported by the remote server.\n"); 278979971Sobrien return; 279079971Sobrien } 279179971Sobrien verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 279298247Smikeh if (argc == 2) 279398247Smikeh command("OPTS %s", argv[1]); 279498247Smikeh else 279598247Smikeh command("OPTS %s %s", argv[1], argv[2]); 279679971Sobrien verbose = oldverbose; 279779971Sobrien} 2798