1cc361f65SGavin Atkinson /* $NetBSD: cmds.c,v 1.17 2010/01/12 06:55:47 lukem Exp $ */ 2cc361f65SGavin Atkinson /* from NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp */ 3f982db4aSGavin Atkinson 4f982db4aSGavin Atkinson /*- 5cc361f65SGavin Atkinson * Copyright (c) 1996-2009 The NetBSD Foundation, Inc. 6f982db4aSGavin Atkinson * All rights reserved. 7f982db4aSGavin Atkinson * 8f982db4aSGavin Atkinson * This code is derived from software contributed to The NetBSD Foundation 9f982db4aSGavin Atkinson * by Luke Mewburn. 10f982db4aSGavin Atkinson * 11f982db4aSGavin Atkinson * This code is derived from software contributed to The NetBSD Foundation 12f982db4aSGavin Atkinson * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 13f982db4aSGavin Atkinson * NASA Ames Research Center. 14f982db4aSGavin Atkinson * 15f982db4aSGavin Atkinson * Redistribution and use in source and binary forms, with or without 16f982db4aSGavin Atkinson * modification, are permitted provided that the following conditions 17f982db4aSGavin Atkinson * are met: 18f982db4aSGavin Atkinson * 1. Redistributions of source code must retain the above copyright 19f982db4aSGavin Atkinson * notice, this list of conditions and the following disclaimer. 20f982db4aSGavin Atkinson * 2. Redistributions in binary form must reproduce the above copyright 21f982db4aSGavin Atkinson * notice, this list of conditions and the following disclaimer in the 22f982db4aSGavin Atkinson * documentation and/or other materials provided with the distribution. 23f982db4aSGavin Atkinson * 24f982db4aSGavin Atkinson * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25f982db4aSGavin Atkinson * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26f982db4aSGavin Atkinson * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27f982db4aSGavin Atkinson * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28f982db4aSGavin Atkinson * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29f982db4aSGavin Atkinson * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30f982db4aSGavin Atkinson * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31f982db4aSGavin Atkinson * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32f982db4aSGavin Atkinson * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33f982db4aSGavin Atkinson * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34f982db4aSGavin Atkinson * POSSIBILITY OF SUCH DAMAGE. 35f982db4aSGavin Atkinson */ 36f982db4aSGavin Atkinson 37f982db4aSGavin Atkinson /* 38f982db4aSGavin Atkinson * Copyright (c) 1985, 1989, 1993, 1994 39f982db4aSGavin Atkinson * The Regents of the University of California. All rights reserved. 40f982db4aSGavin Atkinson * 41f982db4aSGavin Atkinson * Redistribution and use in source and binary forms, with or without 42f982db4aSGavin Atkinson * modification, are permitted provided that the following conditions 43f982db4aSGavin Atkinson * are met: 44f982db4aSGavin Atkinson * 1. Redistributions of source code must retain the above copyright 45f982db4aSGavin Atkinson * notice, this list of conditions and the following disclaimer. 46f982db4aSGavin Atkinson * 2. Redistributions in binary form must reproduce the above copyright 47f982db4aSGavin Atkinson * notice, this list of conditions and the following disclaimer in the 48f982db4aSGavin Atkinson * documentation and/or other materials provided with the distribution. 49f982db4aSGavin Atkinson * 3. Neither the name of the University nor the names of its contributors 50f982db4aSGavin Atkinson * may be used to endorse or promote products derived from this software 51f982db4aSGavin Atkinson * without specific prior written permission. 52f982db4aSGavin Atkinson * 53f982db4aSGavin Atkinson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 54f982db4aSGavin Atkinson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 55f982db4aSGavin Atkinson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 56f982db4aSGavin Atkinson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 57f982db4aSGavin Atkinson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 58f982db4aSGavin Atkinson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 59f982db4aSGavin Atkinson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 60f982db4aSGavin Atkinson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 61f982db4aSGavin Atkinson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 62f982db4aSGavin Atkinson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 63f982db4aSGavin Atkinson * SUCH DAMAGE. 64f982db4aSGavin Atkinson */ 65f982db4aSGavin Atkinson 66f982db4aSGavin Atkinson /* 67f982db4aSGavin Atkinson * Copyright (C) 1997 and 1998 WIDE Project. 68f982db4aSGavin Atkinson * All rights reserved. 69f982db4aSGavin Atkinson * 70f982db4aSGavin Atkinson * Redistribution and use in source and binary forms, with or without 71f982db4aSGavin Atkinson * modification, are permitted provided that the following conditions 72f982db4aSGavin Atkinson * are met: 73f982db4aSGavin Atkinson * 1. Redistributions of source code must retain the above copyright 74f982db4aSGavin Atkinson * notice, this list of conditions and the following disclaimer. 75f982db4aSGavin Atkinson * 2. Redistributions in binary form must reproduce the above copyright 76f982db4aSGavin Atkinson * notice, this list of conditions and the following disclaimer in the 77f982db4aSGavin Atkinson * documentation and/or other materials provided with the distribution. 78f982db4aSGavin Atkinson * 3. Neither the name of the project nor the names of its contributors 79f982db4aSGavin Atkinson * may be used to endorse or promote products derived from this software 80f982db4aSGavin Atkinson * without specific prior written permission. 81f982db4aSGavin Atkinson * 82f982db4aSGavin Atkinson * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 83f982db4aSGavin Atkinson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 84f982db4aSGavin Atkinson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 85f982db4aSGavin Atkinson * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 86f982db4aSGavin Atkinson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 87f982db4aSGavin Atkinson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 88f982db4aSGavin Atkinson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 89f982db4aSGavin Atkinson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 90f982db4aSGavin Atkinson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 91f982db4aSGavin Atkinson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 92f982db4aSGavin Atkinson * SUCH DAMAGE. 93f982db4aSGavin Atkinson */ 94f982db4aSGavin Atkinson 95cc361f65SGavin Atkinson #include "tnftp.h" 96cc361f65SGavin Atkinson 97cc361f65SGavin Atkinson #if 0 /* tnftp */ 98cc361f65SGavin Atkinson 99f982db4aSGavin Atkinson #include <sys/cdefs.h> 100f982db4aSGavin Atkinson #ifndef lint 101f982db4aSGavin Atkinson #if 0 102f982db4aSGavin Atkinson static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94"; 103f982db4aSGavin Atkinson #else 104cc361f65SGavin Atkinson __RCSID(" NetBSD: cmds.c,v 1.130 2009/07/13 19:05:41 roy Exp "); 105f982db4aSGavin Atkinson #endif 106f982db4aSGavin Atkinson #endif /* not lint */ 107f982db4aSGavin Atkinson 108f982db4aSGavin Atkinson /* 109f982db4aSGavin Atkinson * FTP User Program -- Command Routines. 110f982db4aSGavin Atkinson */ 111f982db4aSGavin Atkinson #include <sys/types.h> 112f982db4aSGavin Atkinson #include <sys/socket.h> 113f982db4aSGavin Atkinson #include <sys/stat.h> 114f982db4aSGavin Atkinson #include <sys/wait.h> 115f982db4aSGavin Atkinson #include <arpa/ftp.h> 116f982db4aSGavin Atkinson 117f982db4aSGavin Atkinson #include <ctype.h> 118f982db4aSGavin Atkinson #include <err.h> 119f982db4aSGavin Atkinson #include <glob.h> 120f982db4aSGavin Atkinson #include <limits.h> 121f982db4aSGavin Atkinson #include <netdb.h> 122f982db4aSGavin Atkinson #include <paths.h> 123cc361f65SGavin Atkinson #include <stddef.h> 124f982db4aSGavin Atkinson #include <stdio.h> 125f982db4aSGavin Atkinson #include <stdlib.h> 126f982db4aSGavin Atkinson #include <string.h> 127f982db4aSGavin Atkinson #include <time.h> 128f982db4aSGavin Atkinson #include <unistd.h> 129cc361f65SGavin Atkinson 130cc361f65SGavin Atkinson #endif /* tnftp */ 131f982db4aSGavin Atkinson 132f982db4aSGavin Atkinson #include "ftp_var.h" 133f982db4aSGavin Atkinson #include "version.h" 134f982db4aSGavin Atkinson 135cc361f65SGavin Atkinson static struct types { 136cc361f65SGavin Atkinson const char *t_name; 137cc361f65SGavin Atkinson const char *t_mode; 138f982db4aSGavin Atkinson int t_type; 139cc361f65SGavin Atkinson const char *t_arg; 140f982db4aSGavin Atkinson } types[] = { 141f982db4aSGavin Atkinson { "ascii", "A", TYPE_A, 0 }, 142f982db4aSGavin Atkinson { "binary", "I", TYPE_I, 0 }, 143f982db4aSGavin Atkinson { "image", "I", TYPE_I, 0 }, 144f982db4aSGavin Atkinson { "ebcdic", "E", TYPE_E, 0 }, 145f982db4aSGavin Atkinson { "tenex", "L", TYPE_L, bytename }, 146cc361f65SGavin Atkinson { NULL, NULL, 0, NULL } 147f982db4aSGavin Atkinson }; 148f982db4aSGavin Atkinson 149cc361f65SGavin Atkinson static sigjmp_buf jabort; 150f982db4aSGavin Atkinson 151f982db4aSGavin Atkinson static int confirm(const char *, const char *); 152cc361f65SGavin Atkinson static void mintr(int); 153cc361f65SGavin Atkinson static void mabort(const char *); 154cc361f65SGavin Atkinson static void set_type(const char *); 155f982db4aSGavin Atkinson 156f982db4aSGavin Atkinson static const char *doprocess(char *, size_t, const char *, int, int, int); 157f982db4aSGavin Atkinson static const char *domap(char *, size_t, const char *); 158f982db4aSGavin Atkinson static const char *docase(char *, size_t, const char *); 159f982db4aSGavin Atkinson static const char *dotrans(char *, size_t, const char *); 160f982db4aSGavin Atkinson 161cc361f65SGavin Atkinson /* 162cc361f65SGavin Atkinson * Confirm if "cmd" is to be performed upon "file". 163cc361f65SGavin Atkinson * If "file" is NULL, generate a "Continue with" prompt instead. 164cc361f65SGavin Atkinson */ 165f982db4aSGavin Atkinson static int 166f982db4aSGavin Atkinson confirm(const char *cmd, const char *file) 167f982db4aSGavin Atkinson { 168cc361f65SGavin Atkinson const char *errormsg; 169cc361f65SGavin Atkinson char cline[BUFSIZ]; 170cc361f65SGavin Atkinson const char *promptleft, *promptright; 171f982db4aSGavin Atkinson 172f982db4aSGavin Atkinson if (!interactive || confirmrest) 173f982db4aSGavin Atkinson return (1); 174cc361f65SGavin Atkinson if (file == NULL) { 175cc361f65SGavin Atkinson promptleft = "Continue with"; 176cc361f65SGavin Atkinson promptright = cmd; 177cc361f65SGavin Atkinson } else { 178cc361f65SGavin Atkinson promptleft = cmd; 179cc361f65SGavin Atkinson promptright = file; 180cc361f65SGavin Atkinson } 181f982db4aSGavin Atkinson while (1) { 182cc361f65SGavin Atkinson fprintf(ttyout, "%s %s [anpqy?]? ", promptleft, promptright); 183f982db4aSGavin Atkinson (void)fflush(ttyout); 184cc361f65SGavin Atkinson if (get_line(stdin, cline, sizeof(cline), &errormsg) < 0) { 185f982db4aSGavin Atkinson mflag = 0; 186cc361f65SGavin Atkinson fprintf(ttyout, "%s; %s aborted\n", errormsg, cmd); 187f982db4aSGavin Atkinson return (0); 188f982db4aSGavin Atkinson } 189cc361f65SGavin Atkinson switch (tolower((unsigned char)*cline)) { 190f982db4aSGavin Atkinson case 'a': 191f982db4aSGavin Atkinson confirmrest = 1; 192f982db4aSGavin Atkinson fprintf(ttyout, 193f982db4aSGavin Atkinson "Prompting off for duration of %s.\n", cmd); 194f982db4aSGavin Atkinson break; 195f982db4aSGavin Atkinson case 'p': 196f982db4aSGavin Atkinson interactive = 0; 197f982db4aSGavin Atkinson fputs("Interactive mode: off.\n", ttyout); 198f982db4aSGavin Atkinson break; 199f982db4aSGavin Atkinson case 'q': 200f982db4aSGavin Atkinson mflag = 0; 201cc361f65SGavin Atkinson fprintf(ttyout, "%s aborted.\n", cmd); 202f982db4aSGavin Atkinson /* FALLTHROUGH */ 203f982db4aSGavin Atkinson case 'n': 204f982db4aSGavin Atkinson return (0); 205f982db4aSGavin Atkinson case '?': 206f982db4aSGavin Atkinson fprintf(ttyout, 207f982db4aSGavin Atkinson " confirmation options:\n" 208f982db4aSGavin Atkinson "\ta answer `yes' for the duration of %s\n" 209f982db4aSGavin Atkinson "\tn answer `no' for this file\n" 210f982db4aSGavin Atkinson "\tp turn off `prompt' mode\n" 211f982db4aSGavin Atkinson "\tq stop the current %s\n" 212f982db4aSGavin Atkinson "\ty answer `yes' for this file\n" 213f982db4aSGavin Atkinson "\t? this help list\n", 214f982db4aSGavin Atkinson cmd, cmd); 215f982db4aSGavin Atkinson continue; /* back to while(1) */ 216f982db4aSGavin Atkinson } 217f982db4aSGavin Atkinson return (1); 218f982db4aSGavin Atkinson } 219f982db4aSGavin Atkinson /* NOTREACHED */ 220f982db4aSGavin Atkinson } 221f982db4aSGavin Atkinson 222f982db4aSGavin Atkinson /* 223f982db4aSGavin Atkinson * Set transfer type. 224f982db4aSGavin Atkinson */ 225f982db4aSGavin Atkinson void 226f982db4aSGavin Atkinson settype(int argc, char *argv[]) 227f982db4aSGavin Atkinson { 228f982db4aSGavin Atkinson struct types *p; 229f982db4aSGavin Atkinson 230f982db4aSGavin Atkinson if (argc == 0 || argc > 2) { 231cc361f65SGavin Atkinson const char *sep; 232f982db4aSGavin Atkinson 233cc361f65SGavin Atkinson UPRINTF("usage: %s [", argv[0]); 234f982db4aSGavin Atkinson sep = " "; 235f982db4aSGavin Atkinson for (p = types; p->t_name; p++) { 236f982db4aSGavin Atkinson fprintf(ttyout, "%s%s", sep, p->t_name); 237f982db4aSGavin Atkinson sep = " | "; 238f982db4aSGavin Atkinson } 239f982db4aSGavin Atkinson fputs(" ]\n", ttyout); 240f982db4aSGavin Atkinson code = -1; 241f982db4aSGavin Atkinson return; 242f982db4aSGavin Atkinson } 243f982db4aSGavin Atkinson if (argc < 2) { 244f982db4aSGavin Atkinson fprintf(ttyout, "Using %s mode to transfer files.\n", typename); 245f982db4aSGavin Atkinson code = 0; 246f982db4aSGavin Atkinson return; 247f982db4aSGavin Atkinson } 248cc361f65SGavin Atkinson set_type(argv[1]); 249cc361f65SGavin Atkinson } 250cc361f65SGavin Atkinson 251cc361f65SGavin Atkinson void 252cc361f65SGavin Atkinson set_type(const char *ttype) 253cc361f65SGavin Atkinson { 254cc361f65SGavin Atkinson struct types *p; 255cc361f65SGavin Atkinson int comret; 256cc361f65SGavin Atkinson 257f982db4aSGavin Atkinson for (p = types; p->t_name; p++) 258cc361f65SGavin Atkinson if (strcmp(ttype, p->t_name) == 0) 259f982db4aSGavin Atkinson break; 260f982db4aSGavin Atkinson if (p->t_name == 0) { 261cc361f65SGavin Atkinson fprintf(ttyout, "%s: unknown mode.\n", ttype); 262f982db4aSGavin Atkinson code = -1; 263f982db4aSGavin Atkinson return; 264f982db4aSGavin Atkinson } 265f982db4aSGavin Atkinson if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 266f982db4aSGavin Atkinson comret = command("TYPE %s %s", p->t_mode, p->t_arg); 267f982db4aSGavin Atkinson else 268f982db4aSGavin Atkinson comret = command("TYPE %s", p->t_mode); 269f982db4aSGavin Atkinson if (comret == COMPLETE) { 270f982db4aSGavin Atkinson (void)strlcpy(typename, p->t_name, sizeof(typename)); 271f982db4aSGavin Atkinson curtype = type = p->t_type; 272f982db4aSGavin Atkinson } 273f982db4aSGavin Atkinson } 274f982db4aSGavin Atkinson 275f982db4aSGavin Atkinson /* 276f982db4aSGavin Atkinson * Internal form of settype; changes current type in use with server 277f982db4aSGavin Atkinson * without changing our notion of the type for data transfers. 278f982db4aSGavin Atkinson * Used to change to and from ascii for listings. 279f982db4aSGavin Atkinson */ 280f982db4aSGavin Atkinson void 281f982db4aSGavin Atkinson changetype(int newtype, int show) 282f982db4aSGavin Atkinson { 283f982db4aSGavin Atkinson struct types *p; 284f982db4aSGavin Atkinson int comret, oldverbose = verbose; 285f982db4aSGavin Atkinson 286f982db4aSGavin Atkinson if (newtype == 0) 287f982db4aSGavin Atkinson newtype = TYPE_I; 288f982db4aSGavin Atkinson if (newtype == curtype) 289f982db4aSGavin Atkinson return; 290cc361f65SGavin Atkinson if (ftp_debug == 0 && show == 0) 291f982db4aSGavin Atkinson verbose = 0; 292f982db4aSGavin Atkinson for (p = types; p->t_name; p++) 293f982db4aSGavin Atkinson if (newtype == p->t_type) 294f982db4aSGavin Atkinson break; 295f982db4aSGavin Atkinson if (p->t_name == 0) { 296cc361f65SGavin Atkinson errx(1, "changetype: unknown type %d", newtype); 297f982db4aSGavin Atkinson } 298f982db4aSGavin Atkinson if (newtype == TYPE_L && bytename[0] != '\0') 299f982db4aSGavin Atkinson comret = command("TYPE %s %s", p->t_mode, bytename); 300f982db4aSGavin Atkinson else 301f982db4aSGavin Atkinson comret = command("TYPE %s", p->t_mode); 302f982db4aSGavin Atkinson if (comret == COMPLETE) 303f982db4aSGavin Atkinson curtype = newtype; 304f982db4aSGavin Atkinson verbose = oldverbose; 305f982db4aSGavin Atkinson } 306f982db4aSGavin Atkinson 307f982db4aSGavin Atkinson /* 308f982db4aSGavin Atkinson * Set binary transfer type. 309f982db4aSGavin Atkinson */ 310f982db4aSGavin Atkinson /*VARARGS*/ 311f982db4aSGavin Atkinson void 312f982db4aSGavin Atkinson setbinary(int argc, char *argv[]) 313f982db4aSGavin Atkinson { 314f982db4aSGavin Atkinson 315f982db4aSGavin Atkinson if (argc == 0) { 316cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 317f982db4aSGavin Atkinson code = -1; 318f982db4aSGavin Atkinson return; 319f982db4aSGavin Atkinson } 320cc361f65SGavin Atkinson set_type("binary"); 321f982db4aSGavin Atkinson } 322f982db4aSGavin Atkinson 323f982db4aSGavin Atkinson /* 324f982db4aSGavin Atkinson * Set ascii transfer type. 325f982db4aSGavin Atkinson */ 326f982db4aSGavin Atkinson /*VARARGS*/ 327f982db4aSGavin Atkinson void 328f982db4aSGavin Atkinson setascii(int argc, char *argv[]) 329f982db4aSGavin Atkinson { 330f982db4aSGavin Atkinson 331f982db4aSGavin Atkinson if (argc == 0) { 332cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 333f982db4aSGavin Atkinson code = -1; 334f982db4aSGavin Atkinson return; 335f982db4aSGavin Atkinson } 336cc361f65SGavin Atkinson set_type("ascii"); 337f982db4aSGavin Atkinson } 338f982db4aSGavin Atkinson 339f982db4aSGavin Atkinson /* 340f982db4aSGavin Atkinson * Set tenex transfer type. 341f982db4aSGavin Atkinson */ 342f982db4aSGavin Atkinson /*VARARGS*/ 343f982db4aSGavin Atkinson void 344f982db4aSGavin Atkinson settenex(int argc, char *argv[]) 345f982db4aSGavin Atkinson { 346f982db4aSGavin Atkinson 347f982db4aSGavin Atkinson if (argc == 0) { 348cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 349f982db4aSGavin Atkinson code = -1; 350f982db4aSGavin Atkinson return; 351f982db4aSGavin Atkinson } 352cc361f65SGavin Atkinson set_type("tenex"); 353f982db4aSGavin Atkinson } 354f982db4aSGavin Atkinson 355f982db4aSGavin Atkinson /* 356f982db4aSGavin Atkinson * Set file transfer mode. 357f982db4aSGavin Atkinson */ 358f982db4aSGavin Atkinson /*ARGSUSED*/ 359f982db4aSGavin Atkinson void 360f982db4aSGavin Atkinson setftmode(int argc, char *argv[]) 361f982db4aSGavin Atkinson { 362f982db4aSGavin Atkinson 363f982db4aSGavin Atkinson if (argc != 2) { 364cc361f65SGavin Atkinson UPRINTF("usage: %s mode-name\n", argv[0]); 365f982db4aSGavin Atkinson code = -1; 366f982db4aSGavin Atkinson return; 367f982db4aSGavin Atkinson } 368f982db4aSGavin Atkinson fprintf(ttyout, "We only support %s mode, sorry.\n", modename); 369f982db4aSGavin Atkinson code = -1; 370f982db4aSGavin Atkinson } 371f982db4aSGavin Atkinson 372f982db4aSGavin Atkinson /* 373f982db4aSGavin Atkinson * Set file transfer format. 374f982db4aSGavin Atkinson */ 375f982db4aSGavin Atkinson /*ARGSUSED*/ 376f982db4aSGavin Atkinson void 377f982db4aSGavin Atkinson setform(int argc, char *argv[]) 378f982db4aSGavin Atkinson { 379f982db4aSGavin Atkinson 380f982db4aSGavin Atkinson if (argc != 2) { 381cc361f65SGavin Atkinson UPRINTF("usage: %s format\n", argv[0]); 382f982db4aSGavin Atkinson code = -1; 383f982db4aSGavin Atkinson return; 384f982db4aSGavin Atkinson } 385f982db4aSGavin Atkinson fprintf(ttyout, "We only support %s format, sorry.\n", formname); 386f982db4aSGavin Atkinson code = -1; 387f982db4aSGavin Atkinson } 388f982db4aSGavin Atkinson 389f982db4aSGavin Atkinson /* 390f982db4aSGavin Atkinson * Set file transfer structure. 391f982db4aSGavin Atkinson */ 392f982db4aSGavin Atkinson /*ARGSUSED*/ 393f982db4aSGavin Atkinson void 394f982db4aSGavin Atkinson setstruct(int argc, char *argv[]) 395f982db4aSGavin Atkinson { 396f982db4aSGavin Atkinson 397f982db4aSGavin Atkinson if (argc != 2) { 398cc361f65SGavin Atkinson UPRINTF("usage: %s struct-mode\n", argv[0]); 399f982db4aSGavin Atkinson code = -1; 400f982db4aSGavin Atkinson return; 401f982db4aSGavin Atkinson } 402f982db4aSGavin Atkinson fprintf(ttyout, "We only support %s structure, sorry.\n", structname); 403f982db4aSGavin Atkinson code = -1; 404f982db4aSGavin Atkinson } 405f982db4aSGavin Atkinson 406f982db4aSGavin Atkinson /* 407f982db4aSGavin Atkinson * Send a single file. 408f982db4aSGavin Atkinson */ 409f982db4aSGavin Atkinson void 410f982db4aSGavin Atkinson put(int argc, char *argv[]) 411f982db4aSGavin Atkinson { 412f982db4aSGavin Atkinson char buf[MAXPATHLEN]; 413cc361f65SGavin Atkinson const char *cmd; 414f982db4aSGavin Atkinson int loc = 0; 415f982db4aSGavin Atkinson char *locfile; 416f982db4aSGavin Atkinson const char *remfile; 417f982db4aSGavin Atkinson 418f982db4aSGavin Atkinson if (argc == 2) { 419f982db4aSGavin Atkinson argc++; 420f982db4aSGavin Atkinson argv[2] = argv[1]; 421f982db4aSGavin Atkinson loc++; 422f982db4aSGavin Atkinson } 423f982db4aSGavin Atkinson if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-file"))) 424f982db4aSGavin Atkinson goto usage; 425f982db4aSGavin Atkinson if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 426f982db4aSGavin Atkinson usage: 427cc361f65SGavin Atkinson UPRINTF("usage: %s local-file [remote-file]\n", argv[0]); 428f982db4aSGavin Atkinson code = -1; 429f982db4aSGavin Atkinson return; 430f982db4aSGavin Atkinson } 431f982db4aSGavin Atkinson if ((locfile = globulize(argv[1])) == NULL) { 432f982db4aSGavin Atkinson code = -1; 433f982db4aSGavin Atkinson return; 434f982db4aSGavin Atkinson } 435f982db4aSGavin Atkinson remfile = argv[2]; 436f982db4aSGavin Atkinson if (loc) /* If argv[2] is a copy of the old argv[1], update it */ 437f982db4aSGavin Atkinson remfile = locfile; 438f982db4aSGavin Atkinson cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 439f982db4aSGavin Atkinson remfile = doprocess(buf, sizeof(buf), remfile, 440f982db4aSGavin Atkinson 0, loc && ntflag, loc && mapflag); 441f982db4aSGavin Atkinson sendrequest(cmd, locfile, remfile, 442f982db4aSGavin Atkinson locfile != argv[1] || remfile != argv[2]); 443f982db4aSGavin Atkinson free(locfile); 444f982db4aSGavin Atkinson } 445f982db4aSGavin Atkinson 446f982db4aSGavin Atkinson static const char * 447f982db4aSGavin Atkinson doprocess(char *dst, size_t dlen, const char *src, 448f982db4aSGavin Atkinson int casef, int transf, int mapf) 449f982db4aSGavin Atkinson { 450f982db4aSGavin Atkinson if (casef) 451f982db4aSGavin Atkinson src = docase(dst, dlen, src); 452f982db4aSGavin Atkinson if (transf) 453f982db4aSGavin Atkinson src = dotrans(dst, dlen, src); 454f982db4aSGavin Atkinson if (mapf) 455f982db4aSGavin Atkinson src = domap(dst, dlen, src); 456f982db4aSGavin Atkinson return src; 457f982db4aSGavin Atkinson } 458f982db4aSGavin Atkinson 459f982db4aSGavin Atkinson /* 460f982db4aSGavin Atkinson * Send multiple files. 461f982db4aSGavin Atkinson */ 462f982db4aSGavin Atkinson void 463f982db4aSGavin Atkinson mput(int argc, char *argv[]) 464f982db4aSGavin Atkinson { 465f982db4aSGavin Atkinson int i; 466f982db4aSGavin Atkinson sigfunc oldintr; 467f982db4aSGavin Atkinson int ointer; 468f982db4aSGavin Atkinson const char *tp; 469f982db4aSGavin Atkinson 470f982db4aSGavin Atkinson if (argc == 0 || (argc == 1 && !another(&argc, &argv, "local-files"))) { 471cc361f65SGavin Atkinson UPRINTF("usage: %s local-files\n", argv[0]); 472f982db4aSGavin Atkinson code = -1; 473f982db4aSGavin Atkinson return; 474f982db4aSGavin Atkinson } 475f982db4aSGavin Atkinson mflag = 1; 476f982db4aSGavin Atkinson oldintr = xsignal(SIGINT, mintr); 477f982db4aSGavin Atkinson if (sigsetjmp(jabort, 1)) 478cc361f65SGavin Atkinson mabort(argv[0]); 479f982db4aSGavin Atkinson if (proxy) { 480f982db4aSGavin Atkinson char *cp; 481f982db4aSGavin Atkinson 482f982db4aSGavin Atkinson while ((cp = remglob(argv, 0, NULL)) != NULL) { 483f982db4aSGavin Atkinson if (*cp == '\0' || !connected) { 484f982db4aSGavin Atkinson mflag = 0; 485f982db4aSGavin Atkinson continue; 486f982db4aSGavin Atkinson } 487f982db4aSGavin Atkinson if (mflag && confirm(argv[0], cp)) { 488f982db4aSGavin Atkinson char buf[MAXPATHLEN]; 489f982db4aSGavin Atkinson tp = doprocess(buf, sizeof(buf), cp, 490f982db4aSGavin Atkinson mcase, ntflag, mapflag); 491f982db4aSGavin Atkinson sendrequest((sunique) ? "STOU" : "STOR", 492f982db4aSGavin Atkinson cp, tp, cp != tp || !interactive); 493f982db4aSGavin Atkinson if (!mflag && fromatty) { 494f982db4aSGavin Atkinson ointer = interactive; 495f982db4aSGavin Atkinson interactive = 1; 496cc361f65SGavin Atkinson if (confirm(argv[0], NULL)) { 497f982db4aSGavin Atkinson mflag++; 498f982db4aSGavin Atkinson } 499f982db4aSGavin Atkinson interactive = ointer; 500f982db4aSGavin Atkinson } 501f982db4aSGavin Atkinson } 502f982db4aSGavin Atkinson } 503f982db4aSGavin Atkinson goto cleanupmput; 504f982db4aSGavin Atkinson } 505f982db4aSGavin Atkinson for (i = 1; i < argc && connected; i++) { 506f982db4aSGavin Atkinson char **cpp; 507f982db4aSGavin Atkinson glob_t gl; 508f982db4aSGavin Atkinson int flags; 509f982db4aSGavin Atkinson 510f982db4aSGavin Atkinson if (!doglob) { 511f982db4aSGavin Atkinson if (mflag && confirm(argv[0], argv[i])) { 512f982db4aSGavin Atkinson char buf[MAXPATHLEN]; 513f982db4aSGavin Atkinson tp = doprocess(buf, sizeof(buf), argv[i], 514f982db4aSGavin Atkinson 0, ntflag, mapflag); 515f982db4aSGavin Atkinson sendrequest((sunique) ? "STOU" : "STOR", 516f982db4aSGavin Atkinson argv[i], tp, tp != argv[i] || !interactive); 517f982db4aSGavin Atkinson if (!mflag && fromatty) { 518f982db4aSGavin Atkinson ointer = interactive; 519f982db4aSGavin Atkinson interactive = 1; 520cc361f65SGavin Atkinson if (confirm(argv[0], NULL)) { 521f982db4aSGavin Atkinson mflag++; 522f982db4aSGavin Atkinson } 523f982db4aSGavin Atkinson interactive = ointer; 524f982db4aSGavin Atkinson } 525f982db4aSGavin Atkinson } 526f982db4aSGavin Atkinson continue; 527f982db4aSGavin Atkinson } 528f982db4aSGavin Atkinson 529f982db4aSGavin Atkinson memset(&gl, 0, sizeof(gl)); 530f982db4aSGavin Atkinson flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_TILDE; 531f982db4aSGavin Atkinson if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { 532cc361f65SGavin Atkinson warnx("Glob pattern `%s' not found", argv[i]); 533f982db4aSGavin Atkinson globfree(&gl); 534f982db4aSGavin Atkinson continue; 535f982db4aSGavin Atkinson } 536f982db4aSGavin Atkinson for (cpp = gl.gl_pathv; cpp && *cpp != NULL && connected; 537f982db4aSGavin Atkinson cpp++) { 538f982db4aSGavin Atkinson if (mflag && confirm(argv[0], *cpp)) { 539f982db4aSGavin Atkinson char buf[MAXPATHLEN]; 540f982db4aSGavin Atkinson tp = *cpp; 541f982db4aSGavin Atkinson tp = doprocess(buf, sizeof(buf), *cpp, 542f982db4aSGavin Atkinson 0, ntflag, mapflag); 543f982db4aSGavin Atkinson sendrequest((sunique) ? "STOU" : "STOR", 544f982db4aSGavin Atkinson *cpp, tp, *cpp != tp || !interactive); 545f982db4aSGavin Atkinson if (!mflag && fromatty) { 546f982db4aSGavin Atkinson ointer = interactive; 547f982db4aSGavin Atkinson interactive = 1; 548cc361f65SGavin Atkinson if (confirm(argv[0], NULL)) { 549f982db4aSGavin Atkinson mflag++; 550f982db4aSGavin Atkinson } 551f982db4aSGavin Atkinson interactive = ointer; 552f982db4aSGavin Atkinson } 553f982db4aSGavin Atkinson } 554f982db4aSGavin Atkinson } 555f982db4aSGavin Atkinson globfree(&gl); 556f982db4aSGavin Atkinson } 557f982db4aSGavin Atkinson cleanupmput: 558f982db4aSGavin Atkinson (void)xsignal(SIGINT, oldintr); 559f982db4aSGavin Atkinson mflag = 0; 560f982db4aSGavin Atkinson } 561f982db4aSGavin Atkinson 562f982db4aSGavin Atkinson void 563f982db4aSGavin Atkinson reget(int argc, char *argv[]) 564f982db4aSGavin Atkinson { 565f982db4aSGavin Atkinson 566f982db4aSGavin Atkinson (void)getit(argc, argv, 1, "r+"); 567f982db4aSGavin Atkinson } 568f982db4aSGavin Atkinson 569f982db4aSGavin Atkinson void 570f982db4aSGavin Atkinson get(int argc, char *argv[]) 571f982db4aSGavin Atkinson { 572f982db4aSGavin Atkinson 573f982db4aSGavin Atkinson (void)getit(argc, argv, 0, restart_point ? "r+" : "w" ); 574f982db4aSGavin Atkinson } 575f982db4aSGavin Atkinson 576f982db4aSGavin Atkinson /* 577f982db4aSGavin Atkinson * Receive one file. 578f982db4aSGavin Atkinson * If restartit is 1, restart the xfer always. 579f982db4aSGavin Atkinson * If restartit is -1, restart the xfer only if the remote file is newer. 580f982db4aSGavin Atkinson */ 581f982db4aSGavin Atkinson int 582cc361f65SGavin Atkinson getit(int argc, char *argv[], int restartit, const char *gmode) 583f982db4aSGavin Atkinson { 584f982db4aSGavin Atkinson int loc, rval; 585f982db4aSGavin Atkinson char *remfile, *olocfile; 586f982db4aSGavin Atkinson const char *locfile; 587f982db4aSGavin Atkinson char buf[MAXPATHLEN]; 588f982db4aSGavin Atkinson 589f982db4aSGavin Atkinson loc = rval = 0; 590f982db4aSGavin Atkinson if (argc == 2) { 591f982db4aSGavin Atkinson argc++; 592f982db4aSGavin Atkinson argv[2] = argv[1]; 593f982db4aSGavin Atkinson loc++; 594f982db4aSGavin Atkinson } 595f982db4aSGavin Atkinson if (argc == 0 || (argc == 1 && !another(&argc, &argv, "remote-file"))) 596f982db4aSGavin Atkinson goto usage; 597f982db4aSGavin Atkinson if ((argc < 3 && !another(&argc, &argv, "local-file")) || argc > 3) { 598f982db4aSGavin Atkinson usage: 599cc361f65SGavin Atkinson UPRINTF("usage: %s remote-file [local-file]\n", argv[0]); 600f982db4aSGavin Atkinson code = -1; 601f982db4aSGavin Atkinson return (0); 602f982db4aSGavin Atkinson } 603f982db4aSGavin Atkinson remfile = argv[1]; 604f982db4aSGavin Atkinson if ((olocfile = globulize(argv[2])) == NULL) { 605f982db4aSGavin Atkinson code = -1; 606f982db4aSGavin Atkinson return (0); 607f982db4aSGavin Atkinson } 608f982db4aSGavin Atkinson locfile = doprocess(buf, sizeof(buf), olocfile, 609f982db4aSGavin Atkinson loc && mcase, loc && ntflag, loc && mapflag); 610f982db4aSGavin Atkinson if (restartit) { 611f982db4aSGavin Atkinson struct stat stbuf; 612f982db4aSGavin Atkinson int ret; 613f982db4aSGavin Atkinson 614f982db4aSGavin Atkinson if (! features[FEAT_REST_STREAM]) { 615f982db4aSGavin Atkinson fprintf(ttyout, 616f982db4aSGavin Atkinson "Restart is not supported by the remote server.\n"); 617f982db4aSGavin Atkinson return (0); 618f982db4aSGavin Atkinson } 619f982db4aSGavin Atkinson ret = stat(locfile, &stbuf); 620f982db4aSGavin Atkinson if (restartit == 1) { 621f982db4aSGavin Atkinson if (ret < 0) { 622cc361f65SGavin Atkinson warn("Can't stat `%s'", locfile); 623f982db4aSGavin Atkinson goto freegetit; 624f982db4aSGavin Atkinson } 625f982db4aSGavin Atkinson restart_point = stbuf.st_size; 626f982db4aSGavin Atkinson } else { 627f982db4aSGavin Atkinson if (ret == 0) { 628f982db4aSGavin Atkinson time_t mtime; 629f982db4aSGavin Atkinson 630f982db4aSGavin Atkinson mtime = remotemodtime(argv[1], 0); 631f982db4aSGavin Atkinson if (mtime == -1) 632f982db4aSGavin Atkinson goto freegetit; 633f982db4aSGavin Atkinson if (stbuf.st_mtime >= mtime) { 634f982db4aSGavin Atkinson rval = 1; 635f982db4aSGavin Atkinson goto freegetit; 636f982db4aSGavin Atkinson } 637f982db4aSGavin Atkinson } 638f982db4aSGavin Atkinson } 639f982db4aSGavin Atkinson } 640f982db4aSGavin Atkinson 641cc361f65SGavin Atkinson recvrequest("RETR", locfile, remfile, gmode, 642f982db4aSGavin Atkinson remfile != argv[1] || locfile != argv[2], loc); 643f982db4aSGavin Atkinson restart_point = 0; 644f982db4aSGavin Atkinson freegetit: 645f982db4aSGavin Atkinson (void)free(olocfile); 646f982db4aSGavin Atkinson return (rval); 647f982db4aSGavin Atkinson } 648f982db4aSGavin Atkinson 649f982db4aSGavin Atkinson /* ARGSUSED */ 650cc361f65SGavin Atkinson static void 651f982db4aSGavin Atkinson mintr(int signo) 652f982db4aSGavin Atkinson { 653f982db4aSGavin Atkinson 654f982db4aSGavin Atkinson alarmtimer(0); 655f982db4aSGavin Atkinson if (fromatty) 656f982db4aSGavin Atkinson write(fileno(ttyout), "\n", 1); 657f982db4aSGavin Atkinson siglongjmp(jabort, 1); 658f982db4aSGavin Atkinson } 659f982db4aSGavin Atkinson 660cc361f65SGavin Atkinson static void 661cc361f65SGavin Atkinson mabort(const char *cmd) 662f982db4aSGavin Atkinson { 663f982db4aSGavin Atkinson int ointer, oconf; 664f982db4aSGavin Atkinson 665f982db4aSGavin Atkinson if (mflag && fromatty) { 666f982db4aSGavin Atkinson ointer = interactive; 667f982db4aSGavin Atkinson oconf = confirmrest; 668f982db4aSGavin Atkinson interactive = 1; 669f982db4aSGavin Atkinson confirmrest = 0; 670cc361f65SGavin Atkinson if (confirm(cmd, NULL)) { 671f982db4aSGavin Atkinson interactive = ointer; 672f982db4aSGavin Atkinson confirmrest = oconf; 673f982db4aSGavin Atkinson return; 674f982db4aSGavin Atkinson } 675f982db4aSGavin Atkinson interactive = ointer; 676f982db4aSGavin Atkinson confirmrest = oconf; 677f982db4aSGavin Atkinson } 678f982db4aSGavin Atkinson mflag = 0; 679f982db4aSGavin Atkinson } 680f982db4aSGavin Atkinson 681f982db4aSGavin Atkinson /* 682f982db4aSGavin Atkinson * Get multiple files. 683f982db4aSGavin Atkinson */ 684f982db4aSGavin Atkinson void 685f982db4aSGavin Atkinson mget(int argc, char *argv[]) 686f982db4aSGavin Atkinson { 687f982db4aSGavin Atkinson sigfunc oldintr; 688f982db4aSGavin Atkinson int ointer; 689f982db4aSGavin Atkinson char *cp; 690f982db4aSGavin Atkinson const char *tp; 691cc361f65SGavin Atkinson int volatile restartit; 692f982db4aSGavin Atkinson 693f982db4aSGavin Atkinson if (argc == 0 || 694f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "remote-files"))) { 695cc361f65SGavin Atkinson UPRINTF("usage: %s remote-files\n", argv[0]); 696f982db4aSGavin Atkinson code = -1; 697f982db4aSGavin Atkinson return; 698f982db4aSGavin Atkinson } 699f982db4aSGavin Atkinson mflag = 1; 700f982db4aSGavin Atkinson restart_point = 0; 701f982db4aSGavin Atkinson restartit = 0; 702f982db4aSGavin Atkinson if (strcmp(argv[0], "mreget") == 0) { 703f982db4aSGavin Atkinson if (! features[FEAT_REST_STREAM]) { 704f982db4aSGavin Atkinson fprintf(ttyout, 705f982db4aSGavin Atkinson "Restart is not supported by the remote server.\n"); 706f982db4aSGavin Atkinson return; 707f982db4aSGavin Atkinson } 708f982db4aSGavin Atkinson restartit = 1; 709f982db4aSGavin Atkinson } 710f982db4aSGavin Atkinson oldintr = xsignal(SIGINT, mintr); 711f982db4aSGavin Atkinson if (sigsetjmp(jabort, 1)) 712cc361f65SGavin Atkinson mabort(argv[0]); 713f982db4aSGavin Atkinson while ((cp = remglob(argv, proxy, NULL)) != NULL) { 714f982db4aSGavin Atkinson char buf[MAXPATHLEN]; 715f982db4aSGavin Atkinson if (*cp == '\0' || !connected) { 716f982db4aSGavin Atkinson mflag = 0; 717f982db4aSGavin Atkinson continue; 718f982db4aSGavin Atkinson } 719f982db4aSGavin Atkinson if (! mflag) 720f982db4aSGavin Atkinson continue; 721f982db4aSGavin Atkinson if (! fileindir(cp, localcwd)) { 722f982db4aSGavin Atkinson fprintf(ttyout, "Skipping non-relative filename `%s'\n", 723f982db4aSGavin Atkinson cp); 724f982db4aSGavin Atkinson continue; 725f982db4aSGavin Atkinson } 726f982db4aSGavin Atkinson if (!confirm(argv[0], cp)) 727f982db4aSGavin Atkinson continue; 728f982db4aSGavin Atkinson tp = doprocess(buf, sizeof(buf), cp, mcase, ntflag, mapflag); 729f982db4aSGavin Atkinson if (restartit) { 730f982db4aSGavin Atkinson struct stat stbuf; 731f982db4aSGavin Atkinson 732f982db4aSGavin Atkinson if (stat(tp, &stbuf) == 0) 733f982db4aSGavin Atkinson restart_point = stbuf.st_size; 734f982db4aSGavin Atkinson else 735cc361f65SGavin Atkinson warn("Can't stat `%s'", tp); 736f982db4aSGavin Atkinson } 737f982db4aSGavin Atkinson recvrequest("RETR", tp, cp, restart_point ? "r+" : "w", 738f982db4aSGavin Atkinson tp != cp || !interactive, 1); 739f982db4aSGavin Atkinson restart_point = 0; 740f982db4aSGavin Atkinson if (!mflag && fromatty) { 741f982db4aSGavin Atkinson ointer = interactive; 742f982db4aSGavin Atkinson interactive = 1; 743cc361f65SGavin Atkinson if (confirm(argv[0], NULL)) 744f982db4aSGavin Atkinson mflag++; 745f982db4aSGavin Atkinson interactive = ointer; 746f982db4aSGavin Atkinson } 747f982db4aSGavin Atkinson } 748f982db4aSGavin Atkinson (void)xsignal(SIGINT, oldintr); 749f982db4aSGavin Atkinson mflag = 0; 750f982db4aSGavin Atkinson } 751f982db4aSGavin Atkinson 752f982db4aSGavin Atkinson /* 753f982db4aSGavin Atkinson * Read list of filenames from a local file and get those 754f982db4aSGavin Atkinson */ 755f982db4aSGavin Atkinson void 756f982db4aSGavin Atkinson fget(int argc, char *argv[]) 757f982db4aSGavin Atkinson { 758cc361f65SGavin Atkinson const char *gmode; 759f982db4aSGavin Atkinson FILE *fp; 760cc361f65SGavin Atkinson char buf[MAXPATHLEN], cmdbuf[MAX_C_NAME]; 761f982db4aSGavin Atkinson 762f982db4aSGavin Atkinson if (argc != 2) { 763cc361f65SGavin Atkinson UPRINTF("usage: %s localfile\n", argv[0]); 764f982db4aSGavin Atkinson code = -1; 765f982db4aSGavin Atkinson return; 766f982db4aSGavin Atkinson } 767f982db4aSGavin Atkinson 768f982db4aSGavin Atkinson fp = fopen(argv[1], "r"); 769f982db4aSGavin Atkinson if (fp == NULL) { 770cc361f65SGavin Atkinson fprintf(ttyout, "Can't open source file %s\n", argv[1]); 771f982db4aSGavin Atkinson code = -1; 772f982db4aSGavin Atkinson return; 773f982db4aSGavin Atkinson } 774f982db4aSGavin Atkinson 775cc361f65SGavin Atkinson (void)strlcpy(cmdbuf, "get", sizeof(cmdbuf)); 776cc361f65SGavin Atkinson argv[0] = cmdbuf; 777cc361f65SGavin Atkinson gmode = restart_point ? "r+" : "w"; 778f982db4aSGavin Atkinson 779cc361f65SGavin Atkinson while (get_line(fp, buf, sizeof(buf), NULL) >= 0) { 780f982db4aSGavin Atkinson if (buf[0] == '\0') 781f982db4aSGavin Atkinson continue; 782f982db4aSGavin Atkinson argv[1] = buf; 783cc361f65SGavin Atkinson (void)getit(argc, argv, 0, gmode); 784f982db4aSGavin Atkinson } 785f982db4aSGavin Atkinson fclose(fp); 786f982db4aSGavin Atkinson } 787f982db4aSGavin Atkinson 788cc361f65SGavin Atkinson const char * 789cc361f65SGavin Atkinson onoff(int val) 790f982db4aSGavin Atkinson { 791f982db4aSGavin Atkinson 792cc361f65SGavin Atkinson return (val ? "on" : "off"); 793f982db4aSGavin Atkinson } 794f982db4aSGavin Atkinson 795f982db4aSGavin Atkinson /* 796f982db4aSGavin Atkinson * Show status. 797f982db4aSGavin Atkinson */ 798f982db4aSGavin Atkinson /*ARGSUSED*/ 799f982db4aSGavin Atkinson void 800f982db4aSGavin Atkinson status(int argc, char *argv[]) 801f982db4aSGavin Atkinson { 802f982db4aSGavin Atkinson 803f982db4aSGavin Atkinson if (argc == 0) { 804cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 805f982db4aSGavin Atkinson code = -1; 806f982db4aSGavin Atkinson return; 807f982db4aSGavin Atkinson } 808f982db4aSGavin Atkinson #ifndef NO_STATUS 809f982db4aSGavin Atkinson if (connected) 810f982db4aSGavin Atkinson fprintf(ttyout, "Connected %sto %s.\n", 811f982db4aSGavin Atkinson connected == -1 ? "and logged in" : "", hostname); 812f982db4aSGavin Atkinson else 813f982db4aSGavin Atkinson fputs("Not connected.\n", ttyout); 814f982db4aSGavin Atkinson if (!proxy) { 815f982db4aSGavin Atkinson pswitch(1); 816f982db4aSGavin Atkinson if (connected) { 817f982db4aSGavin Atkinson fprintf(ttyout, "Connected for proxy commands to %s.\n", 818f982db4aSGavin Atkinson hostname); 819f982db4aSGavin Atkinson } 820f982db4aSGavin Atkinson else { 821f982db4aSGavin Atkinson fputs("No proxy connection.\n", ttyout); 822f982db4aSGavin Atkinson } 823f982db4aSGavin Atkinson pswitch(0); 824f982db4aSGavin Atkinson } 825f982db4aSGavin Atkinson fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", onoff(gatemode), 826f982db4aSGavin Atkinson *gateserver ? gateserver : "(none)", gateport); 827f982db4aSGavin Atkinson fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 828f982db4aSGavin Atkinson onoff(passivemode), onoff(activefallback)); 829f982db4aSGavin Atkinson fprintf(ttyout, "Mode: %s; Type: %s; Form: %s; Structure: %s.\n", 830f982db4aSGavin Atkinson modename, typename, formname, structname); 831f982db4aSGavin Atkinson fprintf(ttyout, "Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s.\n", 832f982db4aSGavin Atkinson onoff(verbose), onoff(bell), onoff(interactive), onoff(doglob)); 833f982db4aSGavin Atkinson fprintf(ttyout, "Store unique: %s; Receive unique: %s.\n", 834f982db4aSGavin Atkinson onoff(sunique), onoff(runique)); 835f982db4aSGavin Atkinson fprintf(ttyout, "Preserve modification times: %s.\n", onoff(preserve)); 836f982db4aSGavin Atkinson fprintf(ttyout, "Case: %s; CR stripping: %s.\n", onoff(mcase), 837f982db4aSGavin Atkinson onoff(crflag)); 838f982db4aSGavin Atkinson if (ntflag) { 839f982db4aSGavin Atkinson fprintf(ttyout, "Ntrans: (in) %s (out) %s\n", ntin, ntout); 840f982db4aSGavin Atkinson } 841f982db4aSGavin Atkinson else { 842f982db4aSGavin Atkinson fputs("Ntrans: off.\n", ttyout); 843f982db4aSGavin Atkinson } 844f982db4aSGavin Atkinson if (mapflag) { 845f982db4aSGavin Atkinson fprintf(ttyout, "Nmap: (in) %s (out) %s\n", mapin, mapout); 846f982db4aSGavin Atkinson } 847f982db4aSGavin Atkinson else { 848f982db4aSGavin Atkinson fputs("Nmap: off.\n", ttyout); 849f982db4aSGavin Atkinson } 850f982db4aSGavin Atkinson fprintf(ttyout, 851f982db4aSGavin Atkinson "Hash mark printing: %s; Mark count: %d; Progress bar: %s.\n", 852f982db4aSGavin Atkinson onoff(hash), mark, onoff(progress)); 853f982db4aSGavin Atkinson fprintf(ttyout, 854f982db4aSGavin Atkinson "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 855f982db4aSGavin Atkinson onoff(rate_get), rate_get, rate_get_incr); 856f982db4aSGavin Atkinson fprintf(ttyout, 857f982db4aSGavin Atkinson "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 858f982db4aSGavin Atkinson onoff(rate_put), rate_put, rate_put_incr); 859f982db4aSGavin Atkinson fprintf(ttyout, 860f982db4aSGavin Atkinson "Socket buffer sizes: send %d, receive %d.\n", 861f982db4aSGavin Atkinson sndbuf_size, rcvbuf_size); 862f982db4aSGavin Atkinson fprintf(ttyout, "Use of PORT cmds: %s.\n", onoff(sendport)); 863f982db4aSGavin Atkinson fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv4: %s%s.\n", onoff(epsv4), 864f982db4aSGavin Atkinson epsv4bad ? " (disabled for this connection)" : ""); 865cc361f65SGavin Atkinson fprintf(ttyout, "Use of EPSV/EPRT cmds for IPv6: %s%s.\n", onoff(epsv6), 866cc361f65SGavin Atkinson epsv6bad ? " (disabled for this connection)" : ""); 867f982db4aSGavin Atkinson fprintf(ttyout, "Command line editing: %s.\n", 868f982db4aSGavin Atkinson #ifdef NO_EDITCOMPLETE 869f982db4aSGavin Atkinson "support not compiled in" 870f982db4aSGavin Atkinson #else /* !def NO_EDITCOMPLETE */ 871f982db4aSGavin Atkinson onoff(editing) 872f982db4aSGavin Atkinson #endif /* !def NO_EDITCOMPLETE */ 873f982db4aSGavin Atkinson ); 874f982db4aSGavin Atkinson if (macnum > 0) { 875f982db4aSGavin Atkinson int i; 876f982db4aSGavin Atkinson 877f982db4aSGavin Atkinson fputs("Macros:\n", ttyout); 878f982db4aSGavin Atkinson for (i=0; i<macnum; i++) { 879f982db4aSGavin Atkinson fprintf(ttyout, "\t%s\n", macros[i].mac_name); 880f982db4aSGavin Atkinson } 881f982db4aSGavin Atkinson } 882f982db4aSGavin Atkinson #endif /* !def NO_STATUS */ 883f982db4aSGavin Atkinson fprintf(ttyout, "Version: %s %s\n", FTP_PRODUCT, FTP_VERSION); 884f982db4aSGavin Atkinson code = 0; 885f982db4aSGavin Atkinson } 886f982db4aSGavin Atkinson 887f982db4aSGavin Atkinson /* 888f982db4aSGavin Atkinson * Toggle a variable 889f982db4aSGavin Atkinson */ 890f982db4aSGavin Atkinson int 891f982db4aSGavin Atkinson togglevar(int argc, char *argv[], int *var, const char *mesg) 892f982db4aSGavin Atkinson { 893f982db4aSGavin Atkinson if (argc == 1) { 894f982db4aSGavin Atkinson *var = !*var; 895f982db4aSGavin Atkinson } else if (argc == 2 && strcasecmp(argv[1], "on") == 0) { 896f982db4aSGavin Atkinson *var = 1; 897f982db4aSGavin Atkinson } else if (argc == 2 && strcasecmp(argv[1], "off") == 0) { 898f982db4aSGavin Atkinson *var = 0; 899f982db4aSGavin Atkinson } else { 900cc361f65SGavin Atkinson UPRINTF("usage: %s [ on | off ]\n", argv[0]); 901f982db4aSGavin Atkinson return (-1); 902f982db4aSGavin Atkinson } 903f982db4aSGavin Atkinson if (mesg) 904f982db4aSGavin Atkinson fprintf(ttyout, "%s %s.\n", mesg, onoff(*var)); 905f982db4aSGavin Atkinson return (*var); 906f982db4aSGavin Atkinson } 907f982db4aSGavin Atkinson 908f982db4aSGavin Atkinson /* 909f982db4aSGavin Atkinson * Set beep on cmd completed mode. 910f982db4aSGavin Atkinson */ 911f982db4aSGavin Atkinson /*VARARGS*/ 912f982db4aSGavin Atkinson void 913f982db4aSGavin Atkinson setbell(int argc, char *argv[]) 914f982db4aSGavin Atkinson { 915f982db4aSGavin Atkinson 916f982db4aSGavin Atkinson code = togglevar(argc, argv, &bell, "Bell mode"); 917f982db4aSGavin Atkinson } 918f982db4aSGavin Atkinson 919f982db4aSGavin Atkinson /* 920f982db4aSGavin Atkinson * Set command line editing 921f982db4aSGavin Atkinson */ 922f982db4aSGavin Atkinson /*VARARGS*/ 923f982db4aSGavin Atkinson void 924f982db4aSGavin Atkinson setedit(int argc, char *argv[]) 925f982db4aSGavin Atkinson { 926f982db4aSGavin Atkinson 927f982db4aSGavin Atkinson #ifdef NO_EDITCOMPLETE 928f982db4aSGavin Atkinson if (argc == 0) { 929cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 930f982db4aSGavin Atkinson code = -1; 931f982db4aSGavin Atkinson return; 932f982db4aSGavin Atkinson } 933f982db4aSGavin Atkinson if (verbose) 934f982db4aSGavin Atkinson fputs("Editing support not compiled in; ignoring command.\n", 935f982db4aSGavin Atkinson ttyout); 936f982db4aSGavin Atkinson #else /* !def NO_EDITCOMPLETE */ 937f982db4aSGavin Atkinson code = togglevar(argc, argv, &editing, "Editing mode"); 938f982db4aSGavin Atkinson controlediting(); 939f982db4aSGavin Atkinson #endif /* !def NO_EDITCOMPLETE */ 940f982db4aSGavin Atkinson } 941f982db4aSGavin Atkinson 942f982db4aSGavin Atkinson /* 943f982db4aSGavin Atkinson * Turn on packet tracing. 944f982db4aSGavin Atkinson */ 945f982db4aSGavin Atkinson /*VARARGS*/ 946f982db4aSGavin Atkinson void 947f982db4aSGavin Atkinson settrace(int argc, char *argv[]) 948f982db4aSGavin Atkinson { 949f982db4aSGavin Atkinson 950f982db4aSGavin Atkinson code = togglevar(argc, argv, &trace, "Packet tracing"); 951f982db4aSGavin Atkinson } 952f982db4aSGavin Atkinson 953f982db4aSGavin Atkinson /* 954f982db4aSGavin Atkinson * Toggle hash mark printing during transfers, or set hash mark bytecount. 955f982db4aSGavin Atkinson */ 956f982db4aSGavin Atkinson /*VARARGS*/ 957f982db4aSGavin Atkinson void 958f982db4aSGavin Atkinson sethash(int argc, char *argv[]) 959f982db4aSGavin Atkinson { 960f982db4aSGavin Atkinson if (argc == 1) 961f982db4aSGavin Atkinson hash = !hash; 962f982db4aSGavin Atkinson else if (argc != 2) { 963cc361f65SGavin Atkinson UPRINTF("usage: %s [ on | off | bytecount ]\n", 964f982db4aSGavin Atkinson argv[0]); 965f982db4aSGavin Atkinson code = -1; 966f982db4aSGavin Atkinson return; 967f982db4aSGavin Atkinson } else if (strcasecmp(argv[1], "on") == 0) 968f982db4aSGavin Atkinson hash = 1; 969f982db4aSGavin Atkinson else if (strcasecmp(argv[1], "off") == 0) 970f982db4aSGavin Atkinson hash = 0; 971f982db4aSGavin Atkinson else { 972f982db4aSGavin Atkinson int nmark; 973f982db4aSGavin Atkinson 974f982db4aSGavin Atkinson nmark = strsuftoi(argv[1]); 975f982db4aSGavin Atkinson if (nmark < 1) { 976f982db4aSGavin Atkinson fprintf(ttyout, "mark: bad bytecount value `%s'.\n", 977f982db4aSGavin Atkinson argv[1]); 978f982db4aSGavin Atkinson code = -1; 979f982db4aSGavin Atkinson return; 980f982db4aSGavin Atkinson } 981f982db4aSGavin Atkinson mark = nmark; 982f982db4aSGavin Atkinson hash = 1; 983f982db4aSGavin Atkinson } 984f982db4aSGavin Atkinson fprintf(ttyout, "Hash mark printing %s", onoff(hash)); 985f982db4aSGavin Atkinson if (hash) 986f982db4aSGavin Atkinson fprintf(ttyout, " (%d bytes/hash mark)", mark); 987f982db4aSGavin Atkinson fputs(".\n", ttyout); 988f982db4aSGavin Atkinson if (hash) 989f982db4aSGavin Atkinson progress = 0; 990f982db4aSGavin Atkinson code = hash; 991f982db4aSGavin Atkinson } 992f982db4aSGavin Atkinson 993f982db4aSGavin Atkinson /* 994f982db4aSGavin Atkinson * Turn on printing of server echo's. 995f982db4aSGavin Atkinson */ 996f982db4aSGavin Atkinson /*VARARGS*/ 997f982db4aSGavin Atkinson void 998f982db4aSGavin Atkinson setverbose(int argc, char *argv[]) 999f982db4aSGavin Atkinson { 1000f982db4aSGavin Atkinson 1001f982db4aSGavin Atkinson code = togglevar(argc, argv, &verbose, "Verbose mode"); 1002f982db4aSGavin Atkinson } 1003f982db4aSGavin Atkinson 1004f982db4aSGavin Atkinson /* 1005f982db4aSGavin Atkinson * Toggle PORT/LPRT cmd use before each data connection. 1006f982db4aSGavin Atkinson */ 1007f982db4aSGavin Atkinson /*VARARGS*/ 1008f982db4aSGavin Atkinson void 1009f982db4aSGavin Atkinson setport(int argc, char *argv[]) 1010f982db4aSGavin Atkinson { 1011f982db4aSGavin Atkinson 1012f982db4aSGavin Atkinson code = togglevar(argc, argv, &sendport, "Use of PORT/LPRT cmds"); 1013f982db4aSGavin Atkinson } 1014f982db4aSGavin Atkinson 1015f982db4aSGavin Atkinson /* 1016f982db4aSGavin Atkinson * Toggle transfer progress bar. 1017f982db4aSGavin Atkinson */ 1018f982db4aSGavin Atkinson /*VARARGS*/ 1019f982db4aSGavin Atkinson void 1020f982db4aSGavin Atkinson setprogress(int argc, char *argv[]) 1021f982db4aSGavin Atkinson { 1022f982db4aSGavin Atkinson 1023f982db4aSGavin Atkinson code = togglevar(argc, argv, &progress, "Progress bar"); 1024f982db4aSGavin Atkinson if (progress) 1025f982db4aSGavin Atkinson hash = 0; 1026f982db4aSGavin Atkinson } 1027f982db4aSGavin Atkinson 1028f982db4aSGavin Atkinson /* 1029f982db4aSGavin Atkinson * Turn on interactive prompting during mget, mput, and mdelete. 1030f982db4aSGavin Atkinson */ 1031f982db4aSGavin Atkinson /*VARARGS*/ 1032f982db4aSGavin Atkinson void 1033f982db4aSGavin Atkinson setprompt(int argc, char *argv[]) 1034f982db4aSGavin Atkinson { 1035f982db4aSGavin Atkinson 1036f982db4aSGavin Atkinson code = togglevar(argc, argv, &interactive, "Interactive mode"); 1037f982db4aSGavin Atkinson } 1038f982db4aSGavin Atkinson 1039f982db4aSGavin Atkinson /* 1040f982db4aSGavin Atkinson * Toggle gate-ftp mode, or set gate-ftp server 1041f982db4aSGavin Atkinson */ 1042f982db4aSGavin Atkinson /*VARARGS*/ 1043f982db4aSGavin Atkinson void 1044f982db4aSGavin Atkinson setgate(int argc, char *argv[]) 1045f982db4aSGavin Atkinson { 1046f982db4aSGavin Atkinson static char gsbuf[MAXHOSTNAMELEN]; 1047f982db4aSGavin Atkinson 1048f982db4aSGavin Atkinson if (argc == 0 || argc > 3) { 1049cc361f65SGavin Atkinson UPRINTF( 1050f982db4aSGavin Atkinson "usage: %s [ on | off | gateserver [port] ]\n", argv[0]); 1051f982db4aSGavin Atkinson code = -1; 1052f982db4aSGavin Atkinson return; 1053f982db4aSGavin Atkinson } else if (argc < 2) { 1054f982db4aSGavin Atkinson gatemode = !gatemode; 1055f982db4aSGavin Atkinson } else { 1056f982db4aSGavin Atkinson if (argc == 2 && strcasecmp(argv[1], "on") == 0) 1057f982db4aSGavin Atkinson gatemode = 1; 1058f982db4aSGavin Atkinson else if (argc == 2 && strcasecmp(argv[1], "off") == 0) 1059f982db4aSGavin Atkinson gatemode = 0; 1060f982db4aSGavin Atkinson else { 1061f982db4aSGavin Atkinson if (argc == 3) 1062cc361f65SGavin Atkinson gateport = ftp_strdup(argv[2]); 1063f982db4aSGavin Atkinson (void)strlcpy(gsbuf, argv[1], sizeof(gsbuf)); 1064f982db4aSGavin Atkinson gateserver = gsbuf; 1065f982db4aSGavin Atkinson gatemode = 1; 1066f982db4aSGavin Atkinson } 1067f982db4aSGavin Atkinson } 1068f982db4aSGavin Atkinson if (gatemode && (gateserver == NULL || *gateserver == '\0')) { 1069f982db4aSGavin Atkinson fprintf(ttyout, 1070f982db4aSGavin Atkinson "Disabling gate-ftp mode - no gate-ftp server defined.\n"); 1071f982db4aSGavin Atkinson gatemode = 0; 1072f982db4aSGavin Atkinson } else { 1073f982db4aSGavin Atkinson fprintf(ttyout, "Gate ftp: %s, server %s, port %s.\n", 1074f982db4aSGavin Atkinson onoff(gatemode), *gateserver ? gateserver : "(none)", 1075f982db4aSGavin Atkinson gateport); 1076f982db4aSGavin Atkinson } 1077f982db4aSGavin Atkinson code = gatemode; 1078f982db4aSGavin Atkinson } 1079f982db4aSGavin Atkinson 1080f982db4aSGavin Atkinson /* 1081f982db4aSGavin Atkinson * Toggle metacharacter interpretation on local file names. 1082f982db4aSGavin Atkinson */ 1083f982db4aSGavin Atkinson /*VARARGS*/ 1084f982db4aSGavin Atkinson void 1085f982db4aSGavin Atkinson setglob(int argc, char *argv[]) 1086f982db4aSGavin Atkinson { 1087f982db4aSGavin Atkinson 1088f982db4aSGavin Atkinson code = togglevar(argc, argv, &doglob, "Globbing"); 1089f982db4aSGavin Atkinson } 1090f982db4aSGavin Atkinson 1091f982db4aSGavin Atkinson /* 1092f982db4aSGavin Atkinson * Toggle preserving modification times on retrieved files. 1093f982db4aSGavin Atkinson */ 1094f982db4aSGavin Atkinson /*VARARGS*/ 1095f982db4aSGavin Atkinson void 1096f982db4aSGavin Atkinson setpreserve(int argc, char *argv[]) 1097f982db4aSGavin Atkinson { 1098f982db4aSGavin Atkinson 1099f982db4aSGavin Atkinson code = togglevar(argc, argv, &preserve, "Preserve modification times"); 1100f982db4aSGavin Atkinson } 1101f982db4aSGavin Atkinson 1102f982db4aSGavin Atkinson /* 1103f982db4aSGavin Atkinson * Set debugging mode on/off and/or set level of debugging. 1104f982db4aSGavin Atkinson */ 1105f982db4aSGavin Atkinson /*VARARGS*/ 1106f982db4aSGavin Atkinson void 1107f982db4aSGavin Atkinson setdebug(int argc, char *argv[]) 1108f982db4aSGavin Atkinson { 1109f982db4aSGavin Atkinson if (argc == 0 || argc > 2) { 1110cc361f65SGavin Atkinson UPRINTF("usage: %s [ on | off | debuglevel ]\n", argv[0]); 1111f982db4aSGavin Atkinson code = -1; 1112f982db4aSGavin Atkinson return; 1113f982db4aSGavin Atkinson } else if (argc == 2) { 1114f982db4aSGavin Atkinson if (strcasecmp(argv[1], "on") == 0) 1115cc361f65SGavin Atkinson ftp_debug = 1; 1116f982db4aSGavin Atkinson else if (strcasecmp(argv[1], "off") == 0) 1117cc361f65SGavin Atkinson ftp_debug = 0; 1118f982db4aSGavin Atkinson else { 1119f982db4aSGavin Atkinson int val; 1120f982db4aSGavin Atkinson 1121f982db4aSGavin Atkinson val = strsuftoi(argv[1]); 1122f982db4aSGavin Atkinson if (val < 0) { 1123f982db4aSGavin Atkinson fprintf(ttyout, "%s: bad debugging value.\n", 1124f982db4aSGavin Atkinson argv[1]); 1125f982db4aSGavin Atkinson code = -1; 1126f982db4aSGavin Atkinson return; 1127f982db4aSGavin Atkinson } 1128cc361f65SGavin Atkinson ftp_debug = val; 1129f982db4aSGavin Atkinson } 1130f982db4aSGavin Atkinson } else 1131cc361f65SGavin Atkinson ftp_debug = !ftp_debug; 1132cc361f65SGavin Atkinson if (ftp_debug) 1133f982db4aSGavin Atkinson options |= SO_DEBUG; 1134f982db4aSGavin Atkinson else 1135f982db4aSGavin Atkinson options &= ~SO_DEBUG; 1136cc361f65SGavin Atkinson fprintf(ttyout, "Debugging %s (ftp_debug=%d).\n", onoff(ftp_debug), ftp_debug); 1137cc361f65SGavin Atkinson code = ftp_debug > 0; 1138f982db4aSGavin Atkinson } 1139f982db4aSGavin Atkinson 1140f982db4aSGavin Atkinson /* 1141f982db4aSGavin Atkinson * Set current working directory on remote machine. 1142f982db4aSGavin Atkinson */ 1143f982db4aSGavin Atkinson void 1144f982db4aSGavin Atkinson cd(int argc, char *argv[]) 1145f982db4aSGavin Atkinson { 1146f982db4aSGavin Atkinson int r; 1147f982db4aSGavin Atkinson 1148f982db4aSGavin Atkinson if (argc == 0 || argc > 2 || 1149f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "remote-directory"))) { 1150cc361f65SGavin Atkinson UPRINTF("usage: %s remote-directory\n", argv[0]); 1151f982db4aSGavin Atkinson code = -1; 1152f982db4aSGavin Atkinson return; 1153f982db4aSGavin Atkinson } 1154f982db4aSGavin Atkinson r = command("CWD %s", argv[1]); 1155f982db4aSGavin Atkinson if (r == ERROR && code == 500) { 1156f982db4aSGavin Atkinson if (verbose) 1157f982db4aSGavin Atkinson fputs("CWD command not recognized, trying XCWD.\n", 1158f982db4aSGavin Atkinson ttyout); 1159f982db4aSGavin Atkinson r = command("XCWD %s", argv[1]); 1160f982db4aSGavin Atkinson } 1161f982db4aSGavin Atkinson if (r == COMPLETE) { 1162f982db4aSGavin Atkinson dirchange = 1; 1163f982db4aSGavin Atkinson updateremotecwd(); 1164f982db4aSGavin Atkinson } 1165f982db4aSGavin Atkinson } 1166f982db4aSGavin Atkinson 1167f982db4aSGavin Atkinson /* 1168f982db4aSGavin Atkinson * Set current working directory on local machine. 1169f982db4aSGavin Atkinson */ 1170f982db4aSGavin Atkinson void 1171f982db4aSGavin Atkinson lcd(int argc, char *argv[]) 1172f982db4aSGavin Atkinson { 1173f982db4aSGavin Atkinson char *locdir; 1174f982db4aSGavin Atkinson 1175f982db4aSGavin Atkinson code = -1; 1176f982db4aSGavin Atkinson if (argc == 1) { 1177f982db4aSGavin Atkinson argc++; 1178f982db4aSGavin Atkinson argv[1] = localhome; 1179f982db4aSGavin Atkinson } 1180f982db4aSGavin Atkinson if (argc != 2) { 1181cc361f65SGavin Atkinson UPRINTF("usage: %s [local-directory]\n", argv[0]); 1182f982db4aSGavin Atkinson return; 1183f982db4aSGavin Atkinson } 1184f982db4aSGavin Atkinson if ((locdir = globulize(argv[1])) == NULL) 1185f982db4aSGavin Atkinson return; 1186f982db4aSGavin Atkinson if (chdir(locdir) == -1) 1187cc361f65SGavin Atkinson warn("Can't chdir `%s'", locdir); 1188f982db4aSGavin Atkinson else { 1189f982db4aSGavin Atkinson updatelocalcwd(); 1190f982db4aSGavin Atkinson if (localcwd[0]) { 1191f982db4aSGavin Atkinson fprintf(ttyout, "Local directory now: %s\n", localcwd); 1192f982db4aSGavin Atkinson code = 0; 1193f982db4aSGavin Atkinson } else { 1194f982db4aSGavin Atkinson fprintf(ttyout, "Unable to determine local directory\n"); 1195f982db4aSGavin Atkinson } 1196f982db4aSGavin Atkinson } 1197f982db4aSGavin Atkinson (void)free(locdir); 1198f982db4aSGavin Atkinson } 1199f982db4aSGavin Atkinson 1200f982db4aSGavin Atkinson /* 1201f982db4aSGavin Atkinson * Delete a single file. 1202f982db4aSGavin Atkinson */ 1203f982db4aSGavin Atkinson void 1204f982db4aSGavin Atkinson delete(int argc, char *argv[]) 1205f982db4aSGavin Atkinson { 1206f982db4aSGavin Atkinson 1207f982db4aSGavin Atkinson if (argc == 0 || argc > 2 || 1208f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "remote-file"))) { 1209cc361f65SGavin Atkinson UPRINTF("usage: %s remote-file\n", argv[0]); 1210f982db4aSGavin Atkinson code = -1; 1211f982db4aSGavin Atkinson return; 1212f982db4aSGavin Atkinson } 1213f982db4aSGavin Atkinson if (command("DELE %s", argv[1]) == COMPLETE) 1214f982db4aSGavin Atkinson dirchange = 1; 1215f982db4aSGavin Atkinson } 1216f982db4aSGavin Atkinson 1217f982db4aSGavin Atkinson /* 1218f982db4aSGavin Atkinson * Delete multiple files. 1219f982db4aSGavin Atkinson */ 1220f982db4aSGavin Atkinson void 1221f982db4aSGavin Atkinson mdelete(int argc, char *argv[]) 1222f982db4aSGavin Atkinson { 1223f982db4aSGavin Atkinson sigfunc oldintr; 1224f982db4aSGavin Atkinson int ointer; 1225f982db4aSGavin Atkinson char *cp; 1226f982db4aSGavin Atkinson 1227f982db4aSGavin Atkinson if (argc == 0 || 1228f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "remote-files"))) { 1229cc361f65SGavin Atkinson UPRINTF("usage: %s [remote-files]\n", argv[0]); 1230f982db4aSGavin Atkinson code = -1; 1231f982db4aSGavin Atkinson return; 1232f982db4aSGavin Atkinson } 1233f982db4aSGavin Atkinson mflag = 1; 1234f982db4aSGavin Atkinson oldintr = xsignal(SIGINT, mintr); 1235f982db4aSGavin Atkinson if (sigsetjmp(jabort, 1)) 1236cc361f65SGavin Atkinson mabort(argv[0]); 1237f982db4aSGavin Atkinson while ((cp = remglob(argv, 0, NULL)) != NULL) { 1238f982db4aSGavin Atkinson if (*cp == '\0') { 1239f982db4aSGavin Atkinson mflag = 0; 1240f982db4aSGavin Atkinson continue; 1241f982db4aSGavin Atkinson } 1242f982db4aSGavin Atkinson if (mflag && confirm(argv[0], cp)) { 1243f982db4aSGavin Atkinson if (command("DELE %s", cp) == COMPLETE) 1244f982db4aSGavin Atkinson dirchange = 1; 1245f982db4aSGavin Atkinson if (!mflag && fromatty) { 1246f982db4aSGavin Atkinson ointer = interactive; 1247f982db4aSGavin Atkinson interactive = 1; 1248cc361f65SGavin Atkinson if (confirm(argv[0], NULL)) { 1249f982db4aSGavin Atkinson mflag++; 1250f982db4aSGavin Atkinson } 1251f982db4aSGavin Atkinson interactive = ointer; 1252f982db4aSGavin Atkinson } 1253f982db4aSGavin Atkinson } 1254f982db4aSGavin Atkinson } 1255f982db4aSGavin Atkinson (void)xsignal(SIGINT, oldintr); 1256f982db4aSGavin Atkinson mflag = 0; 1257f982db4aSGavin Atkinson } 1258f982db4aSGavin Atkinson 1259f982db4aSGavin Atkinson /* 1260f982db4aSGavin Atkinson * Rename a remote file. 1261f982db4aSGavin Atkinson */ 1262f982db4aSGavin Atkinson void 1263f982db4aSGavin Atkinson renamefile(int argc, char *argv[]) 1264f982db4aSGavin Atkinson { 1265f982db4aSGavin Atkinson 1266f982db4aSGavin Atkinson if (argc == 0 || (argc == 1 && !another(&argc, &argv, "from-name"))) 1267f982db4aSGavin Atkinson goto usage; 1268f982db4aSGavin Atkinson if ((argc < 3 && !another(&argc, &argv, "to-name")) || argc > 3) { 1269f982db4aSGavin Atkinson usage: 1270cc361f65SGavin Atkinson UPRINTF("usage: %s from-name to-name\n", argv[0]); 1271f982db4aSGavin Atkinson code = -1; 1272f982db4aSGavin Atkinson return; 1273f982db4aSGavin Atkinson } 1274f982db4aSGavin Atkinson if (command("RNFR %s", argv[1]) == CONTINUE && 1275f982db4aSGavin Atkinson command("RNTO %s", argv[2]) == COMPLETE) 1276f982db4aSGavin Atkinson dirchange = 1; 1277f982db4aSGavin Atkinson } 1278f982db4aSGavin Atkinson 1279f982db4aSGavin Atkinson /* 1280f982db4aSGavin Atkinson * Get a directory listing of remote files. 1281f982db4aSGavin Atkinson * Supports being invoked as: 1282f982db4aSGavin Atkinson * cmd runs 1283f982db4aSGavin Atkinson * --- ---- 1284f982db4aSGavin Atkinson * dir, ls LIST 1285f982db4aSGavin Atkinson * mlsd MLSD 1286f982db4aSGavin Atkinson * nlist NLST 1287f982db4aSGavin Atkinson * pdir, pls LIST |$PAGER 1288cc361f65SGavin Atkinson * pmlsd MLSD |$PAGER 1289f982db4aSGavin Atkinson */ 1290f982db4aSGavin Atkinson void 1291f982db4aSGavin Atkinson ls(int argc, char *argv[]) 1292f982db4aSGavin Atkinson { 1293f982db4aSGavin Atkinson const char *cmd; 1294cc361f65SGavin Atkinson char *remdir, *locbuf; 1295cc361f65SGavin Atkinson const char *locfile; 1296cc361f65SGavin Atkinson int pagecmd, mlsdcmd; 1297f982db4aSGavin Atkinson 1298f982db4aSGavin Atkinson remdir = NULL; 1299cc361f65SGavin Atkinson locbuf = NULL; 1300f982db4aSGavin Atkinson locfile = "-"; 1301cc361f65SGavin Atkinson pagecmd = mlsdcmd = 0; 1302f982db4aSGavin Atkinson /* 1303f982db4aSGavin Atkinson * the only commands that start with `p' are 1304f982db4aSGavin Atkinson * the `pager' versions. 1305f982db4aSGavin Atkinson */ 1306f982db4aSGavin Atkinson if (argv[0][0] == 'p') 1307f982db4aSGavin Atkinson pagecmd = 1; 1308f982db4aSGavin Atkinson if (strcmp(argv[0] + pagecmd , "mlsd") == 0) { 1309f982db4aSGavin Atkinson if (! features[FEAT_MLST]) { 1310f982db4aSGavin Atkinson fprintf(ttyout, 1311f982db4aSGavin Atkinson "MLSD is not supported by the remote server.\n"); 1312f982db4aSGavin Atkinson return; 1313f982db4aSGavin Atkinson } 1314f982db4aSGavin Atkinson mlsdcmd = 1; 1315f982db4aSGavin Atkinson } 1316f982db4aSGavin Atkinson if (argc == 0) 1317f982db4aSGavin Atkinson goto usage; 1318f982db4aSGavin Atkinson 1319f982db4aSGavin Atkinson if (mlsdcmd) 1320f982db4aSGavin Atkinson cmd = "MLSD"; 1321f982db4aSGavin Atkinson else if (strcmp(argv[0] + pagecmd, "nlist") == 0) 1322f982db4aSGavin Atkinson cmd = "NLST"; 1323f982db4aSGavin Atkinson else 1324f982db4aSGavin Atkinson cmd = "LIST"; 1325f982db4aSGavin Atkinson 1326f982db4aSGavin Atkinson if (argc > 1) 1327f982db4aSGavin Atkinson remdir = argv[1]; 1328f982db4aSGavin Atkinson if (argc > 2) 1329f982db4aSGavin Atkinson locfile = argv[2]; 1330f982db4aSGavin Atkinson if (argc > 3 || ((pagecmd | mlsdcmd) && argc > 2)) { 1331f982db4aSGavin Atkinson usage: 1332f982db4aSGavin Atkinson if (pagecmd || mlsdcmd) 1333cc361f65SGavin Atkinson UPRINTF("usage: %s [remote-path]\n", argv[0]); 1334f982db4aSGavin Atkinson else 1335cc361f65SGavin Atkinson UPRINTF("usage: %s [remote-path [local-file]]\n", 1336f982db4aSGavin Atkinson argv[0]); 1337f982db4aSGavin Atkinson code = -1; 1338f982db4aSGavin Atkinson goto freels; 1339f982db4aSGavin Atkinson } 1340f982db4aSGavin Atkinson 1341f982db4aSGavin Atkinson if (pagecmd) { 1342cc361f65SGavin Atkinson const char *p; 1343cc361f65SGavin Atkinson size_t len; 1344f982db4aSGavin Atkinson 1345f982db4aSGavin Atkinson p = getoptionvalue("pager"); 1346f982db4aSGavin Atkinson if (EMPTYSTRING(p)) 1347f982db4aSGavin Atkinson p = DEFAULTPAGER; 1348f982db4aSGavin Atkinson len = strlen(p) + 2; 1349cc361f65SGavin Atkinson locbuf = ftp_malloc(len); 1350cc361f65SGavin Atkinson locbuf[0] = '|'; 1351cc361f65SGavin Atkinson (void)strlcpy(locbuf + 1, p, len - 1); 1352cc361f65SGavin Atkinson locfile = locbuf; 1353f982db4aSGavin Atkinson } else if ((strcmp(locfile, "-") != 0) && *locfile != '|') { 1354cc361f65SGavin Atkinson if ((locbuf = globulize(locfile)) == NULL || 1355cc361f65SGavin Atkinson !confirm("output to local-file:", locbuf)) { 1356f982db4aSGavin Atkinson code = -1; 1357f982db4aSGavin Atkinson goto freels; 1358f982db4aSGavin Atkinson } 1359cc361f65SGavin Atkinson locfile = locbuf; 1360f982db4aSGavin Atkinson } 1361f982db4aSGavin Atkinson recvrequest(cmd, locfile, remdir, "w", 0, 0); 1362f982db4aSGavin Atkinson freels: 1363cc361f65SGavin Atkinson if (locbuf) 1364cc361f65SGavin Atkinson (void)free(locbuf); 1365f982db4aSGavin Atkinson } 1366f982db4aSGavin Atkinson 1367f982db4aSGavin Atkinson /* 1368f982db4aSGavin Atkinson * Get a directory listing of multiple remote files. 1369f982db4aSGavin Atkinson */ 1370f982db4aSGavin Atkinson void 1371f982db4aSGavin Atkinson mls(int argc, char *argv[]) 1372f982db4aSGavin Atkinson { 1373f982db4aSGavin Atkinson sigfunc oldintr; 1374f982db4aSGavin Atkinson int ointer, i; 1375cc361f65SGavin Atkinson int volatile dolist; 1376cc361f65SGavin Atkinson char * volatile dest, *odest; 1377cc361f65SGavin Atkinson const char *lmode; 1378f982db4aSGavin Atkinson 1379f982db4aSGavin Atkinson if (argc == 0) 1380f982db4aSGavin Atkinson goto usage; 1381f982db4aSGavin Atkinson if (argc < 2 && !another(&argc, &argv, "remote-files")) 1382f982db4aSGavin Atkinson goto usage; 1383f982db4aSGavin Atkinson if (argc < 3 && !another(&argc, &argv, "local-file")) { 1384f982db4aSGavin Atkinson usage: 1385cc361f65SGavin Atkinson UPRINTF("usage: %s remote-files local-file\n", argv[0]); 1386f982db4aSGavin Atkinson code = -1; 1387f982db4aSGavin Atkinson return; 1388f982db4aSGavin Atkinson } 1389f982db4aSGavin Atkinson odest = dest = argv[argc - 1]; 1390f982db4aSGavin Atkinson argv[argc - 1] = NULL; 1391f982db4aSGavin Atkinson if (strcmp(dest, "-") && *dest != '|') 1392f982db4aSGavin Atkinson if (((dest = globulize(dest)) == NULL) || 1393f982db4aSGavin Atkinson !confirm("output to local-file:", dest)) { 1394f982db4aSGavin Atkinson code = -1; 1395f982db4aSGavin Atkinson return; 1396f982db4aSGavin Atkinson } 1397f982db4aSGavin Atkinson dolist = strcmp(argv[0], "mls"); 1398f982db4aSGavin Atkinson mflag = 1; 1399f982db4aSGavin Atkinson oldintr = xsignal(SIGINT, mintr); 1400f982db4aSGavin Atkinson if (sigsetjmp(jabort, 1)) 1401cc361f65SGavin Atkinson mabort(argv[0]); 1402f982db4aSGavin Atkinson for (i = 1; mflag && i < argc-1 && connected; i++) { 1403cc361f65SGavin Atkinson lmode = (i == 1) ? "w" : "a"; 1404cc361f65SGavin Atkinson recvrequest(dolist ? "LIST" : "NLST", dest, argv[i], lmode, 1405f982db4aSGavin Atkinson 0, 0); 1406f982db4aSGavin Atkinson if (!mflag && fromatty) { 1407f982db4aSGavin Atkinson ointer = interactive; 1408f982db4aSGavin Atkinson interactive = 1; 1409cc361f65SGavin Atkinson if (confirm(argv[0], NULL)) { 1410f982db4aSGavin Atkinson mflag++; 1411f982db4aSGavin Atkinson } 1412f982db4aSGavin Atkinson interactive = ointer; 1413f982db4aSGavin Atkinson } 1414f982db4aSGavin Atkinson } 1415f982db4aSGavin Atkinson (void)xsignal(SIGINT, oldintr); 1416f982db4aSGavin Atkinson mflag = 0; 1417f982db4aSGavin Atkinson if (dest != odest) /* free up after globulize() */ 1418f982db4aSGavin Atkinson free(dest); 1419f982db4aSGavin Atkinson } 1420f982db4aSGavin Atkinson 1421f982db4aSGavin Atkinson /* 1422f982db4aSGavin Atkinson * Do a shell escape 1423f982db4aSGavin Atkinson */ 1424f982db4aSGavin Atkinson /*ARGSUSED*/ 1425f982db4aSGavin Atkinson void 1426f982db4aSGavin Atkinson shell(int argc, char *argv[]) 1427f982db4aSGavin Atkinson { 1428f982db4aSGavin Atkinson pid_t pid; 1429f982db4aSGavin Atkinson sigfunc oldintr; 1430cc361f65SGavin Atkinson char shellnam[MAXPATHLEN]; 1431cc361f65SGavin Atkinson const char *shellp, *namep; 1432f982db4aSGavin Atkinson int wait_status; 1433f982db4aSGavin Atkinson 1434f982db4aSGavin Atkinson if (argc == 0) { 1435cc361f65SGavin Atkinson UPRINTF("usage: %s [command [args]]\n", argv[0]); 1436f982db4aSGavin Atkinson code = -1; 1437f982db4aSGavin Atkinson return; 1438f982db4aSGavin Atkinson } 1439f982db4aSGavin Atkinson oldintr = xsignal(SIGINT, SIG_IGN); 1440f982db4aSGavin Atkinson if ((pid = fork()) == 0) { 1441*d54cfbd1SPedro F. Giffuni (void)closefrom(3); 1442f982db4aSGavin Atkinson (void)xsignal(SIGINT, SIG_DFL); 1443cc361f65SGavin Atkinson shellp = getenv("SHELL"); 1444cc361f65SGavin Atkinson if (shellp == NULL) 1445cc361f65SGavin Atkinson shellp = _PATH_BSHELL; 1446cc361f65SGavin Atkinson namep = strrchr(shellp, '/'); 1447f982db4aSGavin Atkinson if (namep == NULL) 1448cc361f65SGavin Atkinson namep = shellp; 1449f982db4aSGavin Atkinson else 1450f982db4aSGavin Atkinson namep++; 1451f982db4aSGavin Atkinson (void)strlcpy(shellnam, namep, sizeof(shellnam)); 1452cc361f65SGavin Atkinson if (ftp_debug) { 1453cc361f65SGavin Atkinson fputs(shellp, ttyout); 1454f982db4aSGavin Atkinson putc('\n', ttyout); 1455f982db4aSGavin Atkinson } 1456f982db4aSGavin Atkinson if (argc > 1) { 1457cc361f65SGavin Atkinson execl(shellp, shellnam, "-c", altarg, (char *)0); 1458f982db4aSGavin Atkinson } 1459f982db4aSGavin Atkinson else { 1460cc361f65SGavin Atkinson execl(shellp, shellnam, (char *)0); 1461f982db4aSGavin Atkinson } 1462cc361f65SGavin Atkinson warn("Can't execute `%s'", shellp); 1463f982db4aSGavin Atkinson code = -1; 1464f982db4aSGavin Atkinson exit(1); 1465f982db4aSGavin Atkinson } 1466f982db4aSGavin Atkinson if (pid > 0) 1467f982db4aSGavin Atkinson while (wait(&wait_status) != pid) 1468f982db4aSGavin Atkinson ; 1469f982db4aSGavin Atkinson (void)xsignal(SIGINT, oldintr); 1470f982db4aSGavin Atkinson if (pid == -1) { 1471cc361f65SGavin Atkinson warn("Can't fork a subshell; try again later"); 1472f982db4aSGavin Atkinson code = -1; 1473f982db4aSGavin Atkinson } else 1474f982db4aSGavin Atkinson code = 0; 1475f982db4aSGavin Atkinson } 1476f982db4aSGavin Atkinson 1477f982db4aSGavin Atkinson /* 1478f982db4aSGavin Atkinson * Send new user information (re-login) 1479f982db4aSGavin Atkinson */ 1480f982db4aSGavin Atkinson void 1481f982db4aSGavin Atkinson user(int argc, char *argv[]) 1482f982db4aSGavin Atkinson { 1483cc361f65SGavin Atkinson char *password; 1484cc361f65SGavin Atkinson char emptypass[] = ""; 1485f982db4aSGavin Atkinson int n, aflag = 0; 1486f982db4aSGavin Atkinson 1487f982db4aSGavin Atkinson if (argc == 0) 1488f982db4aSGavin Atkinson goto usage; 1489f982db4aSGavin Atkinson if (argc < 2) 1490f982db4aSGavin Atkinson (void)another(&argc, &argv, "username"); 1491f982db4aSGavin Atkinson if (argc < 2 || argc > 4) { 1492f982db4aSGavin Atkinson usage: 1493cc361f65SGavin Atkinson UPRINTF("usage: %s username [password [account]]\n", 1494f982db4aSGavin Atkinson argv[0]); 1495f982db4aSGavin Atkinson code = -1; 1496f982db4aSGavin Atkinson return; 1497f982db4aSGavin Atkinson } 1498f982db4aSGavin Atkinson n = command("USER %s", argv[1]); 1499f982db4aSGavin Atkinson if (n == CONTINUE) { 1500f982db4aSGavin Atkinson if (argc < 3) { 1501cc361f65SGavin Atkinson password = getpass("Password: "); 1502cc361f65SGavin Atkinson if (password == NULL) 1503cc361f65SGavin Atkinson password = emptypass; 1504cc361f65SGavin Atkinson } else { 1505cc361f65SGavin Atkinson password = argv[2]; 1506f982db4aSGavin Atkinson } 1507cc361f65SGavin Atkinson n = command("PASS %s", password); 1508cc361f65SGavin Atkinson memset(password, 0, strlen(password)); 1509f982db4aSGavin Atkinson } 1510f982db4aSGavin Atkinson if (n == CONTINUE) { 1511f982db4aSGavin Atkinson aflag++; 1512cc361f65SGavin Atkinson if (argc < 4) { 1513cc361f65SGavin Atkinson password = getpass("Account: "); 1514cc361f65SGavin Atkinson if (password == NULL) 1515cc361f65SGavin Atkinson password = emptypass; 1516cc361f65SGavin Atkinson } else { 1517cc361f65SGavin Atkinson password = argv[3]; 1518cc361f65SGavin Atkinson } 1519cc361f65SGavin Atkinson n = command("ACCT %s", password); 1520cc361f65SGavin Atkinson memset(password, 0, strlen(password)); 1521f982db4aSGavin Atkinson } 1522f982db4aSGavin Atkinson if (n != COMPLETE) { 1523f982db4aSGavin Atkinson fputs("Login failed.\n", ttyout); 1524f982db4aSGavin Atkinson return; 1525f982db4aSGavin Atkinson } 1526f982db4aSGavin Atkinson if (!aflag && argc == 4) { 1527cc361f65SGavin Atkinson password = argv[3]; 1528cc361f65SGavin Atkinson (void)command("ACCT %s", password); 1529cc361f65SGavin Atkinson memset(password, 0, strlen(password)); 1530f982db4aSGavin Atkinson } 1531f982db4aSGavin Atkinson connected = -1; 1532f982db4aSGavin Atkinson getremoteinfo(); 1533f982db4aSGavin Atkinson } 1534f982db4aSGavin Atkinson 1535f982db4aSGavin Atkinson /* 1536f982db4aSGavin Atkinson * Print working directory on remote machine. 1537f982db4aSGavin Atkinson */ 1538f982db4aSGavin Atkinson /*VARARGS*/ 1539f982db4aSGavin Atkinson void 1540f982db4aSGavin Atkinson pwd(int argc, char *argv[]) 1541f982db4aSGavin Atkinson { 1542f982db4aSGavin Atkinson 1543f982db4aSGavin Atkinson code = -1; 1544f982db4aSGavin Atkinson if (argc != 1) { 1545cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 1546f982db4aSGavin Atkinson return; 1547f982db4aSGavin Atkinson } 1548f982db4aSGavin Atkinson if (! remotecwd[0]) 1549f982db4aSGavin Atkinson updateremotecwd(); 1550f982db4aSGavin Atkinson if (! remotecwd[0]) 1551f982db4aSGavin Atkinson fprintf(ttyout, "Unable to determine remote directory\n"); 1552f982db4aSGavin Atkinson else { 1553f982db4aSGavin Atkinson fprintf(ttyout, "Remote directory: %s\n", remotecwd); 1554f982db4aSGavin Atkinson code = 0; 1555f982db4aSGavin Atkinson } 1556f982db4aSGavin Atkinson } 1557f982db4aSGavin Atkinson 1558f982db4aSGavin Atkinson /* 1559f982db4aSGavin Atkinson * Print working directory on local machine. 1560f982db4aSGavin Atkinson */ 1561f982db4aSGavin Atkinson void 1562f982db4aSGavin Atkinson lpwd(int argc, char *argv[]) 1563f982db4aSGavin Atkinson { 1564f982db4aSGavin Atkinson 1565f982db4aSGavin Atkinson code = -1; 1566f982db4aSGavin Atkinson if (argc != 1) { 1567cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 1568f982db4aSGavin Atkinson return; 1569f982db4aSGavin Atkinson } 1570f982db4aSGavin Atkinson if (! localcwd[0]) 1571f982db4aSGavin Atkinson updatelocalcwd(); 1572f982db4aSGavin Atkinson if (! localcwd[0]) 1573f982db4aSGavin Atkinson fprintf(ttyout, "Unable to determine local directory\n"); 1574f982db4aSGavin Atkinson else { 1575f982db4aSGavin Atkinson fprintf(ttyout, "Local directory: %s\n", localcwd); 1576f982db4aSGavin Atkinson code = 0; 1577f982db4aSGavin Atkinson } 1578f982db4aSGavin Atkinson } 1579f982db4aSGavin Atkinson 1580f982db4aSGavin Atkinson /* 1581f982db4aSGavin Atkinson * Make a directory. 1582f982db4aSGavin Atkinson */ 1583f982db4aSGavin Atkinson void 1584f982db4aSGavin Atkinson makedir(int argc, char *argv[]) 1585f982db4aSGavin Atkinson { 1586f982db4aSGavin Atkinson int r; 1587f982db4aSGavin Atkinson 1588f982db4aSGavin Atkinson if (argc == 0 || argc > 2 || 1589f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1590cc361f65SGavin Atkinson UPRINTF("usage: %s directory-name\n", argv[0]); 1591f982db4aSGavin Atkinson code = -1; 1592f982db4aSGavin Atkinson return; 1593f982db4aSGavin Atkinson } 1594f982db4aSGavin Atkinson r = command("MKD %s", argv[1]); 1595f982db4aSGavin Atkinson if (r == ERROR && code == 500) { 1596f982db4aSGavin Atkinson if (verbose) 1597f982db4aSGavin Atkinson fputs("MKD command not recognized, trying XMKD.\n", 1598f982db4aSGavin Atkinson ttyout); 1599f982db4aSGavin Atkinson r = command("XMKD %s", argv[1]); 1600f982db4aSGavin Atkinson } 1601f982db4aSGavin Atkinson if (r == COMPLETE) 1602f982db4aSGavin Atkinson dirchange = 1; 1603f982db4aSGavin Atkinson } 1604f982db4aSGavin Atkinson 1605f982db4aSGavin Atkinson /* 1606f982db4aSGavin Atkinson * Remove a directory. 1607f982db4aSGavin Atkinson */ 1608f982db4aSGavin Atkinson void 1609f982db4aSGavin Atkinson removedir(int argc, char *argv[]) 1610f982db4aSGavin Atkinson { 1611f982db4aSGavin Atkinson int r; 1612f982db4aSGavin Atkinson 1613f982db4aSGavin Atkinson if (argc == 0 || argc > 2 || 1614f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "directory-name"))) { 1615cc361f65SGavin Atkinson UPRINTF("usage: %s directory-name\n", argv[0]); 1616f982db4aSGavin Atkinson code = -1; 1617f982db4aSGavin Atkinson return; 1618f982db4aSGavin Atkinson } 1619f982db4aSGavin Atkinson r = command("RMD %s", argv[1]); 1620f982db4aSGavin Atkinson if (r == ERROR && code == 500) { 1621f982db4aSGavin Atkinson if (verbose) 1622f982db4aSGavin Atkinson fputs("RMD command not recognized, trying XRMD.\n", 1623f982db4aSGavin Atkinson ttyout); 1624f982db4aSGavin Atkinson r = command("XRMD %s", argv[1]); 1625f982db4aSGavin Atkinson } 1626f982db4aSGavin Atkinson if (r == COMPLETE) 1627f982db4aSGavin Atkinson dirchange = 1; 1628f982db4aSGavin Atkinson } 1629f982db4aSGavin Atkinson 1630f982db4aSGavin Atkinson /* 1631f982db4aSGavin Atkinson * Send a line, verbatim, to the remote machine. 1632f982db4aSGavin Atkinson */ 1633f982db4aSGavin Atkinson void 1634f982db4aSGavin Atkinson quote(int argc, char *argv[]) 1635f982db4aSGavin Atkinson { 1636f982db4aSGavin Atkinson 1637f982db4aSGavin Atkinson if (argc == 0 || 1638f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "command line to send"))) { 1639cc361f65SGavin Atkinson UPRINTF("usage: %s line-to-send\n", argv[0]); 1640f982db4aSGavin Atkinson code = -1; 1641f982db4aSGavin Atkinson return; 1642f982db4aSGavin Atkinson } 1643f982db4aSGavin Atkinson quote1("", argc, argv); 1644f982db4aSGavin Atkinson } 1645f982db4aSGavin Atkinson 1646f982db4aSGavin Atkinson /* 1647f982db4aSGavin Atkinson * Send a SITE command to the remote machine. The line 1648f982db4aSGavin Atkinson * is sent verbatim to the remote machine, except that the 1649f982db4aSGavin Atkinson * word "SITE" is added at the front. 1650f982db4aSGavin Atkinson */ 1651f982db4aSGavin Atkinson void 1652f982db4aSGavin Atkinson site(int argc, char *argv[]) 1653f982db4aSGavin Atkinson { 1654f982db4aSGavin Atkinson 1655f982db4aSGavin Atkinson if (argc == 0 || 1656f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "arguments to SITE command"))){ 1657cc361f65SGavin Atkinson UPRINTF("usage: %s line-to-send\n", argv[0]); 1658f982db4aSGavin Atkinson code = -1; 1659f982db4aSGavin Atkinson return; 1660f982db4aSGavin Atkinson } 1661f982db4aSGavin Atkinson quote1("SITE ", argc, argv); 1662f982db4aSGavin Atkinson } 1663f982db4aSGavin Atkinson 1664f982db4aSGavin Atkinson /* 1665f982db4aSGavin Atkinson * Turn argv[1..argc) into a space-separated string, then prepend initial text. 1666f982db4aSGavin Atkinson * Send the result as a one-line command and get response. 1667f982db4aSGavin Atkinson */ 1668f982db4aSGavin Atkinson void 1669f982db4aSGavin Atkinson quote1(const char *initial, int argc, char *argv[]) 1670f982db4aSGavin Atkinson { 1671f982db4aSGavin Atkinson int i; 1672f982db4aSGavin Atkinson char buf[BUFSIZ]; /* must be >= sizeof(line) */ 1673f982db4aSGavin Atkinson 1674f982db4aSGavin Atkinson (void)strlcpy(buf, initial, sizeof(buf)); 1675f982db4aSGavin Atkinson for (i = 1; i < argc; i++) { 1676f982db4aSGavin Atkinson (void)strlcat(buf, argv[i], sizeof(buf)); 1677f982db4aSGavin Atkinson if (i < (argc - 1)) 1678f982db4aSGavin Atkinson (void)strlcat(buf, " ", sizeof(buf)); 1679f982db4aSGavin Atkinson } 1680f982db4aSGavin Atkinson if (command("%s", buf) == PRELIM) { 1681f982db4aSGavin Atkinson while (getreply(0) == PRELIM) 1682f982db4aSGavin Atkinson continue; 1683f982db4aSGavin Atkinson } 1684f982db4aSGavin Atkinson dirchange = 1; 1685f982db4aSGavin Atkinson } 1686f982db4aSGavin Atkinson 1687f982db4aSGavin Atkinson void 1688f982db4aSGavin Atkinson do_chmod(int argc, char *argv[]) 1689f982db4aSGavin Atkinson { 1690f982db4aSGavin Atkinson 1691f982db4aSGavin Atkinson if (argc == 0 || (argc == 1 && !another(&argc, &argv, "mode"))) 1692f982db4aSGavin Atkinson goto usage; 1693f982db4aSGavin Atkinson if ((argc < 3 && !another(&argc, &argv, "remote-file")) || argc > 3) { 1694f982db4aSGavin Atkinson usage: 1695cc361f65SGavin Atkinson UPRINTF("usage: %s mode remote-file\n", argv[0]); 1696f982db4aSGavin Atkinson code = -1; 1697f982db4aSGavin Atkinson return; 1698f982db4aSGavin Atkinson } 1699f982db4aSGavin Atkinson (void)command("SITE CHMOD %s %s", argv[1], argv[2]); 1700f982db4aSGavin Atkinson } 1701f982db4aSGavin Atkinson 1702f982db4aSGavin Atkinson #define COMMAND_1ARG(argc, argv, cmd) \ 1703f982db4aSGavin Atkinson if (argc == 1) \ 1704f982db4aSGavin Atkinson command(cmd); \ 1705f982db4aSGavin Atkinson else \ 1706f982db4aSGavin Atkinson command(cmd " %s", argv[1]) 1707f982db4aSGavin Atkinson 1708f982db4aSGavin Atkinson void 1709f982db4aSGavin Atkinson do_umask(int argc, char *argv[]) 1710f982db4aSGavin Atkinson { 1711f982db4aSGavin Atkinson int oldverbose = verbose; 1712f982db4aSGavin Atkinson 1713f982db4aSGavin Atkinson if (argc == 0) { 1714cc361f65SGavin Atkinson UPRINTF("usage: %s [umask]\n", argv[0]); 1715f982db4aSGavin Atkinson code = -1; 1716f982db4aSGavin Atkinson return; 1717f982db4aSGavin Atkinson } 1718f982db4aSGavin Atkinson verbose = 1; 1719f982db4aSGavin Atkinson COMMAND_1ARG(argc, argv, "SITE UMASK"); 1720f982db4aSGavin Atkinson verbose = oldverbose; 1721f982db4aSGavin Atkinson } 1722f982db4aSGavin Atkinson 1723f982db4aSGavin Atkinson void 1724f982db4aSGavin Atkinson idlecmd(int argc, char *argv[]) 1725f982db4aSGavin Atkinson { 1726f982db4aSGavin Atkinson int oldverbose = verbose; 1727f982db4aSGavin Atkinson 1728f982db4aSGavin Atkinson if (argc < 1 || argc > 2) { 1729cc361f65SGavin Atkinson UPRINTF("usage: %s [seconds]\n", argv[0]); 1730f982db4aSGavin Atkinson code = -1; 1731f982db4aSGavin Atkinson return; 1732f982db4aSGavin Atkinson } 1733f982db4aSGavin Atkinson verbose = 1; 1734f982db4aSGavin Atkinson COMMAND_1ARG(argc, argv, "SITE IDLE"); 1735f982db4aSGavin Atkinson verbose = oldverbose; 1736f982db4aSGavin Atkinson } 1737f982db4aSGavin Atkinson 1738f982db4aSGavin Atkinson /* 1739f982db4aSGavin Atkinson * Ask the other side for help. 1740f982db4aSGavin Atkinson */ 1741f982db4aSGavin Atkinson void 1742f982db4aSGavin Atkinson rmthelp(int argc, char *argv[]) 1743f982db4aSGavin Atkinson { 1744f982db4aSGavin Atkinson int oldverbose = verbose; 1745f982db4aSGavin Atkinson 1746f982db4aSGavin Atkinson if (argc == 0) { 1747cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 1748f982db4aSGavin Atkinson code = -1; 1749f982db4aSGavin Atkinson return; 1750f982db4aSGavin Atkinson } 1751f982db4aSGavin Atkinson verbose = 1; 1752f982db4aSGavin Atkinson COMMAND_1ARG(argc, argv, "HELP"); 1753f982db4aSGavin Atkinson verbose = oldverbose; 1754f982db4aSGavin Atkinson } 1755f982db4aSGavin Atkinson 1756f982db4aSGavin Atkinson /* 1757f982db4aSGavin Atkinson * Terminate session and exit. 1758f982db4aSGavin Atkinson * May be called with 0, NULL. 1759f982db4aSGavin Atkinson */ 1760f982db4aSGavin Atkinson /*VARARGS*/ 1761f982db4aSGavin Atkinson void 1762f982db4aSGavin Atkinson quit(int argc, char *argv[]) 1763f982db4aSGavin Atkinson { 1764f982db4aSGavin Atkinson 1765f982db4aSGavin Atkinson /* this may be called with argc == 0, argv == NULL */ 1766f982db4aSGavin Atkinson if (argc == 0 && argv != NULL) { 1767cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 1768f982db4aSGavin Atkinson code = -1; 1769f982db4aSGavin Atkinson return; 1770f982db4aSGavin Atkinson } 1771f982db4aSGavin Atkinson if (connected) 1772f982db4aSGavin Atkinson disconnect(0, NULL); 1773f982db4aSGavin Atkinson pswitch(1); 1774f982db4aSGavin Atkinson if (connected) 1775f982db4aSGavin Atkinson disconnect(0, NULL); 1776f982db4aSGavin Atkinson exit(0); 1777f982db4aSGavin Atkinson } 1778f982db4aSGavin Atkinson 1779f982db4aSGavin Atkinson /* 1780f982db4aSGavin Atkinson * Terminate session, but don't exit. 1781f982db4aSGavin Atkinson * May be called with 0, NULL. 1782f982db4aSGavin Atkinson */ 1783f982db4aSGavin Atkinson void 1784f982db4aSGavin Atkinson disconnect(int argc, char *argv[]) 1785f982db4aSGavin Atkinson { 1786f982db4aSGavin Atkinson 1787f982db4aSGavin Atkinson /* this may be called with argc == 0, argv == NULL */ 1788f982db4aSGavin Atkinson if (argc == 0 && argv != NULL) { 1789cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 1790f982db4aSGavin Atkinson code = -1; 1791f982db4aSGavin Atkinson return; 1792f982db4aSGavin Atkinson } 1793f982db4aSGavin Atkinson if (!connected) 1794f982db4aSGavin Atkinson return; 1795f982db4aSGavin Atkinson (void)command("QUIT"); 1796f982db4aSGavin Atkinson cleanuppeer(); 1797f982db4aSGavin Atkinson } 1798f982db4aSGavin Atkinson 1799f982db4aSGavin Atkinson void 1800f982db4aSGavin Atkinson account(int argc, char *argv[]) 1801f982db4aSGavin Atkinson { 1802f982db4aSGavin Atkinson char *ap; 1803cc361f65SGavin Atkinson char emptypass[] = ""; 1804f982db4aSGavin Atkinson 1805f982db4aSGavin Atkinson if (argc == 0 || argc > 2) { 1806cc361f65SGavin Atkinson UPRINTF("usage: %s [password]\n", argv[0]); 1807f982db4aSGavin Atkinson code = -1; 1808f982db4aSGavin Atkinson return; 1809f982db4aSGavin Atkinson } 1810f982db4aSGavin Atkinson else if (argc == 2) 1811f982db4aSGavin Atkinson ap = argv[1]; 1812cc361f65SGavin Atkinson else { 1813f982db4aSGavin Atkinson ap = getpass("Account:"); 1814cc361f65SGavin Atkinson if (ap == NULL) 1815cc361f65SGavin Atkinson ap = emptypass; 1816cc361f65SGavin Atkinson } 1817f982db4aSGavin Atkinson (void)command("ACCT %s", ap); 1818cc361f65SGavin Atkinson memset(ap, 0, strlen(ap)); 1819f982db4aSGavin Atkinson } 1820f982db4aSGavin Atkinson 1821f982db4aSGavin Atkinson sigjmp_buf abortprox; 1822f982db4aSGavin Atkinson 1823f982db4aSGavin Atkinson void 1824f982db4aSGavin Atkinson proxabort(int notused) 1825f982db4aSGavin Atkinson { 1826f982db4aSGavin Atkinson 1827f982db4aSGavin Atkinson sigint_raised = 1; 1828f982db4aSGavin Atkinson alarmtimer(0); 1829f982db4aSGavin Atkinson if (!proxy) { 1830f982db4aSGavin Atkinson pswitch(1); 1831f982db4aSGavin Atkinson } 1832f982db4aSGavin Atkinson if (connected) { 1833f982db4aSGavin Atkinson proxflag = 1; 1834f982db4aSGavin Atkinson } 1835f982db4aSGavin Atkinson else { 1836f982db4aSGavin Atkinson proxflag = 0; 1837f982db4aSGavin Atkinson } 1838f982db4aSGavin Atkinson pswitch(0); 1839f982db4aSGavin Atkinson siglongjmp(abortprox, 1); 1840f982db4aSGavin Atkinson } 1841f982db4aSGavin Atkinson 1842f982db4aSGavin Atkinson void 1843f982db4aSGavin Atkinson doproxy(int argc, char *argv[]) 1844f982db4aSGavin Atkinson { 1845f982db4aSGavin Atkinson struct cmd *c; 1846f982db4aSGavin Atkinson int cmdpos; 1847f982db4aSGavin Atkinson sigfunc oldintr; 1848cc361f65SGavin Atkinson char cmdbuf[MAX_C_NAME]; 1849f982db4aSGavin Atkinson 1850f982db4aSGavin Atkinson if (argc == 0 || (argc == 1 && !another(&argc, &argv, "command"))) { 1851cc361f65SGavin Atkinson UPRINTF("usage: %s command\n", argv[0]); 1852f982db4aSGavin Atkinson code = -1; 1853f982db4aSGavin Atkinson return; 1854f982db4aSGavin Atkinson } 1855f982db4aSGavin Atkinson c = getcmd(argv[1]); 1856f982db4aSGavin Atkinson if (c == (struct cmd *) -1) { 1857f982db4aSGavin Atkinson fputs("?Ambiguous command.\n", ttyout); 1858f982db4aSGavin Atkinson code = -1; 1859f982db4aSGavin Atkinson return; 1860f982db4aSGavin Atkinson } 1861f982db4aSGavin Atkinson if (c == 0) { 1862f982db4aSGavin Atkinson fputs("?Invalid command.\n", ttyout); 1863f982db4aSGavin Atkinson code = -1; 1864f982db4aSGavin Atkinson return; 1865f982db4aSGavin Atkinson } 1866f982db4aSGavin Atkinson if (!c->c_proxy) { 1867f982db4aSGavin Atkinson fputs("?Invalid proxy command.\n", ttyout); 1868f982db4aSGavin Atkinson code = -1; 1869f982db4aSGavin Atkinson return; 1870f982db4aSGavin Atkinson } 1871f982db4aSGavin Atkinson if (sigsetjmp(abortprox, 1)) { 1872f982db4aSGavin Atkinson code = -1; 1873f982db4aSGavin Atkinson return; 1874f982db4aSGavin Atkinson } 1875f982db4aSGavin Atkinson oldintr = xsignal(SIGINT, proxabort); 1876f982db4aSGavin Atkinson pswitch(1); 1877f982db4aSGavin Atkinson if (c->c_conn && !connected) { 1878f982db4aSGavin Atkinson fputs("Not connected.\n", ttyout); 1879f982db4aSGavin Atkinson pswitch(0); 1880f982db4aSGavin Atkinson (void)xsignal(SIGINT, oldintr); 1881f982db4aSGavin Atkinson code = -1; 1882f982db4aSGavin Atkinson return; 1883f982db4aSGavin Atkinson } 1884f982db4aSGavin Atkinson cmdpos = strcspn(line, " \t"); 1885f982db4aSGavin Atkinson if (cmdpos > 0) /* remove leading "proxy " from input buffer */ 1886f982db4aSGavin Atkinson memmove(line, line + cmdpos + 1, strlen(line) - cmdpos + 1); 1887cc361f65SGavin Atkinson (void)strlcpy(cmdbuf, c->c_name, sizeof(cmdbuf)); 1888cc361f65SGavin Atkinson argv[1] = cmdbuf; 1889f982db4aSGavin Atkinson (*c->c_handler)(argc-1, argv+1); 1890f982db4aSGavin Atkinson if (connected) { 1891f982db4aSGavin Atkinson proxflag = 1; 1892f982db4aSGavin Atkinson } 1893f982db4aSGavin Atkinson else { 1894f982db4aSGavin Atkinson proxflag = 0; 1895f982db4aSGavin Atkinson } 1896f982db4aSGavin Atkinson pswitch(0); 1897f982db4aSGavin Atkinson (void)xsignal(SIGINT, oldintr); 1898f982db4aSGavin Atkinson } 1899f982db4aSGavin Atkinson 1900f982db4aSGavin Atkinson void 1901f982db4aSGavin Atkinson setcase(int argc, char *argv[]) 1902f982db4aSGavin Atkinson { 1903f982db4aSGavin Atkinson 1904f982db4aSGavin Atkinson code = togglevar(argc, argv, &mcase, "Case mapping"); 1905f982db4aSGavin Atkinson } 1906f982db4aSGavin Atkinson 1907f982db4aSGavin Atkinson /* 1908f982db4aSGavin Atkinson * convert the given name to lower case if it's all upper case, into 1909f982db4aSGavin Atkinson * a static buffer which is returned to the caller 1910f982db4aSGavin Atkinson */ 1911f982db4aSGavin Atkinson static const char * 1912f982db4aSGavin Atkinson docase(char *dst, size_t dlen, const char *src) 1913f982db4aSGavin Atkinson { 1914f982db4aSGavin Atkinson size_t i; 1915f982db4aSGavin Atkinson int dochange = 1; 1916f982db4aSGavin Atkinson 1917f982db4aSGavin Atkinson for (i = 0; src[i] != '\0' && i < dlen - 1; i++) { 1918f982db4aSGavin Atkinson dst[i] = src[i]; 1919f982db4aSGavin Atkinson if (islower((unsigned char)dst[i])) 1920f982db4aSGavin Atkinson dochange = 0; 1921f982db4aSGavin Atkinson } 1922f982db4aSGavin Atkinson dst[i] = '\0'; 1923f982db4aSGavin Atkinson 1924f982db4aSGavin Atkinson if (dochange) { 1925f982db4aSGavin Atkinson for (i = 0; dst[i] != '\0'; i++) 1926f982db4aSGavin Atkinson if (isupper((unsigned char)dst[i])) 1927f982db4aSGavin Atkinson dst[i] = tolower((unsigned char)dst[i]); 1928f982db4aSGavin Atkinson } 1929f982db4aSGavin Atkinson return dst; 1930f982db4aSGavin Atkinson } 1931f982db4aSGavin Atkinson 1932f982db4aSGavin Atkinson void 1933f982db4aSGavin Atkinson setcr(int argc, char *argv[]) 1934f982db4aSGavin Atkinson { 1935f982db4aSGavin Atkinson 1936f982db4aSGavin Atkinson code = togglevar(argc, argv, &crflag, "Carriage Return stripping"); 1937f982db4aSGavin Atkinson } 1938f982db4aSGavin Atkinson 1939f982db4aSGavin Atkinson void 1940f982db4aSGavin Atkinson setntrans(int argc, char *argv[]) 1941f982db4aSGavin Atkinson { 1942f982db4aSGavin Atkinson 1943f982db4aSGavin Atkinson if (argc == 0 || argc > 3) { 1944cc361f65SGavin Atkinson UPRINTF("usage: %s [inchars [outchars]]\n", argv[0]); 1945f982db4aSGavin Atkinson code = -1; 1946f982db4aSGavin Atkinson return; 1947f982db4aSGavin Atkinson } 1948f982db4aSGavin Atkinson if (argc == 1) { 1949f982db4aSGavin Atkinson ntflag = 0; 1950f982db4aSGavin Atkinson fputs("Ntrans off.\n", ttyout); 1951f982db4aSGavin Atkinson code = ntflag; 1952f982db4aSGavin Atkinson return; 1953f982db4aSGavin Atkinson } 1954f982db4aSGavin Atkinson ntflag++; 1955f982db4aSGavin Atkinson code = ntflag; 1956f982db4aSGavin Atkinson (void)strlcpy(ntin, argv[1], sizeof(ntin)); 1957f982db4aSGavin Atkinson if (argc == 2) { 1958f982db4aSGavin Atkinson ntout[0] = '\0'; 1959f982db4aSGavin Atkinson return; 1960f982db4aSGavin Atkinson } 1961f982db4aSGavin Atkinson (void)strlcpy(ntout, argv[2], sizeof(ntout)); 1962f982db4aSGavin Atkinson } 1963f982db4aSGavin Atkinson 1964f982db4aSGavin Atkinson static const char * 1965f982db4aSGavin Atkinson dotrans(char *dst, size_t dlen, const char *src) 1966f982db4aSGavin Atkinson { 1967f982db4aSGavin Atkinson const char *cp1; 1968f982db4aSGavin Atkinson char *cp2 = dst; 1969f982db4aSGavin Atkinson size_t i, ostop; 1970f982db4aSGavin Atkinson 1971f982db4aSGavin Atkinson for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 1972f982db4aSGavin Atkinson continue; 1973f982db4aSGavin Atkinson for (cp1 = src; *cp1; cp1++) { 1974f982db4aSGavin Atkinson int found = 0; 1975f982db4aSGavin Atkinson for (i = 0; *(ntin + i) && i < 16; i++) { 1976f982db4aSGavin Atkinson if (*cp1 == *(ntin + i)) { 1977f982db4aSGavin Atkinson found++; 1978f982db4aSGavin Atkinson if (i < ostop) { 1979f982db4aSGavin Atkinson *cp2++ = *(ntout + i); 1980cc361f65SGavin Atkinson if (cp2 - dst >= (ptrdiff_t)(dlen - 1)) 1981f982db4aSGavin Atkinson goto out; 1982f982db4aSGavin Atkinson } 1983f982db4aSGavin Atkinson break; 1984f982db4aSGavin Atkinson } 1985f982db4aSGavin Atkinson } 1986f982db4aSGavin Atkinson if (!found) { 1987f982db4aSGavin Atkinson *cp2++ = *cp1; 1988f982db4aSGavin Atkinson } 1989f982db4aSGavin Atkinson } 1990f982db4aSGavin Atkinson out: 1991f982db4aSGavin Atkinson *cp2 = '\0'; 1992f982db4aSGavin Atkinson return dst; 1993f982db4aSGavin Atkinson } 1994f982db4aSGavin Atkinson 1995f982db4aSGavin Atkinson void 1996f982db4aSGavin Atkinson setnmap(int argc, char *argv[]) 1997f982db4aSGavin Atkinson { 1998f982db4aSGavin Atkinson char *cp; 1999f982db4aSGavin Atkinson 2000f982db4aSGavin Atkinson if (argc == 1) { 2001f982db4aSGavin Atkinson mapflag = 0; 2002f982db4aSGavin Atkinson fputs("Nmap off.\n", ttyout); 2003f982db4aSGavin Atkinson code = mapflag; 2004f982db4aSGavin Atkinson return; 2005f982db4aSGavin Atkinson } 2006f982db4aSGavin Atkinson if (argc == 0 || 2007f982db4aSGavin Atkinson (argc < 3 && !another(&argc, &argv, "mapout")) || argc > 3) { 2008cc361f65SGavin Atkinson UPRINTF("usage: %s [mapin mapout]\n", argv[0]); 2009f982db4aSGavin Atkinson code = -1; 2010f982db4aSGavin Atkinson return; 2011f982db4aSGavin Atkinson } 2012f982db4aSGavin Atkinson mapflag = 1; 2013f982db4aSGavin Atkinson code = 1; 2014f982db4aSGavin Atkinson cp = strchr(altarg, ' '); 2015f982db4aSGavin Atkinson if (proxy) { 2016f982db4aSGavin Atkinson while(*++cp == ' ') 2017f982db4aSGavin Atkinson continue; 2018f982db4aSGavin Atkinson altarg = cp; 2019f982db4aSGavin Atkinson cp = strchr(altarg, ' '); 2020f982db4aSGavin Atkinson } 2021f982db4aSGavin Atkinson *cp = '\0'; 2022f982db4aSGavin Atkinson (void)strlcpy(mapin, altarg, MAXPATHLEN); 2023f982db4aSGavin Atkinson while (*++cp == ' ') 2024f982db4aSGavin Atkinson continue; 2025f982db4aSGavin Atkinson (void)strlcpy(mapout, cp, MAXPATHLEN); 2026f982db4aSGavin Atkinson } 2027f982db4aSGavin Atkinson 2028f982db4aSGavin Atkinson static const char * 2029f982db4aSGavin Atkinson domap(char *dst, size_t dlen, const char *src) 2030f982db4aSGavin Atkinson { 2031f982db4aSGavin Atkinson const char *cp1 = src; 2032f982db4aSGavin Atkinson char *cp2 = mapin; 2033f982db4aSGavin Atkinson const char *tp[9], *te[9]; 2034f982db4aSGavin Atkinson int i, toks[9], toknum = 0, match = 1; 2035f982db4aSGavin Atkinson 2036f982db4aSGavin Atkinson for (i=0; i < 9; ++i) { 2037f982db4aSGavin Atkinson toks[i] = 0; 2038f982db4aSGavin Atkinson } 2039f982db4aSGavin Atkinson while (match && *cp1 && *cp2) { 2040f982db4aSGavin Atkinson switch (*cp2) { 2041f982db4aSGavin Atkinson case '\\': 2042f982db4aSGavin Atkinson if (*++cp2 != *cp1) { 2043f982db4aSGavin Atkinson match = 0; 2044f982db4aSGavin Atkinson } 2045f982db4aSGavin Atkinson break; 2046f982db4aSGavin Atkinson case '$': 2047f982db4aSGavin Atkinson if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 2048f982db4aSGavin Atkinson if (*cp1 != *(++cp2+1)) { 2049f982db4aSGavin Atkinson toks[toknum = *cp2 - '1']++; 2050f982db4aSGavin Atkinson tp[toknum] = cp1; 2051f982db4aSGavin Atkinson while (*++cp1 && *(cp2+1) 2052f982db4aSGavin Atkinson != *cp1); 2053f982db4aSGavin Atkinson te[toknum] = cp1; 2054f982db4aSGavin Atkinson } 2055f982db4aSGavin Atkinson cp2++; 2056f982db4aSGavin Atkinson break; 2057f982db4aSGavin Atkinson } 2058f982db4aSGavin Atkinson /* FALLTHROUGH */ 2059f982db4aSGavin Atkinson default: 2060f982db4aSGavin Atkinson if (*cp2 != *cp1) { 2061f982db4aSGavin Atkinson match = 0; 2062f982db4aSGavin Atkinson } 2063f982db4aSGavin Atkinson break; 2064f982db4aSGavin Atkinson } 2065f982db4aSGavin Atkinson if (match && *cp1) { 2066f982db4aSGavin Atkinson cp1++; 2067f982db4aSGavin Atkinson } 2068f982db4aSGavin Atkinson if (match && *cp2) { 2069f982db4aSGavin Atkinson cp2++; 2070f982db4aSGavin Atkinson } 2071f982db4aSGavin Atkinson } 2072f982db4aSGavin Atkinson if (!match && *cp1) /* last token mismatch */ 2073f982db4aSGavin Atkinson { 2074f982db4aSGavin Atkinson toks[toknum] = 0; 2075f982db4aSGavin Atkinson } 2076f982db4aSGavin Atkinson cp2 = dst; 2077f982db4aSGavin Atkinson *cp2 = '\0'; 2078f982db4aSGavin Atkinson cp1 = mapout; 2079f982db4aSGavin Atkinson while (*cp1) { 2080f982db4aSGavin Atkinson match = 0; 2081f982db4aSGavin Atkinson switch (*cp1) { 2082f982db4aSGavin Atkinson case '\\': 2083f982db4aSGavin Atkinson if (*(cp1 + 1)) { 2084f982db4aSGavin Atkinson *cp2++ = *++cp1; 2085f982db4aSGavin Atkinson } 2086f982db4aSGavin Atkinson break; 2087f982db4aSGavin Atkinson case '[': 2088f982db4aSGavin Atkinson LOOP: 2089f982db4aSGavin Atkinson if (*++cp1 == '$' && 2090f982db4aSGavin Atkinson isdigit((unsigned char)*(cp1+1))) { 2091f982db4aSGavin Atkinson if (*++cp1 == '0') { 2092f982db4aSGavin Atkinson const char *cp3 = src; 2093f982db4aSGavin Atkinson 2094f982db4aSGavin Atkinson while (*cp3) { 2095f982db4aSGavin Atkinson *cp2++ = *cp3++; 2096f982db4aSGavin Atkinson } 2097f982db4aSGavin Atkinson match = 1; 2098f982db4aSGavin Atkinson } 2099f982db4aSGavin Atkinson else if (toks[toknum = *cp1 - '1']) { 2100f982db4aSGavin Atkinson const char *cp3 = tp[toknum]; 2101f982db4aSGavin Atkinson 2102f982db4aSGavin Atkinson while (cp3 != te[toknum]) { 2103f982db4aSGavin Atkinson *cp2++ = *cp3++; 2104f982db4aSGavin Atkinson } 2105f982db4aSGavin Atkinson match = 1; 2106f982db4aSGavin Atkinson } 2107f982db4aSGavin Atkinson } 2108f982db4aSGavin Atkinson else { 2109f982db4aSGavin Atkinson while (*cp1 && *cp1 != ',' && 2110f982db4aSGavin Atkinson *cp1 != ']') { 2111f982db4aSGavin Atkinson if (*cp1 == '\\') { 2112f982db4aSGavin Atkinson cp1++; 2113f982db4aSGavin Atkinson } 2114f982db4aSGavin Atkinson else if (*cp1 == '$' && 2115f982db4aSGavin Atkinson isdigit((unsigned char)*(cp1+1))) { 2116f982db4aSGavin Atkinson if (*++cp1 == '0') { 2117f982db4aSGavin Atkinson const char *cp3 = src; 2118f982db4aSGavin Atkinson 2119f982db4aSGavin Atkinson while (*cp3) { 2120f982db4aSGavin Atkinson *cp2++ = *cp3++; 2121f982db4aSGavin Atkinson } 2122f982db4aSGavin Atkinson } 2123f982db4aSGavin Atkinson else if (toks[toknum = 2124f982db4aSGavin Atkinson *cp1 - '1']) { 2125f982db4aSGavin Atkinson const char *cp3=tp[toknum]; 2126f982db4aSGavin Atkinson 2127f982db4aSGavin Atkinson while (cp3 != 2128f982db4aSGavin Atkinson te[toknum]) { 2129f982db4aSGavin Atkinson *cp2++ = *cp3++; 2130f982db4aSGavin Atkinson } 2131f982db4aSGavin Atkinson } 2132f982db4aSGavin Atkinson } 2133f982db4aSGavin Atkinson else if (*cp1) { 2134f982db4aSGavin Atkinson *cp2++ = *cp1++; 2135f982db4aSGavin Atkinson } 2136f982db4aSGavin Atkinson } 2137f982db4aSGavin Atkinson if (!*cp1) { 2138f982db4aSGavin Atkinson fputs( 2139f982db4aSGavin Atkinson "nmap: unbalanced brackets.\n", 2140f982db4aSGavin Atkinson ttyout); 2141f982db4aSGavin Atkinson return (src); 2142f982db4aSGavin Atkinson } 2143f982db4aSGavin Atkinson match = 1; 2144f982db4aSGavin Atkinson cp1--; 2145f982db4aSGavin Atkinson } 2146f982db4aSGavin Atkinson if (match) { 2147f982db4aSGavin Atkinson while (*++cp1 && *cp1 != ']') { 2148f982db4aSGavin Atkinson if (*cp1 == '\\' && *(cp1 + 1)) { 2149f982db4aSGavin Atkinson cp1++; 2150f982db4aSGavin Atkinson } 2151f982db4aSGavin Atkinson } 2152f982db4aSGavin Atkinson if (!*cp1) { 2153f982db4aSGavin Atkinson fputs( 2154f982db4aSGavin Atkinson "nmap: unbalanced brackets.\n", 2155f982db4aSGavin Atkinson ttyout); 2156f982db4aSGavin Atkinson return (src); 2157f982db4aSGavin Atkinson } 2158f982db4aSGavin Atkinson break; 2159f982db4aSGavin Atkinson } 2160f982db4aSGavin Atkinson switch (*++cp1) { 2161f982db4aSGavin Atkinson case ',': 2162f982db4aSGavin Atkinson goto LOOP; 2163f982db4aSGavin Atkinson case ']': 2164f982db4aSGavin Atkinson break; 2165f982db4aSGavin Atkinson default: 2166f982db4aSGavin Atkinson cp1--; 2167f982db4aSGavin Atkinson goto LOOP; 2168f982db4aSGavin Atkinson } 2169f982db4aSGavin Atkinson break; 2170f982db4aSGavin Atkinson case '$': 2171f982db4aSGavin Atkinson if (isdigit((unsigned char)*(cp1 + 1))) { 2172f982db4aSGavin Atkinson if (*++cp1 == '0') { 2173f982db4aSGavin Atkinson const char *cp3 = src; 2174f982db4aSGavin Atkinson 2175f982db4aSGavin Atkinson while (*cp3) { 2176f982db4aSGavin Atkinson *cp2++ = *cp3++; 2177f982db4aSGavin Atkinson } 2178f982db4aSGavin Atkinson } 2179f982db4aSGavin Atkinson else if (toks[toknum = *cp1 - '1']) { 2180f982db4aSGavin Atkinson const char *cp3 = tp[toknum]; 2181f982db4aSGavin Atkinson 2182f982db4aSGavin Atkinson while (cp3 != te[toknum]) { 2183f982db4aSGavin Atkinson *cp2++ = *cp3++; 2184f982db4aSGavin Atkinson } 2185f982db4aSGavin Atkinson } 2186f982db4aSGavin Atkinson break; 2187f982db4aSGavin Atkinson } 2188f982db4aSGavin Atkinson /* intentional drop through */ 2189f982db4aSGavin Atkinson default: 2190f982db4aSGavin Atkinson *cp2++ = *cp1; 2191f982db4aSGavin Atkinson break; 2192f982db4aSGavin Atkinson } 2193f982db4aSGavin Atkinson cp1++; 2194f982db4aSGavin Atkinson } 2195f982db4aSGavin Atkinson *cp2 = '\0'; 2196f982db4aSGavin Atkinson return *dst ? dst : src; 2197f982db4aSGavin Atkinson } 2198f982db4aSGavin Atkinson 2199f982db4aSGavin Atkinson void 2200f982db4aSGavin Atkinson setpassive(int argc, char *argv[]) 2201f982db4aSGavin Atkinson { 2202f982db4aSGavin Atkinson 2203f982db4aSGavin Atkinson if (argc == 1) { 2204f982db4aSGavin Atkinson passivemode = !passivemode; 2205f982db4aSGavin Atkinson activefallback = passivemode; 2206f982db4aSGavin Atkinson } else if (argc != 2) { 2207f982db4aSGavin Atkinson passiveusage: 2208cc361f65SGavin Atkinson UPRINTF("usage: %s [ on | off | auto ]\n", argv[0]); 2209f982db4aSGavin Atkinson code = -1; 2210f982db4aSGavin Atkinson return; 2211f982db4aSGavin Atkinson } else if (strcasecmp(argv[1], "on") == 0) { 2212f982db4aSGavin Atkinson passivemode = 1; 2213f982db4aSGavin Atkinson activefallback = 0; 2214f982db4aSGavin Atkinson } else if (strcasecmp(argv[1], "off") == 0) { 2215f982db4aSGavin Atkinson passivemode = 0; 2216f982db4aSGavin Atkinson activefallback = 0; 2217f982db4aSGavin Atkinson } else if (strcasecmp(argv[1], "auto") == 0) { 2218f982db4aSGavin Atkinson passivemode = 1; 2219f982db4aSGavin Atkinson activefallback = 1; 2220f982db4aSGavin Atkinson } else 2221f982db4aSGavin Atkinson goto passiveusage; 2222f982db4aSGavin Atkinson fprintf(ttyout, "Passive mode: %s; fallback to active mode: %s.\n", 2223f982db4aSGavin Atkinson onoff(passivemode), onoff(activefallback)); 2224f982db4aSGavin Atkinson code = passivemode; 2225f982db4aSGavin Atkinson } 2226f982db4aSGavin Atkinson 2227cc361f65SGavin Atkinson 2228f982db4aSGavin Atkinson void 2229f982db4aSGavin Atkinson setepsv4(int argc, char *argv[]) 2230f982db4aSGavin Atkinson { 2231f982db4aSGavin Atkinson code = togglevar(argc, argv, &epsv4, 2232f982db4aSGavin Atkinson verbose ? "EPSV/EPRT on IPv4" : NULL); 2233f982db4aSGavin Atkinson epsv4bad = 0; 2234f982db4aSGavin Atkinson } 2235f982db4aSGavin Atkinson 2236f982db4aSGavin Atkinson void 2237cc361f65SGavin Atkinson setepsv6(int argc, char *argv[]) 2238cc361f65SGavin Atkinson { 2239cc361f65SGavin Atkinson code = togglevar(argc, argv, &epsv6, 2240cc361f65SGavin Atkinson verbose ? "EPSV/EPRT on IPv6" : NULL); 2241cc361f65SGavin Atkinson epsv6bad = 0; 2242cc361f65SGavin Atkinson } 2243cc361f65SGavin Atkinson 2244cc361f65SGavin Atkinson void 2245cc361f65SGavin Atkinson setepsv(int argc, char*argv[]) 2246cc361f65SGavin Atkinson { 2247cc361f65SGavin Atkinson setepsv4(argc,argv); 2248cc361f65SGavin Atkinson setepsv6(argc,argv); 2249cc361f65SGavin Atkinson } 2250cc361f65SGavin Atkinson 2251cc361f65SGavin Atkinson void 2252f982db4aSGavin Atkinson setsunique(int argc, char *argv[]) 2253f982db4aSGavin Atkinson { 2254f982db4aSGavin Atkinson 2255f982db4aSGavin Atkinson code = togglevar(argc, argv, &sunique, "Store unique"); 2256f982db4aSGavin Atkinson } 2257f982db4aSGavin Atkinson 2258f982db4aSGavin Atkinson void 2259f982db4aSGavin Atkinson setrunique(int argc, char *argv[]) 2260f982db4aSGavin Atkinson { 2261f982db4aSGavin Atkinson 2262f982db4aSGavin Atkinson code = togglevar(argc, argv, &runique, "Receive unique"); 2263f982db4aSGavin Atkinson } 2264f982db4aSGavin Atkinson 2265f982db4aSGavin Atkinson int 2266f982db4aSGavin Atkinson parserate(int argc, char *argv[], int cmdlineopt) 2267f982db4aSGavin Atkinson { 2268f982db4aSGavin Atkinson int dir, max, incr, showonly; 2269f982db4aSGavin Atkinson sigfunc oldusr1, oldusr2; 2270f982db4aSGavin Atkinson 2271f982db4aSGavin Atkinson if (argc > 4 || (argc < (cmdlineopt ? 3 : 2))) { 2272f982db4aSGavin Atkinson usage: 2273f982db4aSGavin Atkinson if (cmdlineopt) 2274cc361f65SGavin Atkinson UPRINTF( 2275f982db4aSGavin Atkinson "usage: %s (all|get|put),maximum-bytes[,increment-bytes]]\n", 2276f982db4aSGavin Atkinson argv[0]); 2277f982db4aSGavin Atkinson else 2278cc361f65SGavin Atkinson UPRINTF( 2279f982db4aSGavin Atkinson "usage: %s (all|get|put) [maximum-bytes [increment-bytes]]\n", 2280f982db4aSGavin Atkinson argv[0]); 2281f982db4aSGavin Atkinson return -1; 2282f982db4aSGavin Atkinson } 2283f982db4aSGavin Atkinson dir = max = incr = showonly = 0; 2284f982db4aSGavin Atkinson #define RATE_GET 1 2285f982db4aSGavin Atkinson #define RATE_PUT 2 2286f982db4aSGavin Atkinson #define RATE_ALL (RATE_GET | RATE_PUT) 2287f982db4aSGavin Atkinson 2288f982db4aSGavin Atkinson if (strcasecmp(argv[1], "all") == 0) 2289f982db4aSGavin Atkinson dir = RATE_ALL; 2290f982db4aSGavin Atkinson else if (strcasecmp(argv[1], "get") == 0) 2291f982db4aSGavin Atkinson dir = RATE_GET; 2292f982db4aSGavin Atkinson else if (strcasecmp(argv[1], "put") == 0) 2293f982db4aSGavin Atkinson dir = RATE_PUT; 2294f982db4aSGavin Atkinson else 2295f982db4aSGavin Atkinson goto usage; 2296f982db4aSGavin Atkinson 2297f982db4aSGavin Atkinson if (argc >= 3) { 2298f982db4aSGavin Atkinson if ((max = strsuftoi(argv[2])) < 0) 2299f982db4aSGavin Atkinson goto usage; 2300f982db4aSGavin Atkinson } else 2301f982db4aSGavin Atkinson showonly = 1; 2302f982db4aSGavin Atkinson 2303f982db4aSGavin Atkinson if (argc == 4) { 2304f982db4aSGavin Atkinson if ((incr = strsuftoi(argv[3])) <= 0) 2305f982db4aSGavin Atkinson goto usage; 2306f982db4aSGavin Atkinson } else 2307f982db4aSGavin Atkinson incr = DEFAULTINCR; 2308f982db4aSGavin Atkinson 2309f982db4aSGavin Atkinson oldusr1 = xsignal(SIGUSR1, SIG_IGN); 2310f982db4aSGavin Atkinson oldusr2 = xsignal(SIGUSR2, SIG_IGN); 2311f982db4aSGavin Atkinson if (dir & RATE_GET) { 2312f982db4aSGavin Atkinson if (!showonly) { 2313f982db4aSGavin Atkinson rate_get = max; 2314f982db4aSGavin Atkinson rate_get_incr = incr; 2315f982db4aSGavin Atkinson } 2316f982db4aSGavin Atkinson if (!cmdlineopt || verbose) 2317f982db4aSGavin Atkinson fprintf(ttyout, 2318f982db4aSGavin Atkinson "Get transfer rate throttle: %s; maximum: %d; increment %d.\n", 2319f982db4aSGavin Atkinson onoff(rate_get), rate_get, rate_get_incr); 2320f982db4aSGavin Atkinson } 2321f982db4aSGavin Atkinson if (dir & RATE_PUT) { 2322f982db4aSGavin Atkinson if (!showonly) { 2323f982db4aSGavin Atkinson rate_put = max; 2324f982db4aSGavin Atkinson rate_put_incr = incr; 2325f982db4aSGavin Atkinson } 2326f982db4aSGavin Atkinson if (!cmdlineopt || verbose) 2327f982db4aSGavin Atkinson fprintf(ttyout, 2328f982db4aSGavin Atkinson "Put transfer rate throttle: %s; maximum: %d; increment %d.\n", 2329f982db4aSGavin Atkinson onoff(rate_put), rate_put, rate_put_incr); 2330f982db4aSGavin Atkinson } 2331f982db4aSGavin Atkinson (void)xsignal(SIGUSR1, oldusr1); 2332f982db4aSGavin Atkinson (void)xsignal(SIGUSR2, oldusr2); 2333f982db4aSGavin Atkinson return 0; 2334f982db4aSGavin Atkinson } 2335f982db4aSGavin Atkinson 2336f982db4aSGavin Atkinson void 2337f982db4aSGavin Atkinson setrate(int argc, char *argv[]) 2338f982db4aSGavin Atkinson { 2339f982db4aSGavin Atkinson 2340f982db4aSGavin Atkinson code = parserate(argc, argv, 0); 2341f982db4aSGavin Atkinson } 2342f982db4aSGavin Atkinson 2343f982db4aSGavin Atkinson /* change directory to parent directory */ 2344f982db4aSGavin Atkinson void 2345f982db4aSGavin Atkinson cdup(int argc, char *argv[]) 2346f982db4aSGavin Atkinson { 2347f982db4aSGavin Atkinson int r; 2348f982db4aSGavin Atkinson 2349f982db4aSGavin Atkinson if (argc == 0) { 2350cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 2351f982db4aSGavin Atkinson code = -1; 2352f982db4aSGavin Atkinson return; 2353f982db4aSGavin Atkinson } 2354f982db4aSGavin Atkinson r = command("CDUP"); 2355f982db4aSGavin Atkinson if (r == ERROR && code == 500) { 2356f982db4aSGavin Atkinson if (verbose) 2357f982db4aSGavin Atkinson fputs("CDUP command not recognized, trying XCUP.\n", 2358f982db4aSGavin Atkinson ttyout); 2359f982db4aSGavin Atkinson r = command("XCUP"); 2360f982db4aSGavin Atkinson } 2361f982db4aSGavin Atkinson if (r == COMPLETE) { 2362f982db4aSGavin Atkinson dirchange = 1; 2363f982db4aSGavin Atkinson updateremotecwd(); 2364f982db4aSGavin Atkinson } 2365f982db4aSGavin Atkinson } 2366f982db4aSGavin Atkinson 2367f982db4aSGavin Atkinson /* 2368f982db4aSGavin Atkinson * Restart transfer at specific point 2369f982db4aSGavin Atkinson */ 2370f982db4aSGavin Atkinson void 2371f982db4aSGavin Atkinson restart(int argc, char *argv[]) 2372f982db4aSGavin Atkinson { 2373f982db4aSGavin Atkinson 2374f982db4aSGavin Atkinson if (argc == 0 || argc > 2) { 2375cc361f65SGavin Atkinson UPRINTF("usage: %s [restart-point]\n", argv[0]); 2376f982db4aSGavin Atkinson code = -1; 2377f982db4aSGavin Atkinson return; 2378f982db4aSGavin Atkinson } 2379f982db4aSGavin Atkinson if (! features[FEAT_REST_STREAM]) { 2380f982db4aSGavin Atkinson fprintf(ttyout, 2381f982db4aSGavin Atkinson "Restart is not supported by the remote server.\n"); 2382f982db4aSGavin Atkinson return; 2383f982db4aSGavin Atkinson } 2384f982db4aSGavin Atkinson if (argc == 2) { 2385f982db4aSGavin Atkinson off_t rp; 2386f982db4aSGavin Atkinson char *ep; 2387f982db4aSGavin Atkinson 2388f982db4aSGavin Atkinson rp = STRTOLL(argv[1], &ep, 10); 2389f982db4aSGavin Atkinson if (rp < 0 || *ep != '\0') 2390f982db4aSGavin Atkinson fprintf(ttyout, "restart: Invalid offset `%s'\n", 2391f982db4aSGavin Atkinson argv[1]); 2392f982db4aSGavin Atkinson else 2393f982db4aSGavin Atkinson restart_point = rp; 2394f982db4aSGavin Atkinson } 2395f982db4aSGavin Atkinson if (restart_point == 0) 2396f982db4aSGavin Atkinson fputs("No restart point defined.\n", ttyout); 2397f982db4aSGavin Atkinson else 2398f982db4aSGavin Atkinson fprintf(ttyout, 2399f982db4aSGavin Atkinson "Restarting at " LLF " for next get, put or append\n", 2400f982db4aSGavin Atkinson (LLT)restart_point); 2401f982db4aSGavin Atkinson } 2402f982db4aSGavin Atkinson 2403f982db4aSGavin Atkinson /* 2404f982db4aSGavin Atkinson * Show remote system type 2405f982db4aSGavin Atkinson */ 2406f982db4aSGavin Atkinson void 2407f982db4aSGavin Atkinson syst(int argc, char *argv[]) 2408f982db4aSGavin Atkinson { 2409f982db4aSGavin Atkinson int oldverbose = verbose; 2410f982db4aSGavin Atkinson 2411f982db4aSGavin Atkinson if (argc == 0) { 2412cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 2413f982db4aSGavin Atkinson code = -1; 2414f982db4aSGavin Atkinson return; 2415f982db4aSGavin Atkinson } 2416f982db4aSGavin Atkinson verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2417f982db4aSGavin Atkinson (void)command("SYST"); 2418f982db4aSGavin Atkinson verbose = oldverbose; 2419f982db4aSGavin Atkinson } 2420f982db4aSGavin Atkinson 2421f982db4aSGavin Atkinson void 2422f982db4aSGavin Atkinson macdef(int argc, char *argv[]) 2423f982db4aSGavin Atkinson { 2424f982db4aSGavin Atkinson char *tmp; 2425f982db4aSGavin Atkinson int c; 2426f982db4aSGavin Atkinson 2427f982db4aSGavin Atkinson if (argc == 0) 2428f982db4aSGavin Atkinson goto usage; 2429f982db4aSGavin Atkinson if (macnum == 16) { 2430f982db4aSGavin Atkinson fputs("Limit of 16 macros have already been defined.\n", 2431f982db4aSGavin Atkinson ttyout); 2432f982db4aSGavin Atkinson code = -1; 2433f982db4aSGavin Atkinson return; 2434f982db4aSGavin Atkinson } 2435f982db4aSGavin Atkinson if ((argc < 2 && !another(&argc, &argv, "macro name")) || argc > 2) { 2436f982db4aSGavin Atkinson usage: 2437cc361f65SGavin Atkinson UPRINTF("usage: %s macro_name\n", argv[0]); 2438f982db4aSGavin Atkinson code = -1; 2439f982db4aSGavin Atkinson return; 2440f982db4aSGavin Atkinson } 2441f982db4aSGavin Atkinson if (interactive) 2442f982db4aSGavin Atkinson fputs( 2443f982db4aSGavin Atkinson "Enter macro line by line, terminating it with a null line.\n", 2444f982db4aSGavin Atkinson ttyout); 2445f982db4aSGavin Atkinson (void)strlcpy(macros[macnum].mac_name, argv[1], 2446f982db4aSGavin Atkinson sizeof(macros[macnum].mac_name)); 2447f982db4aSGavin Atkinson if (macnum == 0) 2448f982db4aSGavin Atkinson macros[macnum].mac_start = macbuf; 2449f982db4aSGavin Atkinson else 2450f982db4aSGavin Atkinson macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 2451f982db4aSGavin Atkinson tmp = macros[macnum].mac_start; 2452f982db4aSGavin Atkinson while (tmp != macbuf+4096) { 2453f982db4aSGavin Atkinson if ((c = getchar()) == EOF) { 2454f982db4aSGavin Atkinson fputs("macdef: end of file encountered.\n", ttyout); 2455f982db4aSGavin Atkinson code = -1; 2456f982db4aSGavin Atkinson return; 2457f982db4aSGavin Atkinson } 2458f982db4aSGavin Atkinson if ((*tmp = c) == '\n') { 2459f982db4aSGavin Atkinson if (tmp == macros[macnum].mac_start) { 2460f982db4aSGavin Atkinson macros[macnum++].mac_end = tmp; 2461f982db4aSGavin Atkinson code = 0; 2462f982db4aSGavin Atkinson return; 2463f982db4aSGavin Atkinson } 2464f982db4aSGavin Atkinson if (*(tmp-1) == '\0') { 2465f982db4aSGavin Atkinson macros[macnum++].mac_end = tmp - 1; 2466f982db4aSGavin Atkinson code = 0; 2467f982db4aSGavin Atkinson return; 2468f982db4aSGavin Atkinson } 2469f982db4aSGavin Atkinson *tmp = '\0'; 2470f982db4aSGavin Atkinson } 2471f982db4aSGavin Atkinson tmp++; 2472f982db4aSGavin Atkinson } 2473f982db4aSGavin Atkinson while (1) { 2474f982db4aSGavin Atkinson while ((c = getchar()) != '\n' && c != EOF) 2475f982db4aSGavin Atkinson /* LOOP */; 2476f982db4aSGavin Atkinson if (c == EOF || getchar() == '\n') { 2477f982db4aSGavin Atkinson fputs("Macro not defined - 4K buffer exceeded.\n", 2478f982db4aSGavin Atkinson ttyout); 2479f982db4aSGavin Atkinson code = -1; 2480f982db4aSGavin Atkinson return; 2481f982db4aSGavin Atkinson } 2482f982db4aSGavin Atkinson } 2483f982db4aSGavin Atkinson } 2484f982db4aSGavin Atkinson 2485f982db4aSGavin Atkinson /* 2486f982db4aSGavin Atkinson * Get size of file on remote machine 2487f982db4aSGavin Atkinson */ 2488f982db4aSGavin Atkinson void 2489f982db4aSGavin Atkinson sizecmd(int argc, char *argv[]) 2490f982db4aSGavin Atkinson { 2491f982db4aSGavin Atkinson off_t size; 2492f982db4aSGavin Atkinson 2493f982db4aSGavin Atkinson if (argc == 0 || argc > 2 || 2494f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2495cc361f65SGavin Atkinson UPRINTF("usage: %s remote-file\n", argv[0]); 2496f982db4aSGavin Atkinson code = -1; 2497f982db4aSGavin Atkinson return; 2498f982db4aSGavin Atkinson } 2499f982db4aSGavin Atkinson size = remotesize(argv[1], 1); 2500f982db4aSGavin Atkinson if (size != -1) 2501f982db4aSGavin Atkinson fprintf(ttyout, 2502f982db4aSGavin Atkinson "%s\t" LLF "\n", argv[1], (LLT)size); 2503f982db4aSGavin Atkinson code = (size > 0); 2504f982db4aSGavin Atkinson } 2505f982db4aSGavin Atkinson 2506f982db4aSGavin Atkinson /* 2507f982db4aSGavin Atkinson * Get last modification time of file on remote machine 2508f982db4aSGavin Atkinson */ 2509f982db4aSGavin Atkinson void 2510f982db4aSGavin Atkinson modtime(int argc, char *argv[]) 2511f982db4aSGavin Atkinson { 2512f982db4aSGavin Atkinson time_t mtime; 2513f982db4aSGavin Atkinson 2514f982db4aSGavin Atkinson if (argc == 0 || argc > 2 || 2515f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2516cc361f65SGavin Atkinson UPRINTF("usage: %s remote-file\n", argv[0]); 2517f982db4aSGavin Atkinson code = -1; 2518f982db4aSGavin Atkinson return; 2519f982db4aSGavin Atkinson } 2520f982db4aSGavin Atkinson mtime = remotemodtime(argv[1], 1); 2521f982db4aSGavin Atkinson if (mtime != -1) 2522cc361f65SGavin Atkinson fprintf(ttyout, "%s\t%s", argv[1], 2523cc361f65SGavin Atkinson rfc2822time(localtime(&mtime))); 2524f982db4aSGavin Atkinson code = (mtime > 0); 2525f982db4aSGavin Atkinson } 2526f982db4aSGavin Atkinson 2527f982db4aSGavin Atkinson /* 2528f982db4aSGavin Atkinson * Show status on remote machine 2529f982db4aSGavin Atkinson */ 2530f982db4aSGavin Atkinson void 2531f982db4aSGavin Atkinson rmtstatus(int argc, char *argv[]) 2532f982db4aSGavin Atkinson { 2533f982db4aSGavin Atkinson 2534f982db4aSGavin Atkinson if (argc == 0) { 2535cc361f65SGavin Atkinson UPRINTF("usage: %s [remote-file]\n", argv[0]); 2536f982db4aSGavin Atkinson code = -1; 2537f982db4aSGavin Atkinson return; 2538f982db4aSGavin Atkinson } 2539f982db4aSGavin Atkinson COMMAND_1ARG(argc, argv, "STAT"); 2540f982db4aSGavin Atkinson } 2541f982db4aSGavin Atkinson 2542f982db4aSGavin Atkinson /* 2543f982db4aSGavin Atkinson * Get file if modtime is more recent than current file 2544f982db4aSGavin Atkinson */ 2545f982db4aSGavin Atkinson void 2546f982db4aSGavin Atkinson newer(int argc, char *argv[]) 2547f982db4aSGavin Atkinson { 2548f982db4aSGavin Atkinson 2549f982db4aSGavin Atkinson if (getit(argc, argv, -1, "w")) 2550f982db4aSGavin Atkinson fprintf(ttyout, 2551f982db4aSGavin Atkinson "Local file \"%s\" is newer than remote file \"%s\".\n", 2552f982db4aSGavin Atkinson argv[2], argv[1]); 2553f982db4aSGavin Atkinson } 2554f982db4aSGavin Atkinson 2555f982db4aSGavin Atkinson /* 2556f982db4aSGavin Atkinson * Display one local file through $PAGER. 2557f982db4aSGavin Atkinson */ 2558f982db4aSGavin Atkinson void 2559f982db4aSGavin Atkinson lpage(int argc, char *argv[]) 2560f982db4aSGavin Atkinson { 2561cc361f65SGavin Atkinson size_t len; 2562cc361f65SGavin Atkinson const char *p; 2563cc361f65SGavin Atkinson char *pager, *locfile; 2564f982db4aSGavin Atkinson 2565f982db4aSGavin Atkinson if (argc == 0 || argc > 2 || 2566f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "local-file"))) { 2567cc361f65SGavin Atkinson UPRINTF("usage: %s local-file\n", argv[0]); 2568f982db4aSGavin Atkinson code = -1; 2569f982db4aSGavin Atkinson return; 2570f982db4aSGavin Atkinson } 2571f982db4aSGavin Atkinson if ((locfile = globulize(argv[1])) == NULL) { 2572f982db4aSGavin Atkinson code = -1; 2573f982db4aSGavin Atkinson return; 2574f982db4aSGavin Atkinson } 2575f982db4aSGavin Atkinson p = getoptionvalue("pager"); 2576f982db4aSGavin Atkinson if (EMPTYSTRING(p)) 2577f982db4aSGavin Atkinson p = DEFAULTPAGER; 2578f982db4aSGavin Atkinson len = strlen(p) + strlen(locfile) + 2; 2579cc361f65SGavin Atkinson pager = ftp_malloc(len); 2580f982db4aSGavin Atkinson (void)strlcpy(pager, p, len); 2581f982db4aSGavin Atkinson (void)strlcat(pager, " ", len); 2582f982db4aSGavin Atkinson (void)strlcat(pager, locfile, len); 2583f982db4aSGavin Atkinson system(pager); 2584f982db4aSGavin Atkinson code = 0; 2585f982db4aSGavin Atkinson (void)free(pager); 2586f982db4aSGavin Atkinson (void)free(locfile); 2587f982db4aSGavin Atkinson } 2588f982db4aSGavin Atkinson 2589f982db4aSGavin Atkinson /* 2590f982db4aSGavin Atkinson * Display one remote file through $PAGER. 2591f982db4aSGavin Atkinson */ 2592f982db4aSGavin Atkinson void 2593f982db4aSGavin Atkinson page(int argc, char *argv[]) 2594f982db4aSGavin Atkinson { 2595cc361f65SGavin Atkinson int ohash, orestart_point, overbose; 2596cc361f65SGavin Atkinson size_t len; 2597cc361f65SGavin Atkinson const char *p; 2598cc361f65SGavin Atkinson char *pager; 2599f982db4aSGavin Atkinson 2600f982db4aSGavin Atkinson if (argc == 0 || argc > 2 || 2601f982db4aSGavin Atkinson (argc == 1 && !another(&argc, &argv, "remote-file"))) { 2602cc361f65SGavin Atkinson UPRINTF("usage: %s remote-file\n", argv[0]); 2603f982db4aSGavin Atkinson code = -1; 2604f982db4aSGavin Atkinson return; 2605f982db4aSGavin Atkinson } 2606f982db4aSGavin Atkinson p = getoptionvalue("pager"); 2607f982db4aSGavin Atkinson if (EMPTYSTRING(p)) 2608f982db4aSGavin Atkinson p = DEFAULTPAGER; 2609f982db4aSGavin Atkinson len = strlen(p) + 2; 2610cc361f65SGavin Atkinson pager = ftp_malloc(len); 2611f982db4aSGavin Atkinson pager[0] = '|'; 2612f982db4aSGavin Atkinson (void)strlcpy(pager + 1, p, len - 1); 2613f982db4aSGavin Atkinson 2614f982db4aSGavin Atkinson ohash = hash; 2615f982db4aSGavin Atkinson orestart_point = restart_point; 2616f982db4aSGavin Atkinson overbose = verbose; 2617f982db4aSGavin Atkinson hash = restart_point = verbose = 0; 2618f982db4aSGavin Atkinson recvrequest("RETR", pager, argv[1], "r+", 1, 0); 2619f982db4aSGavin Atkinson hash = ohash; 2620f982db4aSGavin Atkinson restart_point = orestart_point; 2621f982db4aSGavin Atkinson verbose = overbose; 2622f982db4aSGavin Atkinson (void)free(pager); 2623f982db4aSGavin Atkinson } 2624f982db4aSGavin Atkinson 2625f982db4aSGavin Atkinson /* 2626f982db4aSGavin Atkinson * Set the socket send or receive buffer size. 2627f982db4aSGavin Atkinson */ 2628f982db4aSGavin Atkinson void 2629f982db4aSGavin Atkinson setxferbuf(int argc, char *argv[]) 2630f982db4aSGavin Atkinson { 2631f982db4aSGavin Atkinson int size, dir; 2632f982db4aSGavin Atkinson 2633f982db4aSGavin Atkinson if (argc != 2) { 2634f982db4aSGavin Atkinson usage: 2635cc361f65SGavin Atkinson UPRINTF("usage: %s size\n", argv[0]); 2636f982db4aSGavin Atkinson code = -1; 2637f982db4aSGavin Atkinson return; 2638f982db4aSGavin Atkinson } 2639f982db4aSGavin Atkinson if (strcasecmp(argv[0], "sndbuf") == 0) 2640f982db4aSGavin Atkinson dir = RATE_PUT; 2641f982db4aSGavin Atkinson else if (strcasecmp(argv[0], "rcvbuf") == 0) 2642f982db4aSGavin Atkinson dir = RATE_GET; 2643f982db4aSGavin Atkinson else if (strcasecmp(argv[0], "xferbuf") == 0) 2644f982db4aSGavin Atkinson dir = RATE_ALL; 2645f982db4aSGavin Atkinson else 2646f982db4aSGavin Atkinson goto usage; 2647f982db4aSGavin Atkinson 2648f982db4aSGavin Atkinson if ((size = strsuftoi(argv[1])) == -1) 2649f982db4aSGavin Atkinson goto usage; 2650f982db4aSGavin Atkinson 2651f982db4aSGavin Atkinson if (size == 0) { 2652f982db4aSGavin Atkinson fprintf(ttyout, "%s: size must be positive.\n", argv[0]); 2653f982db4aSGavin Atkinson goto usage; 2654f982db4aSGavin Atkinson } 2655f982db4aSGavin Atkinson 2656f982db4aSGavin Atkinson if (dir & RATE_PUT) 2657f982db4aSGavin Atkinson sndbuf_size = size; 2658f982db4aSGavin Atkinson if (dir & RATE_GET) 2659f982db4aSGavin Atkinson rcvbuf_size = size; 2660f982db4aSGavin Atkinson fprintf(ttyout, "Socket buffer sizes: send %d, receive %d.\n", 2661f982db4aSGavin Atkinson sndbuf_size, rcvbuf_size); 2662f982db4aSGavin Atkinson code = 0; 2663f982db4aSGavin Atkinson } 2664f982db4aSGavin Atkinson 2665f982db4aSGavin Atkinson /* 2666f982db4aSGavin Atkinson * Set or display options (defaults are provided by various env vars) 2667f982db4aSGavin Atkinson */ 2668f982db4aSGavin Atkinson void 2669f982db4aSGavin Atkinson setoption(int argc, char *argv[]) 2670f982db4aSGavin Atkinson { 2671f982db4aSGavin Atkinson struct option *o; 2672f982db4aSGavin Atkinson 2673f982db4aSGavin Atkinson code = -1; 2674f982db4aSGavin Atkinson if (argc == 0 || (argc != 1 && argc != 3)) { 2675cc361f65SGavin Atkinson UPRINTF("usage: %s [option value]\n", argv[0]); 2676f982db4aSGavin Atkinson return; 2677f982db4aSGavin Atkinson } 2678f982db4aSGavin Atkinson 2679f982db4aSGavin Atkinson #define OPTIONINDENT ((int) sizeof("http_proxy")) 2680f982db4aSGavin Atkinson if (argc == 1) { 2681f982db4aSGavin Atkinson for (o = optiontab; o->name != NULL; o++) { 2682f982db4aSGavin Atkinson fprintf(ttyout, "%-*s\t%s\n", OPTIONINDENT, 2683f982db4aSGavin Atkinson o->name, o->value ? o->value : ""); 2684f982db4aSGavin Atkinson } 2685f982db4aSGavin Atkinson } else { 2686cc361f65SGavin Atkinson set_option(argv[1], argv[2], 1); 2687cc361f65SGavin Atkinson } 2688cc361f65SGavin Atkinson code = 0; 2689cc361f65SGavin Atkinson } 2690cc361f65SGavin Atkinson 2691cc361f65SGavin Atkinson void 2692cc361f65SGavin Atkinson set_option(const char * option, const char * value, int doverbose) 2693cc361f65SGavin Atkinson { 2694cc361f65SGavin Atkinson struct option *o; 2695cc361f65SGavin Atkinson 2696cc361f65SGavin Atkinson o = getoption(option); 2697f982db4aSGavin Atkinson if (o == NULL) { 2698cc361f65SGavin Atkinson fprintf(ttyout, "No such option `%s'.\n", option); 2699f982db4aSGavin Atkinson return; 2700f982db4aSGavin Atkinson } 2701f982db4aSGavin Atkinson FREEPTR(o->value); 2702cc361f65SGavin Atkinson o->value = ftp_strdup(value); 2703cc361f65SGavin Atkinson if (verbose && doverbose) 2704f982db4aSGavin Atkinson fprintf(ttyout, "Setting `%s' to `%s'.\n", 2705f982db4aSGavin Atkinson o->name, o->value); 2706f982db4aSGavin Atkinson } 2707f982db4aSGavin Atkinson 2708f982db4aSGavin Atkinson /* 2709f982db4aSGavin Atkinson * Unset an option 2710f982db4aSGavin Atkinson */ 2711f982db4aSGavin Atkinson void 2712f982db4aSGavin Atkinson unsetoption(int argc, char *argv[]) 2713f982db4aSGavin Atkinson { 2714f982db4aSGavin Atkinson struct option *o; 2715f982db4aSGavin Atkinson 2716f982db4aSGavin Atkinson code = -1; 2717f982db4aSGavin Atkinson if (argc == 0 || argc != 2) { 2718cc361f65SGavin Atkinson UPRINTF("usage: %s option\n", argv[0]); 2719f982db4aSGavin Atkinson return; 2720f982db4aSGavin Atkinson } 2721f982db4aSGavin Atkinson 2722f982db4aSGavin Atkinson o = getoption(argv[1]); 2723f982db4aSGavin Atkinson if (o == NULL) { 2724f982db4aSGavin Atkinson fprintf(ttyout, "No such option `%s'.\n", argv[1]); 2725f982db4aSGavin Atkinson return; 2726f982db4aSGavin Atkinson } 2727f982db4aSGavin Atkinson FREEPTR(o->value); 2728f982db4aSGavin Atkinson fprintf(ttyout, "Unsetting `%s'.\n", o->name); 2729f982db4aSGavin Atkinson code = 0; 2730f982db4aSGavin Atkinson } 2731f982db4aSGavin Atkinson 2732f982db4aSGavin Atkinson /* 2733f982db4aSGavin Atkinson * Display features supported by the remote host. 2734f982db4aSGavin Atkinson */ 2735f982db4aSGavin Atkinson void 2736f982db4aSGavin Atkinson feat(int argc, char *argv[]) 2737f982db4aSGavin Atkinson { 2738f982db4aSGavin Atkinson int oldverbose = verbose; 2739f982db4aSGavin Atkinson 2740f982db4aSGavin Atkinson if (argc == 0) { 2741cc361f65SGavin Atkinson UPRINTF("usage: %s\n", argv[0]); 2742f982db4aSGavin Atkinson code = -1; 2743f982db4aSGavin Atkinson return; 2744f982db4aSGavin Atkinson } 2745f982db4aSGavin Atkinson if (! features[FEAT_FEAT]) { 2746f982db4aSGavin Atkinson fprintf(ttyout, 2747f982db4aSGavin Atkinson "FEAT is not supported by the remote server.\n"); 2748f982db4aSGavin Atkinson return; 2749f982db4aSGavin Atkinson } 2750f982db4aSGavin Atkinson verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2751f982db4aSGavin Atkinson (void)command("FEAT"); 2752f982db4aSGavin Atkinson verbose = oldverbose; 2753f982db4aSGavin Atkinson } 2754f982db4aSGavin Atkinson 2755f982db4aSGavin Atkinson void 2756f982db4aSGavin Atkinson mlst(int argc, char *argv[]) 2757f982db4aSGavin Atkinson { 2758f982db4aSGavin Atkinson int oldverbose = verbose; 2759f982db4aSGavin Atkinson 2760f982db4aSGavin Atkinson if (argc < 1 || argc > 2) { 2761cc361f65SGavin Atkinson UPRINTF("usage: %s [remote-path]\n", argv[0]); 2762f982db4aSGavin Atkinson code = -1; 2763f982db4aSGavin Atkinson return; 2764f982db4aSGavin Atkinson } 2765f982db4aSGavin Atkinson if (! features[FEAT_MLST]) { 2766f982db4aSGavin Atkinson fprintf(ttyout, 2767f982db4aSGavin Atkinson "MLST is not supported by the remote server.\n"); 2768f982db4aSGavin Atkinson return; 2769f982db4aSGavin Atkinson } 2770f982db4aSGavin Atkinson verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2771f982db4aSGavin Atkinson COMMAND_1ARG(argc, argv, "MLST"); 2772f982db4aSGavin Atkinson verbose = oldverbose; 2773f982db4aSGavin Atkinson } 2774f982db4aSGavin Atkinson 2775f982db4aSGavin Atkinson void 2776f982db4aSGavin Atkinson opts(int argc, char *argv[]) 2777f982db4aSGavin Atkinson { 2778f982db4aSGavin Atkinson int oldverbose = verbose; 2779f982db4aSGavin Atkinson 2780f982db4aSGavin Atkinson if (argc < 2 || argc > 3) { 2781cc361f65SGavin Atkinson UPRINTF("usage: %s command [options]\n", argv[0]); 2782f982db4aSGavin Atkinson code = -1; 2783f982db4aSGavin Atkinson return; 2784f982db4aSGavin Atkinson } 2785f982db4aSGavin Atkinson if (! features[FEAT_FEAT]) { 2786f982db4aSGavin Atkinson fprintf(ttyout, 2787f982db4aSGavin Atkinson "OPTS is not supported by the remote server.\n"); 2788f982db4aSGavin Atkinson return; 2789f982db4aSGavin Atkinson } 2790f982db4aSGavin Atkinson verbose = 1; /* If we aren't verbose, this doesn't do anything! */ 2791f982db4aSGavin Atkinson if (argc == 2) 2792f982db4aSGavin Atkinson command("OPTS %s", argv[1]); 2793f982db4aSGavin Atkinson else 2794f982db4aSGavin Atkinson command("OPTS %s %s", argv[1], argv[2]); 2795f982db4aSGavin Atkinson verbose = oldverbose; 2796f982db4aSGavin Atkinson } 2797