155682Smarkm/* 255682Smarkm * Copyright (c) 1985, 1989, 1993, 1994 355682Smarkm * The Regents of the University of California. All rights reserved. 455682Smarkm * 555682Smarkm * Redistribution and use in source and binary forms, with or without 655682Smarkm * modification, are permitted provided that the following conditions 755682Smarkm * are met: 855682Smarkm * 1. Redistributions of source code must retain the above copyright 955682Smarkm * notice, this list of conditions and the following disclaimer. 1055682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer in the 1255682Smarkm * documentation and/or other materials provided with the distribution. 1355682Smarkm * 3. All advertising materials mentioning features or use of this software 1455682Smarkm * must display the following acknowledgement: 1555682Smarkm * This product includes software developed by the University of 1655682Smarkm * California, Berkeley and its contributors. 1755682Smarkm * 4. Neither the name of the University nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm/* 3555682Smarkm * FTP User Program -- Command Routines. 3655682Smarkm */ 3755682Smarkm 3855682Smarkm#include "ftp_locl.h" 39233294SstasRCSID("$Id$"); 4055682Smarkm 4155682Smarkmtypedef void (*sighand)(int); 4255682Smarkm 4355682Smarkmjmp_buf jabort; 4455682Smarkmchar *mname; 4555682Smarkmchar *home = "/"; 4655682Smarkm 4755682Smarkm/* 4855682Smarkm * `Another' gets another argument, and stores the new argc and argv. 4955682Smarkm * It reverts to the top level (via main.c's intr()) on EOF/error. 5055682Smarkm * 5155682Smarkm * Returns false if no new arguments have been added. 5255682Smarkm */ 5355682Smarkmint 5455682Smarkmanother(int *pargc, char ***pargv, char *prompt) 5555682Smarkm{ 5655682Smarkm int len = strlen(line), ret; 5755682Smarkm 5855682Smarkm if (len >= sizeof(line) - 3) { 5955682Smarkm printf("sorry, arguments too long\n"); 6055682Smarkm intr(0); 6155682Smarkm } 6255682Smarkm printf("(%s) ", prompt); 6355682Smarkm line[len++] = ' '; 6455682Smarkm if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) 6555682Smarkm intr(0); 6655682Smarkm len += strlen(&line[len]); 6755682Smarkm if (len > 0 && line[len - 1] == '\n') 6855682Smarkm line[len - 1] = '\0'; 6955682Smarkm makeargv(); 7055682Smarkm ret = margc > *pargc; 7155682Smarkm *pargc = margc; 7255682Smarkm *pargv = margv; 7355682Smarkm return (ret); 7455682Smarkm} 7555682Smarkm 7655682Smarkm/* 7755682Smarkm * Connect to peer server and 7855682Smarkm * auto-login, if possible. 7955682Smarkm */ 8055682Smarkmvoid 8155682Smarkmsetpeer(int argc, char **argv) 8255682Smarkm{ 8355682Smarkm char *host; 8478527Sassar u_short port; 8555682Smarkm struct servent *sp; 8655682Smarkm 8755682Smarkm if (connected) { 8855682Smarkm printf("Already connected to %s, use close first.\n", 8955682Smarkm hostname); 9055682Smarkm code = -1; 9155682Smarkm return; 9255682Smarkm } 9355682Smarkm if (argc < 2) 9455682Smarkm another(&argc, &argv, "to"); 9555682Smarkm if (argc < 2 || argc > 3) { 9655682Smarkm printf("usage: %s host-name [port]\n", argv[0]); 9755682Smarkm code = -1; 9855682Smarkm return; 9955682Smarkm } 10055682Smarkm sp = getservbyname("ftp", "tcp"); 10155682Smarkm if (sp == NULL) 10255682Smarkm errx(1, "You bastard. You removed ftp/tcp from services"); 10355682Smarkm port = sp->s_port; 10455682Smarkm if (argc > 2) { 10578527Sassar sp = getservbyname(argv[2], "tcp"); 10678527Sassar if (sp != NULL) { 10778527Sassar port = sp->s_port; 10878527Sassar } else { 10978527Sassar char *ep; 11078527Sassar 11178527Sassar port = strtol(argv[2], &ep, 0); 11278527Sassar if (argv[2] == ep) { 11378527Sassar printf("%s: bad port number-- %s\n", 11478527Sassar argv[1], argv[2]); 11578527Sassar printf ("usage: %s host-name [port]\n", 11678527Sassar argv[0]); 11778527Sassar code = -1; 11878527Sassar return; 11978527Sassar } 12078527Sassar port = htons(port); 12155682Smarkm } 12255682Smarkm } 12355682Smarkm host = hookup(argv[1], port); 12455682Smarkm if (host) { 12555682Smarkm int overbose; 12655682Smarkm 12755682Smarkm connected = 1; 12855682Smarkm /* 12955682Smarkm * Set up defaults for FTP. 13055682Smarkm */ 13155682Smarkm strlcpy(typename, "ascii", sizeof(typename)); 13255682Smarkm type = TYPE_A; 13355682Smarkm curtype = TYPE_A; 13455682Smarkm strlcpy(formname, "non-print", sizeof(formname)); 13555682Smarkm form = FORM_N; 13655682Smarkm strlcpy(modename, "stream", sizeof(modename)); 13755682Smarkm mode = MODE_S; 13855682Smarkm strlcpy(structname, "file", sizeof(structname)); 13955682Smarkm stru = STRU_F; 14055682Smarkm strlcpy(bytename, "8", sizeof(bytename)); 14155682Smarkm bytesize = 8; 14255682Smarkm if (autologin) 14355682Smarkm login(argv[1]); 14455682Smarkm 145178825Sdfr#if (defined(unix) || defined(__unix__) || defined(__unix) || defined(_AIX) || defined(_CRAY) || defined(__NetBSD__) || defined(__APPLE__)) && NBBY == 8 14655682Smarkm/* 14755682Smarkm * this ifdef is to keep someone form "porting" this to an incompatible 14855682Smarkm * system and not checking this out. This way they have to think about it. 14955682Smarkm */ 15055682Smarkm overbose = verbose; 15155682Smarkm if (debug == 0) 15255682Smarkm verbose = -1; 153178825Sdfr if (command("SYST") == COMPLETE && overbose && strlen(reply_string) > 4) { 154178825Sdfr char *cp, *p; 155178825Sdfr 156178825Sdfr cp = strdup(reply_string + 4); 15755682Smarkm if (cp == NULL) 158178825Sdfr errx(1, "strdup: out of memory"); 159178825Sdfr p = strchr(cp, ' '); 160178825Sdfr if (p == NULL) 161178825Sdfr p = strchr(cp, '\r'); 162178825Sdfr if (p) { 163178825Sdfr if (p[-1] == '.') 164178825Sdfr p--; 165178825Sdfr *p = '\0'; 16655682Smarkm } 16755682Smarkm 168178825Sdfr printf("Remote system type is %s.\n", cp); 169178825Sdfr free(cp); 17055682Smarkm } 17155682Smarkm if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { 17255682Smarkm if (proxy) 17355682Smarkm unix_proxy = 1; 17455682Smarkm else 17555682Smarkm unix_server = 1; 17655682Smarkm /* 17755682Smarkm * Set type to 0 (not specified by user), 17855682Smarkm * meaning binary by default, but don't bother 17955682Smarkm * telling server. We can use binary 18055682Smarkm * for text files unless changed by the user. 18155682Smarkm */ 18255682Smarkm type = 0; 18355682Smarkm strlcpy(typename, "binary", sizeof(typename)); 18455682Smarkm if (overbose) 18555682Smarkm printf("Using %s mode to transfer files.\n", 18655682Smarkm typename); 18755682Smarkm } else { 18855682Smarkm if (proxy) 18955682Smarkm unix_proxy = 0; 19055682Smarkm else 19155682Smarkm unix_server = 0; 192233294Sstas if (overbose && 19355682Smarkm !strncmp(reply_string, "215 TOPS20", 10)) 19455682Smarkm printf( 19555682Smarkm"Remember to set tenex mode when transfering binary files from this machine.\n"); 19655682Smarkm } 19755682Smarkm verbose = overbose; 19855682Smarkm#endif /* unix */ 19955682Smarkm } 20055682Smarkm} 20155682Smarkm 20255682Smarkmstruct types { 20355682Smarkm char *t_name; 20455682Smarkm char *t_mode; 20555682Smarkm int t_type; 20655682Smarkm char *t_arg; 20755682Smarkm} types[] = { 20855682Smarkm { "ascii", "A", TYPE_A, 0 }, 20955682Smarkm { "binary", "I", TYPE_I, 0 }, 21055682Smarkm { "image", "I", TYPE_I, 0 }, 21155682Smarkm { "ebcdic", "E", TYPE_E, 0 }, 21255682Smarkm { "tenex", "L", TYPE_L, bytename }, 21355682Smarkm { NULL } 21455682Smarkm}; 21555682Smarkm 21655682Smarkm/* 21755682Smarkm * Set transfer type. 21855682Smarkm */ 21955682Smarkmvoid 22055682Smarkmsettype(int argc, char **argv) 22155682Smarkm{ 22255682Smarkm struct types *p; 22355682Smarkm int comret; 22455682Smarkm 22555682Smarkm if (argc > 2) { 22655682Smarkm char *sep; 22755682Smarkm 22855682Smarkm printf("usage: %s [", argv[0]); 22955682Smarkm sep = " "; 23055682Smarkm for (p = types; p->t_name; p++) { 23155682Smarkm printf("%s%s", sep, p->t_name); 23255682Smarkm sep = " | "; 23355682Smarkm } 23455682Smarkm printf(" ]\n"); 23555682Smarkm code = -1; 23655682Smarkm return; 23755682Smarkm } 23855682Smarkm if (argc < 2) { 23955682Smarkm printf("Using %s mode to transfer files.\n", typename); 24055682Smarkm code = 0; 24155682Smarkm return; 24255682Smarkm } 24355682Smarkm for (p = types; p->t_name; p++) 24455682Smarkm if (strcmp(argv[1], p->t_name) == 0) 24555682Smarkm break; 24655682Smarkm if (p->t_name == 0) { 24755682Smarkm printf("%s: unknown mode\n", argv[1]); 24855682Smarkm code = -1; 24955682Smarkm return; 25055682Smarkm } 25155682Smarkm if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) 25255682Smarkm comret = command ("TYPE %s %s", p->t_mode, p->t_arg); 25355682Smarkm else 25455682Smarkm comret = command("TYPE %s", p->t_mode); 25555682Smarkm if (comret == COMPLETE) { 25655682Smarkm strlcpy(typename, p->t_name, sizeof(typename)); 25755682Smarkm curtype = type = p->t_type; 25855682Smarkm } 25955682Smarkm} 26055682Smarkm 26155682Smarkm/* 26255682Smarkm * Internal form of settype; changes current type in use with server 26355682Smarkm * without changing our notion of the type for data transfers. 26455682Smarkm * Used to change to and from ascii for listings. 26555682Smarkm */ 26655682Smarkmvoid 26755682Smarkmchangetype(int newtype, int show) 26855682Smarkm{ 26955682Smarkm struct types *p; 27055682Smarkm int comret, oldverbose = verbose; 27155682Smarkm 27255682Smarkm if (newtype == 0) 27355682Smarkm newtype = TYPE_I; 27455682Smarkm if (newtype == curtype) 27555682Smarkm return; 27655682Smarkm if (debug == 0 && show == 0) 27755682Smarkm verbose = 0; 27855682Smarkm for (p = types; p->t_name; p++) 27955682Smarkm if (newtype == p->t_type) 28055682Smarkm break; 28155682Smarkm if (p->t_name == 0) { 28255682Smarkm printf("ftp: internal error: unknown type %d\n", newtype); 28355682Smarkm return; 28455682Smarkm } 28555682Smarkm if (newtype == TYPE_L && bytename[0] != '\0') 28655682Smarkm comret = command("TYPE %s %s", p->t_mode, bytename); 28755682Smarkm else 28855682Smarkm comret = command("TYPE %s", p->t_mode); 28955682Smarkm if (comret == COMPLETE) 29055682Smarkm curtype = newtype; 29155682Smarkm verbose = oldverbose; 29255682Smarkm} 29355682Smarkm 29455682Smarkmchar *stype[] = { 29555682Smarkm "type", 29655682Smarkm "", 29755682Smarkm 0 29855682Smarkm}; 29955682Smarkm 30055682Smarkm/* 30155682Smarkm * Set binary transfer type. 30255682Smarkm */ 30355682Smarkm/*VARARGS*/ 30455682Smarkmvoid 30555682Smarkmsetbinary(int argc, char **argv) 30655682Smarkm{ 30755682Smarkm 30855682Smarkm stype[1] = "binary"; 30955682Smarkm settype(2, stype); 31055682Smarkm} 31155682Smarkm 31255682Smarkm/* 31355682Smarkm * Set ascii transfer type. 31455682Smarkm */ 31555682Smarkm/*VARARGS*/ 31655682Smarkmvoid 31755682Smarkmsetascii(int argc, char **argv) 31855682Smarkm{ 31955682Smarkm 32055682Smarkm stype[1] = "ascii"; 32155682Smarkm settype(2, stype); 32255682Smarkm} 32355682Smarkm 32455682Smarkm/* 32555682Smarkm * Set tenex transfer type. 32655682Smarkm */ 32755682Smarkm/*VARARGS*/ 32855682Smarkmvoid 32955682Smarkmsettenex(int argc, char **argv) 33055682Smarkm{ 33155682Smarkm 33255682Smarkm stype[1] = "tenex"; 33355682Smarkm settype(2, stype); 33455682Smarkm} 33555682Smarkm 33655682Smarkm/* 33755682Smarkm * Set file transfer mode. 33855682Smarkm */ 33955682Smarkm/*ARGSUSED*/ 34055682Smarkmvoid 34155682Smarkmsetftmode(int argc, char **argv) 34255682Smarkm{ 34355682Smarkm 34455682Smarkm printf("We only support %s mode, sorry.\n", modename); 34555682Smarkm code = -1; 34655682Smarkm} 34755682Smarkm 34855682Smarkm/* 34955682Smarkm * Set file transfer format. 35055682Smarkm */ 35155682Smarkm/*ARGSUSED*/ 35255682Smarkmvoid 35355682Smarkmsetform(int argc, char **argv) 35455682Smarkm{ 35555682Smarkm 35655682Smarkm printf("We only support %s format, sorry.\n", formname); 35755682Smarkm code = -1; 35855682Smarkm} 35955682Smarkm 36055682Smarkm/* 36155682Smarkm * Set file transfer structure. 36255682Smarkm */ 36355682Smarkm/*ARGSUSED*/ 36455682Smarkmvoid 36555682Smarkmsetstruct(int argc, char **argv) 36655682Smarkm{ 36755682Smarkm 36855682Smarkm printf("We only support %s structure, sorry.\n", structname); 36955682Smarkm code = -1; 37055682Smarkm} 37155682Smarkm 37255682Smarkm/* 37355682Smarkm * Send a single file. 37455682Smarkm */ 37555682Smarkmvoid 37655682Smarkmput(int argc, char **argv) 37755682Smarkm{ 37855682Smarkm char *cmd; 37955682Smarkm int loc = 0; 38055682Smarkm char *oldargv1, *oldargv2; 38155682Smarkm 38255682Smarkm if (argc == 2) { 38355682Smarkm argc++; 38455682Smarkm argv[2] = argv[1]; 38555682Smarkm loc++; 38655682Smarkm } 38755682Smarkm if (argc < 2 && !another(&argc, &argv, "local-file")) 38855682Smarkm goto usage; 38955682Smarkm if (argc < 3 && !another(&argc, &argv, "remote-file")) { 39055682Smarkmusage: 39155682Smarkm printf("usage: %s local-file remote-file\n", argv[0]); 39255682Smarkm code = -1; 39355682Smarkm return; 39455682Smarkm } 39555682Smarkm oldargv1 = argv[1]; 39655682Smarkm oldargv2 = argv[2]; 39755682Smarkm if (!globulize(&argv[1])) { 39855682Smarkm code = -1; 39955682Smarkm return; 40055682Smarkm } 40155682Smarkm /* 40255682Smarkm * If "globulize" modifies argv[1], and argv[2] is a copy of 40355682Smarkm * the old argv[1], make it a copy of the new argv[1]. 40455682Smarkm */ 40555682Smarkm if (argv[1] != oldargv1 && argv[2] == oldargv1) { 40655682Smarkm argv[2] = argv[1]; 40755682Smarkm } 40855682Smarkm cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); 40955682Smarkm if (loc && ntflag) { 41055682Smarkm argv[2] = dotrans(argv[2]); 41155682Smarkm } 41255682Smarkm if (loc && mapflag) { 41355682Smarkm argv[2] = domap(argv[2]); 41455682Smarkm } 41555682Smarkm sendrequest(cmd, argv[1], argv[2], 41655682Smarkm curtype == TYPE_I ? "rb" : "r", 41755682Smarkm argv[1] != oldargv1 || argv[2] != oldargv2); 41855682Smarkm} 41955682Smarkm 42055682Smarkm/* ARGSUSED */ 42155682Smarkmstatic RETSIGTYPE 42255682Smarkmmabort(int signo) 42355682Smarkm{ 42455682Smarkm int ointer; 42555682Smarkm 42655682Smarkm printf("\n"); 42755682Smarkm fflush(stdout); 42855682Smarkm if (mflag && fromatty) { 42955682Smarkm ointer = interactive; 43055682Smarkm interactive = 1; 43155682Smarkm if (confirm("Continue with", mname)) { 43255682Smarkm interactive = ointer; 43355682Smarkm longjmp(jabort,0); 43455682Smarkm } 43555682Smarkm interactive = ointer; 43655682Smarkm } 43755682Smarkm mflag = 0; 43855682Smarkm longjmp(jabort,0); 43955682Smarkm} 44055682Smarkm 44155682Smarkm/* 44255682Smarkm * Send multiple files. 44355682Smarkm */ 44455682Smarkmvoid 44555682Smarkmmput(int argc, char **argv) 44655682Smarkm{ 44755682Smarkm int i; 44872445Sassar RETSIGTYPE (*oldintr)(int); 44955682Smarkm int ointer; 45055682Smarkm char *tp; 45155682Smarkm 45255682Smarkm if (argc < 2 && !another(&argc, &argv, "local-files")) { 45355682Smarkm printf("usage: %s local-files\n", argv[0]); 45455682Smarkm code = -1; 45555682Smarkm return; 45655682Smarkm } 45755682Smarkm mname = argv[0]; 45855682Smarkm mflag = 1; 45955682Smarkm oldintr = signal(SIGINT, mabort); 46055682Smarkm setjmp(jabort); 46155682Smarkm if (proxy) { 46255682Smarkm char *cp, *tp2, tmpbuf[MaxPathLen]; 46355682Smarkm 46455682Smarkm while ((cp = remglob(argv,0)) != NULL) { 46555682Smarkm if (*cp == 0) { 46655682Smarkm mflag = 0; 46755682Smarkm continue; 46855682Smarkm } 46955682Smarkm if (mflag && confirm(argv[0], cp)) { 47055682Smarkm tp = cp; 47155682Smarkm if (mcase) { 47290926Snectar while (*tp && !islower((unsigned char)*tp)) { 47355682Smarkm tp++; 47455682Smarkm } 47555682Smarkm if (!*tp) { 47655682Smarkm tp = cp; 47755682Smarkm tp2 = tmpbuf; 47855682Smarkm while ((*tp2 = *tp) != '\0') { 47990926Snectar if (isupper((unsigned char)*tp2)) { 48055682Smarkm *tp2 = 'a' + *tp2 - 'A'; 48155682Smarkm } 48255682Smarkm tp++; 48355682Smarkm tp2++; 48455682Smarkm } 48555682Smarkm } 48655682Smarkm tp = tmpbuf; 48755682Smarkm } 48855682Smarkm if (ntflag) { 48955682Smarkm tp = dotrans(tp); 49055682Smarkm } 49155682Smarkm if (mapflag) { 49255682Smarkm tp = domap(tp); 49355682Smarkm } 49455682Smarkm sendrequest((sunique) ? "STOU" : "STOR", 49555682Smarkm cp, tp, 49655682Smarkm curtype == TYPE_I ? "rb" : "r", 49755682Smarkm cp != tp || !interactive); 49855682Smarkm if (!mflag && fromatty) { 49955682Smarkm ointer = interactive; 50055682Smarkm interactive = 1; 50155682Smarkm if (confirm("Continue with","mput")) { 50255682Smarkm mflag++; 50355682Smarkm } 50455682Smarkm interactive = ointer; 50555682Smarkm } 50655682Smarkm } 50755682Smarkm } 50855682Smarkm signal(SIGINT, oldintr); 50955682Smarkm mflag = 0; 51055682Smarkm return; 51155682Smarkm } 51255682Smarkm for (i = 1; i < argc; i++) { 51355682Smarkm char **cpp; 51455682Smarkm glob_t gl; 51555682Smarkm int flags; 51655682Smarkm 51755682Smarkm if (!doglob) { 51855682Smarkm if (mflag && confirm(argv[0], argv[i])) { 51955682Smarkm tp = (ntflag) ? dotrans(argv[i]) : argv[i]; 52055682Smarkm tp = (mapflag) ? domap(tp) : tp; 52155682Smarkm sendrequest((sunique) ? "STOU" : "STOR", 52255682Smarkm argv[i], 52355682Smarkm curtype == TYPE_I ? "rb" : "r", 52455682Smarkm tp, tp != argv[i] || !interactive); 52555682Smarkm if (!mflag && fromatty) { 52655682Smarkm ointer = interactive; 52755682Smarkm interactive = 1; 52855682Smarkm if (confirm("Continue with","mput")) { 52955682Smarkm mflag++; 53055682Smarkm } 53155682Smarkm interactive = ointer; 53255682Smarkm } 53355682Smarkm } 53455682Smarkm continue; 53555682Smarkm } 53655682Smarkm 53755682Smarkm memset(&gl, 0, sizeof(gl)); 53855682Smarkm flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 53955682Smarkm if (glob(argv[i], flags, NULL, &gl) || gl.gl_pathc == 0) { 54055682Smarkm warnx("%s: not found", argv[i]); 54155682Smarkm globfree(&gl); 54255682Smarkm continue; 54355682Smarkm } 54455682Smarkm for (cpp = gl.gl_pathv; cpp && *cpp != NULL; cpp++) { 54555682Smarkm if (mflag && confirm(argv[0], *cpp)) { 54655682Smarkm tp = (ntflag) ? dotrans(*cpp) : *cpp; 54755682Smarkm tp = (mapflag) ? domap(tp) : tp; 54855682Smarkm sendrequest((sunique) ? "STOU" : "STOR", 54955682Smarkm *cpp, tp, 55055682Smarkm curtype == TYPE_I ? "rb" : "r", 55155682Smarkm *cpp != tp || !interactive); 55255682Smarkm if (!mflag && fromatty) { 55355682Smarkm ointer = interactive; 55455682Smarkm interactive = 1; 55555682Smarkm if (confirm("Continue with","mput")) { 55655682Smarkm mflag++; 55755682Smarkm } 55855682Smarkm interactive = ointer; 55955682Smarkm } 56055682Smarkm } 56155682Smarkm } 56255682Smarkm globfree(&gl); 56355682Smarkm } 56455682Smarkm signal(SIGINT, oldintr); 56555682Smarkm mflag = 0; 56655682Smarkm} 56755682Smarkm 56855682Smarkmvoid 56955682Smarkmreget(int argc, char **argv) 57055682Smarkm{ 57155682Smarkm getit(argc, argv, 1, curtype == TYPE_I ? "r+wb" : "r+w"); 57255682Smarkm} 57355682Smarkm 57455682Smarkmvoid 57555682Smarkmget(int argc, char **argv) 57655682Smarkm{ 577178825Sdfr char *filemode; 57855682Smarkm 57972445Sassar if (restart_point) { 58055682Smarkm if (curtype == TYPE_I) 581178825Sdfr filemode = "r+wb"; 58255682Smarkm else 583178825Sdfr filemode = "r+w"; 58472445Sassar } else { 58555682Smarkm if (curtype == TYPE_I) 586178825Sdfr filemode = "wb"; 58755682Smarkm else 588178825Sdfr filemode = "w"; 58972445Sassar } 59055682Smarkm 591178825Sdfr getit(argc, argv, 0, filemode); 59255682Smarkm} 59355682Smarkm 59455682Smarkm/* 59555682Smarkm * Receive one file. 59655682Smarkm */ 59755682Smarkmint 598178825Sdfrgetit(int argc, char **argv, int restartit, char *filemode) 59955682Smarkm{ 60055682Smarkm int loc = 0; 60155682Smarkm int local_given = 1; 60255682Smarkm char *oldargv1, *oldargv2; 60355682Smarkm 60455682Smarkm if (argc == 2) { 60555682Smarkm argc++; 60655682Smarkm local_given = 0; 60755682Smarkm argv[2] = argv[1]; 60855682Smarkm loc++; 60955682Smarkm } 61055682Smarkm if ((argc < 2 && !another(&argc, &argv, "remote-file")) || 61155682Smarkm (argc < 3 && !another(&argc, &argv, "local-file"))) { 61255682Smarkm printf("usage: %s remote-file [ local-file ]\n", argv[0]); 61355682Smarkm code = -1; 61455682Smarkm return (0); 61555682Smarkm } 61655682Smarkm oldargv1 = argv[1]; 61755682Smarkm oldargv2 = argv[2]; 61855682Smarkm if (!globulize(&argv[2])) { 61955682Smarkm code = -1; 62055682Smarkm return (0); 62155682Smarkm } 62255682Smarkm if (loc && mcase) { 62355682Smarkm char *tp = argv[1], *tp2, tmpbuf[MaxPathLen]; 62455682Smarkm 62590926Snectar while (*tp && !islower((unsigned char)*tp)) { 62655682Smarkm tp++; 62755682Smarkm } 62855682Smarkm if (!*tp) { 62955682Smarkm tp = argv[2]; 63055682Smarkm tp2 = tmpbuf; 63155682Smarkm while ((*tp2 = *tp) != '\0') { 63290926Snectar if (isupper((unsigned char)*tp2)) { 63355682Smarkm *tp2 = 'a' + *tp2 - 'A'; 63455682Smarkm } 63555682Smarkm tp++; 63655682Smarkm tp2++; 63755682Smarkm } 63855682Smarkm argv[2] = tmpbuf; 63955682Smarkm } 64055682Smarkm } 64155682Smarkm if (loc && ntflag) 64255682Smarkm argv[2] = dotrans(argv[2]); 64355682Smarkm if (loc && mapflag) 64455682Smarkm argv[2] = domap(argv[2]); 64555682Smarkm if (restartit) { 64655682Smarkm struct stat stbuf; 64755682Smarkm int ret; 64855682Smarkm 64955682Smarkm ret = stat(argv[2], &stbuf); 65055682Smarkm if (restartit == 1) { 65155682Smarkm if (ret < 0) { 65255682Smarkm warn("local: %s", argv[2]); 65355682Smarkm return (0); 65455682Smarkm } 65555682Smarkm restart_point = stbuf.st_size; 65655682Smarkm } else if (ret == 0) { 65755682Smarkm int overbose; 65855682Smarkm int cmdret; 65955682Smarkm int yy, mo, day, hour, min, sec; 66055682Smarkm struct tm *tm; 66172445Sassar time_t mtime = stbuf.st_mtime; 66255682Smarkm 66355682Smarkm overbose = verbose; 66455682Smarkm if (debug == 0) 66555682Smarkm verbose = -1; 66655682Smarkm cmdret = command("MDTM %s", argv[1]); 66755682Smarkm verbose = overbose; 66855682Smarkm if (cmdret != COMPLETE) { 66955682Smarkm printf("%s\n", reply_string); 67055682Smarkm return (0); 67155682Smarkm } 67255682Smarkm if (sscanf(reply_string, 67355682Smarkm "%*s %04d%02d%02d%02d%02d%02d", 67455682Smarkm &yy, &mo, &day, &hour, &min, &sec) 67555682Smarkm != 6) { 67655682Smarkm printf ("bad MDTM result\n"); 67755682Smarkm return (0); 67855682Smarkm } 67955682Smarkm 68072445Sassar tm = gmtime(&mtime); 68155682Smarkm tm->tm_mon++; 68255682Smarkm tm->tm_year += 1900; 68355682Smarkm 68455682Smarkm if ((tm->tm_year > yy) || 685233294Sstas (tm->tm_year == yy && 68655682Smarkm tm->tm_mon > mo) || 687233294Sstas (tm->tm_mon == mo && 68855682Smarkm tm->tm_mday > day) || 689233294Sstas (tm->tm_mday == day && 69055682Smarkm tm->tm_hour > hour) || 691233294Sstas (tm->tm_hour == hour && 69255682Smarkm tm->tm_min > min) || 693233294Sstas (tm->tm_min == min && 69455682Smarkm tm->tm_sec > sec)) 69555682Smarkm return (1); 69655682Smarkm } 69755682Smarkm } 69855682Smarkm 699178825Sdfr recvrequest("RETR", argv[2], argv[1], filemode, 70055682Smarkm argv[1] != oldargv1 || argv[2] != oldargv2, local_given); 70155682Smarkm restart_point = 0; 70255682Smarkm return (0); 70355682Smarkm} 70455682Smarkm 70555682Smarkmstatic int 70655682Smarkmsuspicious_filename(const char *fn) 70755682Smarkm{ 70855682Smarkm return strstr(fn, "../") != NULL || *fn == '/'; 70955682Smarkm} 71055682Smarkm 71155682Smarkm/* 71255682Smarkm * Get multiple files. 71355682Smarkm */ 71455682Smarkmvoid 71555682Smarkmmget(int argc, char **argv) 71655682Smarkm{ 71755682Smarkm sighand oldintr; 71855682Smarkm int ch, ointer; 71955682Smarkm char *cp, *tp, *tp2, tmpbuf[MaxPathLen]; 72055682Smarkm 72155682Smarkm if (argc < 2 && !another(&argc, &argv, "remote-files")) { 72255682Smarkm printf("usage: %s remote-files\n", argv[0]); 72355682Smarkm code = -1; 72455682Smarkm return; 72555682Smarkm } 72655682Smarkm mname = argv[0]; 72755682Smarkm mflag = 1; 72855682Smarkm oldintr = signal(SIGINT, mabort); 72955682Smarkm setjmp(jabort); 73055682Smarkm while ((cp = remglob(argv,proxy)) != NULL) { 73155682Smarkm if (*cp == '\0') { 73255682Smarkm mflag = 0; 73355682Smarkm continue; 73455682Smarkm } 73555682Smarkm if (mflag && suspicious_filename(cp)) 73655682Smarkm printf("*** Suspicious filename: %s\n", cp); 73755682Smarkm if (mflag && confirm(argv[0], cp)) { 73855682Smarkm tp = cp; 73955682Smarkm if (mcase) { 740178825Sdfr for (tp2 = tmpbuf;(ch = (unsigned char)*tp++);) 74190926Snectar *tp2++ = tolower(ch); 74255682Smarkm *tp2 = '\0'; 74355682Smarkm tp = tmpbuf; 74455682Smarkm } 74555682Smarkm if (ntflag) { 74655682Smarkm tp = dotrans(tp); 74755682Smarkm } 74855682Smarkm if (mapflag) { 74955682Smarkm tp = domap(tp); 75055682Smarkm } 75155682Smarkm recvrequest("RETR", tp, cp, 75255682Smarkm curtype == TYPE_I ? "wb" : "w", 75355682Smarkm tp != cp || !interactive, 0); 75455682Smarkm if (!mflag && fromatty) { 75555682Smarkm ointer = interactive; 75655682Smarkm interactive = 1; 75755682Smarkm if (confirm("Continue with","mget")) { 75855682Smarkm mflag++; 75955682Smarkm } 76055682Smarkm interactive = ointer; 76155682Smarkm } 76255682Smarkm } 76355682Smarkm } 76455682Smarkm signal(SIGINT,oldintr); 76555682Smarkm mflag = 0; 76655682Smarkm} 76755682Smarkm 76855682Smarkmchar * 76955682Smarkmremglob(char **argv, int doswitch) 77055682Smarkm{ 77155682Smarkm char temp[16]; 77255682Smarkm static char buf[MaxPathLen]; 77355682Smarkm static FILE *ftemp = NULL; 77455682Smarkm static char **args; 77555682Smarkm int oldverbose, oldhash; 776178825Sdfr char *cp, *filemode; 77755682Smarkm 77855682Smarkm if (!mflag) { 77955682Smarkm if (!doglob) { 78055682Smarkm args = NULL; 78155682Smarkm } 78255682Smarkm else { 78355682Smarkm if (ftemp) { 78455682Smarkm fclose(ftemp); 78555682Smarkm ftemp = NULL; 78655682Smarkm } 78755682Smarkm } 78855682Smarkm return (NULL); 78955682Smarkm } 79055682Smarkm if (!doglob) { 79155682Smarkm if (args == NULL) 79255682Smarkm args = argv; 79355682Smarkm if ((cp = *++args) == NULL) 79455682Smarkm args = NULL; 79555682Smarkm return (cp); 79655682Smarkm } 79755682Smarkm if (ftemp == NULL) { 79855682Smarkm int fd; 79955682Smarkm strlcpy(temp, _PATH_TMP_XXX, sizeof(temp)); 80055682Smarkm fd = mkstemp(temp); 80155682Smarkm if(fd < 0){ 80255682Smarkm warn("unable to create temporary file %s", temp); 80355682Smarkm return NULL; 80455682Smarkm } 80555682Smarkm close(fd); 80655682Smarkm oldverbose = verbose, verbose = 0; 80755682Smarkm oldhash = hash, hash = 0; 80855682Smarkm if (doswitch) { 80955682Smarkm pswitch(!proxy); 81055682Smarkm } 811178825Sdfr for (filemode = "w"; *++argv != NULL; filemode = "a") 812178825Sdfr recvrequest ("NLST", temp, *argv, filemode, 0, 0); 81355682Smarkm if (doswitch) { 81455682Smarkm pswitch(!proxy); 81555682Smarkm } 81655682Smarkm verbose = oldverbose; hash = oldhash; 81755682Smarkm ftemp = fopen(temp, "r"); 81855682Smarkm unlink(temp); 81955682Smarkm if (ftemp == NULL) { 82055682Smarkm printf("can't find list of remote files, oops\n"); 82155682Smarkm return (NULL); 82255682Smarkm } 82355682Smarkm } 82455682Smarkm while(fgets(buf, sizeof (buf), ftemp)) { 82555682Smarkm if ((cp = strchr(buf, '\n')) != NULL) 82655682Smarkm *cp = '\0'; 82755682Smarkm if(!interactive && suspicious_filename(buf)){ 82855682Smarkm printf("Ignoring remote globbed file `%s'\n", buf); 82955682Smarkm continue; 83055682Smarkm } 83155682Smarkm return buf; 83255682Smarkm } 83355682Smarkm fclose(ftemp); 83455682Smarkm ftemp = NULL; 83555682Smarkm return (NULL); 83655682Smarkm} 83755682Smarkm 83855682Smarkmchar * 83955682Smarkmonoff(int bool) 84055682Smarkm{ 84155682Smarkm 84255682Smarkm return (bool ? "on" : "off"); 84355682Smarkm} 84455682Smarkm 84555682Smarkm/* 84655682Smarkm * Show status. 84755682Smarkm */ 84855682Smarkm/*ARGSUSED*/ 84955682Smarkmvoid 85055682Smarkmstatus(int argc, char **argv) 85155682Smarkm{ 85255682Smarkm int i; 85355682Smarkm 85455682Smarkm if (connected) 85555682Smarkm printf("Connected to %s.\n", hostname); 85655682Smarkm else 85755682Smarkm printf("Not connected.\n"); 85855682Smarkm if (!proxy) { 85955682Smarkm pswitch(1); 86055682Smarkm if (connected) { 86155682Smarkm printf("Connected for proxy commands to %s.\n", hostname); 86255682Smarkm } 86355682Smarkm else { 86455682Smarkm printf("No proxy connection.\n"); 86555682Smarkm } 86655682Smarkm pswitch(0); 86755682Smarkm } 86855682Smarkm sec_status(); 86955682Smarkm printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", 87055682Smarkm modename, typename, formname, structname); 871233294Sstas printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 87255682Smarkm onoff(verbose), onoff(bell), onoff(interactive), 87355682Smarkm onoff(doglob)); 87455682Smarkm printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), 87555682Smarkm onoff(runique)); 87655682Smarkm printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); 87755682Smarkm if (ntflag) { 87855682Smarkm printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); 87955682Smarkm } 88055682Smarkm else { 88155682Smarkm printf("Ntrans: off\n"); 88255682Smarkm } 88355682Smarkm if (mapflag) { 88455682Smarkm printf("Nmap: (in) %s (out) %s\n", mapin, mapout); 88555682Smarkm } 88655682Smarkm else { 88755682Smarkm printf("Nmap: off\n"); 88855682Smarkm } 88955682Smarkm printf("Hash mark printing: %s; Use of PORT cmds: %s\n", 89055682Smarkm onoff(hash), onoff(sendport)); 89155682Smarkm if (macnum > 0) { 89255682Smarkm printf("Macros:\n"); 89355682Smarkm for (i=0; i<macnum; i++) { 89455682Smarkm printf("\t%s\n",macros[i].mac_name); 89555682Smarkm } 89655682Smarkm } 89755682Smarkm code = 0; 89855682Smarkm} 89955682Smarkm 90055682Smarkm/* 90155682Smarkm * Set beep on cmd completed mode. 90255682Smarkm */ 90355682Smarkm/*VARARGS*/ 90455682Smarkmvoid 90555682Smarkmsetbell(int argc, char **argv) 90655682Smarkm{ 90755682Smarkm 90855682Smarkm bell = !bell; 90955682Smarkm printf("Bell mode %s.\n", onoff(bell)); 91055682Smarkm code = bell; 91155682Smarkm} 91255682Smarkm 91355682Smarkm/* 91455682Smarkm * Turn on packet tracing. 91555682Smarkm */ 91655682Smarkm/*VARARGS*/ 91755682Smarkmvoid 91855682Smarkmsettrace(int argc, char **argv) 91955682Smarkm{ 92055682Smarkm 92155682Smarkm trace = !trace; 92255682Smarkm printf("Packet tracing %s.\n", onoff(trace)); 92355682Smarkm code = trace; 92455682Smarkm} 92555682Smarkm 92655682Smarkm/* 92755682Smarkm * Toggle hash mark printing during transfers. 92855682Smarkm */ 92955682Smarkm/*VARARGS*/ 93055682Smarkmvoid 93155682Smarkmsethash(int argc, char **argv) 93255682Smarkm{ 93355682Smarkm 93455682Smarkm hash = !hash; 93555682Smarkm printf("Hash mark printing %s", onoff(hash)); 93655682Smarkm code = hash; 93755682Smarkm if (hash) 93855682Smarkm printf(" (%d bytes/hash mark)", 1024); 93955682Smarkm printf(".\n"); 94055682Smarkm} 94155682Smarkm 94255682Smarkm/* 94355682Smarkm * Turn on printing of server echo's. 94455682Smarkm */ 94555682Smarkm/*VARARGS*/ 94655682Smarkmvoid 94755682Smarkmsetverbose(int argc, char **argv) 94855682Smarkm{ 94955682Smarkm 95055682Smarkm verbose = !verbose; 95155682Smarkm printf("Verbose mode %s.\n", onoff(verbose)); 95255682Smarkm code = verbose; 95355682Smarkm} 95455682Smarkm 95555682Smarkm/* 95655682Smarkm * Toggle PORT cmd use before each data connection. 95755682Smarkm */ 95855682Smarkm/*VARARGS*/ 95955682Smarkmvoid 96055682Smarkmsetport(int argc, char **argv) 96155682Smarkm{ 96255682Smarkm 96355682Smarkm sendport = !sendport; 96455682Smarkm printf("Use of PORT cmds %s.\n", onoff(sendport)); 96555682Smarkm code = sendport; 96655682Smarkm} 96755682Smarkm 96855682Smarkm/* 96955682Smarkm * Turn on interactive prompting 97055682Smarkm * during mget, mput, and mdelete. 97155682Smarkm */ 97255682Smarkm/*VARARGS*/ 97355682Smarkmvoid 97455682Smarkmsetprompt(int argc, char **argv) 97555682Smarkm{ 97655682Smarkm 97755682Smarkm interactive = !interactive; 97855682Smarkm printf("Interactive mode %s.\n", onoff(interactive)); 97955682Smarkm code = interactive; 98055682Smarkm} 98155682Smarkm 98255682Smarkm/* 98355682Smarkm * Toggle metacharacter interpretation 98455682Smarkm * on local file names. 98555682Smarkm */ 98655682Smarkm/*VARARGS*/ 98755682Smarkmvoid 98855682Smarkmsetglob(int argc, char **argv) 98955682Smarkm{ 990233294Sstas 99155682Smarkm doglob = !doglob; 99255682Smarkm printf("Globbing %s.\n", onoff(doglob)); 99355682Smarkm code = doglob; 99455682Smarkm} 99555682Smarkm 99655682Smarkm/* 99755682Smarkm * Set debugging mode on/off and/or 99855682Smarkm * set level of debugging. 99955682Smarkm */ 100055682Smarkm/*VARARGS*/ 100155682Smarkmvoid 100255682Smarkmsetdebug(int argc, char **argv) 100355682Smarkm{ 100455682Smarkm int val; 100555682Smarkm 100655682Smarkm if (argc > 1) { 100755682Smarkm val = atoi(argv[1]); 100855682Smarkm if (val < 0) { 100955682Smarkm printf("%s: bad debugging value.\n", argv[1]); 101055682Smarkm code = -1; 101155682Smarkm return; 101255682Smarkm } 101355682Smarkm } else 101455682Smarkm val = !debug; 101555682Smarkm debug = val; 101655682Smarkm if (debug) 101755682Smarkm options |= SO_DEBUG; 101855682Smarkm else 101955682Smarkm options &= ~SO_DEBUG; 102055682Smarkm printf("Debugging %s (debug=%d).\n", onoff(debug), debug); 102155682Smarkm code = debug > 0; 102255682Smarkm} 102355682Smarkm 102455682Smarkm/* 102555682Smarkm * Set current working directory 102655682Smarkm * on remote machine. 102755682Smarkm */ 102855682Smarkmvoid 102955682Smarkmcd(int argc, char **argv) 103055682Smarkm{ 103155682Smarkm 103255682Smarkm if (argc < 2 && !another(&argc, &argv, "remote-directory")) { 103355682Smarkm printf("usage: %s remote-directory\n", argv[0]); 103455682Smarkm code = -1; 103555682Smarkm return; 103655682Smarkm } 103755682Smarkm if (command("CWD %s", argv[1]) == ERROR && code == 500) { 103855682Smarkm if (verbose) 103955682Smarkm printf("CWD command not recognized, trying XCWD\n"); 104055682Smarkm command("XCWD %s", argv[1]); 104155682Smarkm } 104255682Smarkm} 104355682Smarkm 104455682Smarkm/* 104555682Smarkm * Set current working directory 104655682Smarkm * on local machine. 104755682Smarkm */ 104855682Smarkmvoid 104955682Smarkmlcd(int argc, char **argv) 105055682Smarkm{ 105155682Smarkm char buf[MaxPathLen]; 105255682Smarkm 105355682Smarkm if (argc < 2) 105455682Smarkm argc++, argv[1] = home; 105555682Smarkm if (argc != 2) { 105655682Smarkm printf("usage: %s local-directory\n", argv[0]); 105755682Smarkm code = -1; 105855682Smarkm return; 105955682Smarkm } 106055682Smarkm if (!globulize(&argv[1])) { 106155682Smarkm code = -1; 106255682Smarkm return; 106355682Smarkm } 106455682Smarkm if (chdir(argv[1]) < 0) { 106555682Smarkm warn("local: %s", argv[1]); 106655682Smarkm code = -1; 106755682Smarkm return; 106855682Smarkm } 106955682Smarkm if (getcwd(buf, sizeof(buf)) != NULL) 107055682Smarkm printf("Local directory now %s\n", buf); 107155682Smarkm else 107255682Smarkm warnx("getwd: %s", buf); 107355682Smarkm code = 0; 107455682Smarkm} 107555682Smarkm 107655682Smarkm/* 107755682Smarkm * Delete a single file. 107855682Smarkm */ 107955682Smarkmvoid 108055682Smarkmdelete(int argc, char **argv) 108155682Smarkm{ 108255682Smarkm 108355682Smarkm if (argc < 2 && !another(&argc, &argv, "remote-file")) { 108455682Smarkm printf("usage: %s remote-file\n", argv[0]); 108555682Smarkm code = -1; 108655682Smarkm return; 108755682Smarkm } 108855682Smarkm command("DELE %s", argv[1]); 108955682Smarkm} 109055682Smarkm 109155682Smarkm/* 109255682Smarkm * Delete multiple files. 109355682Smarkm */ 109455682Smarkmvoid 109555682Smarkmmdelete(int argc, char **argv) 109655682Smarkm{ 109755682Smarkm sighand oldintr; 109855682Smarkm int ointer; 109955682Smarkm char *cp; 110055682Smarkm 110155682Smarkm if (argc < 2 && !another(&argc, &argv, "remote-files")) { 110255682Smarkm printf("usage: %s remote-files\n", argv[0]); 110355682Smarkm code = -1; 110455682Smarkm return; 110555682Smarkm } 110655682Smarkm mname = argv[0]; 110755682Smarkm mflag = 1; 110855682Smarkm oldintr = signal(SIGINT, mabort); 110955682Smarkm setjmp(jabort); 111055682Smarkm while ((cp = remglob(argv,0)) != NULL) { 111155682Smarkm if (*cp == '\0') { 111255682Smarkm mflag = 0; 111355682Smarkm continue; 111455682Smarkm } 111555682Smarkm if (mflag && confirm(argv[0], cp)) { 111655682Smarkm command("DELE %s", cp); 111755682Smarkm if (!mflag && fromatty) { 111855682Smarkm ointer = interactive; 111955682Smarkm interactive = 1; 112055682Smarkm if (confirm("Continue with", "mdelete")) { 112155682Smarkm mflag++; 112255682Smarkm } 112355682Smarkm interactive = ointer; 112455682Smarkm } 112555682Smarkm } 112655682Smarkm } 112755682Smarkm signal(SIGINT, oldintr); 112855682Smarkm mflag = 0; 112955682Smarkm} 113055682Smarkm 113155682Smarkm/* 113255682Smarkm * Rename a remote file. 113355682Smarkm */ 113455682Smarkmvoid 113555682Smarkmrenamefile(int argc, char **argv) 113655682Smarkm{ 113755682Smarkm 113855682Smarkm if (argc < 2 && !another(&argc, &argv, "from-name")) 113955682Smarkm goto usage; 114055682Smarkm if (argc < 3 && !another(&argc, &argv, "to-name")) { 114155682Smarkmusage: 114255682Smarkm printf("%s from-name to-name\n", argv[0]); 114355682Smarkm code = -1; 114455682Smarkm return; 114555682Smarkm } 114655682Smarkm if (command("RNFR %s", argv[1]) == CONTINUE) 114755682Smarkm command("RNTO %s", argv[2]); 114855682Smarkm} 114955682Smarkm 115055682Smarkm/* 115155682Smarkm * Get a directory listing 115255682Smarkm * of remote files. 115355682Smarkm */ 115455682Smarkmvoid 115555682Smarkmls(int argc, char **argv) 115655682Smarkm{ 115755682Smarkm char *cmd; 115855682Smarkm 115955682Smarkm if (argc < 2) 116055682Smarkm argc++, argv[1] = NULL; 116155682Smarkm if (argc < 3) 116255682Smarkm argc++, argv[2] = "-"; 116355682Smarkm if (argc > 3) { 116455682Smarkm printf("usage: %s remote-directory local-file\n", argv[0]); 116555682Smarkm code = -1; 116655682Smarkm return; 116755682Smarkm } 116855682Smarkm cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; 116955682Smarkm if (strcmp(argv[2], "-") && !globulize(&argv[2])) { 117055682Smarkm code = -1; 117155682Smarkm return; 117255682Smarkm } 117355682Smarkm if (strcmp(argv[2], "-") && *argv[2] != '|') 1174233294Sstas if (!globulize(&argv[2]) || !confirm("output to local-file:", 117555682Smarkm argv[2])) { 117655682Smarkm code = -1; 117755682Smarkm return; 117855682Smarkm } 117955682Smarkm recvrequest(cmd, argv[2], argv[1], "w", 0, 1); 118055682Smarkm} 118155682Smarkm 118255682Smarkm/* 118355682Smarkm * Get a directory listing 118455682Smarkm * of multiple remote files. 118555682Smarkm */ 118655682Smarkmvoid 118755682Smarkmmls(int argc, char **argv) 118855682Smarkm{ 118955682Smarkm sighand oldintr; 119055682Smarkm int ointer, i; 1191178825Sdfr char *cmd, filemode[2], *dest; 119255682Smarkm 119355682Smarkm if (argc < 2 && !another(&argc, &argv, "remote-files")) 119455682Smarkm goto usage; 119555682Smarkm if (argc < 3 && !another(&argc, &argv, "local-file")) { 119655682Smarkmusage: 119755682Smarkm printf("usage: %s remote-files local-file\n", argv[0]); 119855682Smarkm code = -1; 119955682Smarkm return; 120055682Smarkm } 120155682Smarkm dest = argv[argc - 1]; 120255682Smarkm argv[argc - 1] = NULL; 120355682Smarkm if (strcmp(dest, "-") && *dest != '|') 120455682Smarkm if (!globulize(&dest) || 120555682Smarkm !confirm("output to local-file:", dest)) { 120655682Smarkm code = -1; 120755682Smarkm return; 120855682Smarkm } 120955682Smarkm cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; 121055682Smarkm mname = argv[0]; 121155682Smarkm mflag = 1; 121255682Smarkm oldintr = signal(SIGINT, mabort); 121355682Smarkm setjmp(jabort); 1214178825Sdfr filemode[1] = '\0'; 121555682Smarkm for (i = 1; mflag && i < argc-1; ++i) { 1216178825Sdfr *filemode = (i == 1) ? 'w' : 'a'; 1217178825Sdfr recvrequest(cmd, dest, argv[i], filemode, 0, 1); 121855682Smarkm if (!mflag && fromatty) { 121955682Smarkm ointer = interactive; 122055682Smarkm interactive = 1; 122155682Smarkm if (confirm("Continue with", argv[0])) { 122255682Smarkm mflag ++; 122355682Smarkm } 122455682Smarkm interactive = ointer; 122555682Smarkm } 122655682Smarkm } 122755682Smarkm signal(SIGINT, oldintr); 122855682Smarkm mflag = 0; 122955682Smarkm} 123055682Smarkm 123155682Smarkm/* 123255682Smarkm * Do a shell escape 123355682Smarkm */ 123455682Smarkm/*ARGSUSED*/ 123555682Smarkmvoid 123655682Smarkmshell(int argc, char **argv) 123755682Smarkm{ 123855682Smarkm pid_t pid; 123972445Sassar RETSIGTYPE (*old1)(int), (*old2)(int); 1240233294Sstas char shellnam[40], *shellpath, *namep; 1241178825Sdfr int waitstatus; 124255682Smarkm 124355682Smarkm old1 = signal (SIGINT, SIG_IGN); 124455682Smarkm old2 = signal (SIGQUIT, SIG_IGN); 124555682Smarkm if ((pid = fork()) == 0) { 124655682Smarkm for (pid = 3; pid < 20; pid++) 124755682Smarkm close(pid); 124855682Smarkm signal(SIGINT, SIG_DFL); 124955682Smarkm signal(SIGQUIT, SIG_DFL); 1250178825Sdfr shellpath = getenv("SHELL"); 1251178825Sdfr if (shellpath == NULL) 1252178825Sdfr shellpath = _PATH_BSHELL; 1253178825Sdfr namep = strrchr(shellpath, '/'); 125455682Smarkm if (namep == NULL) 1255178825Sdfr namep = shellpath; 125655682Smarkm snprintf (shellnam, sizeof(shellnam), 125755682Smarkm "-%s", ++namep); 125855682Smarkm if (strcmp(namep, "sh") != 0) 125955682Smarkm shellnam[0] = '+'; 126055682Smarkm if (debug) { 1261178825Sdfr printf ("%s\n", shellpath); 126255682Smarkm fflush (stdout); 126355682Smarkm } 126455682Smarkm if (argc > 1) { 1265178825Sdfr execl(shellpath,shellnam,"-c",altarg,(char *)0); 126655682Smarkm } 126755682Smarkm else { 1268178825Sdfr execl(shellpath,shellnam,(char *)0); 126955682Smarkm } 1270178825Sdfr warn("%s", shellpath); 127155682Smarkm code = -1; 127255682Smarkm exit(1); 127355682Smarkm } 127455682Smarkm if (pid > 0) 1275178825Sdfr while (waitpid(-1, &waitstatus, 0) != pid) 127655682Smarkm ; 127755682Smarkm signal(SIGINT, old1); 127855682Smarkm signal(SIGQUIT, old2); 127955682Smarkm if (pid == -1) { 128055682Smarkm warn("%s", "Try again later"); 128155682Smarkm code = -1; 128255682Smarkm } 128355682Smarkm else { 128455682Smarkm code = 0; 128555682Smarkm } 128655682Smarkm} 128755682Smarkm 128855682Smarkm/* 128955682Smarkm * Send new user information (re-login) 129055682Smarkm */ 129155682Smarkmvoid 129255682Smarkmuser(int argc, char **argv) 129355682Smarkm{ 1294178825Sdfr char acctstr[80]; 129555682Smarkm int n, aflag = 0; 129655682Smarkm char tmp[256]; 129755682Smarkm 129855682Smarkm if (argc < 2) 129955682Smarkm another(&argc, &argv, "username"); 130055682Smarkm if (argc < 2 || argc > 4) { 130155682Smarkm printf("usage: %s username [password] [account]\n", argv[0]); 130255682Smarkm code = -1; 130355682Smarkm return; 130455682Smarkm } 130555682Smarkm n = command("USER %s", argv[1]); 130655682Smarkm if (n == CONTINUE) { 130755682Smarkm if (argc < 3 ) { 1308178825Sdfr UI_UTIL_read_pw_string (tmp, 130955682Smarkm sizeof(tmp), 131055682Smarkm "Password: ", 0); 131155682Smarkm argv[2] = tmp; 131255682Smarkm argc++; 131355682Smarkm } 131455682Smarkm n = command("PASS %s", argv[2]); 131555682Smarkm } 131655682Smarkm if (n == CONTINUE) { 131755682Smarkm if (argc < 4) { 131855682Smarkm printf("Account: "); fflush(stdout); 1319178825Sdfr fgets(acctstr, sizeof(acctstr) - 1, stdin); 1320178825Sdfr acctstr[strcspn(acctstr, "\r\n")] = '\0'; 1321178825Sdfr argv[3] = acctstr; argc++; 132255682Smarkm } 132355682Smarkm n = command("ACCT %s", argv[3]); 132455682Smarkm aflag++; 132555682Smarkm } 132655682Smarkm if (n != COMPLETE) { 132755682Smarkm fprintf(stdout, "Login failed.\n"); 132855682Smarkm return; 132955682Smarkm } 133055682Smarkm if (!aflag && argc == 4) { 133155682Smarkm command("ACCT %s", argv[3]); 133255682Smarkm } 133355682Smarkm} 133455682Smarkm 133555682Smarkm/* 133655682Smarkm * Print working directory. 133755682Smarkm */ 133855682Smarkm/*VARARGS*/ 133955682Smarkmvoid 134055682Smarkmpwd(int argc, char **argv) 134155682Smarkm{ 134255682Smarkm int oldverbose = verbose; 134355682Smarkm 134455682Smarkm /* 134555682Smarkm * If we aren't verbose, this doesn't do anything! 134655682Smarkm */ 134755682Smarkm verbose = 1; 134855682Smarkm if (command("PWD") == ERROR && code == 500) { 134955682Smarkm printf("PWD command not recognized, trying XPWD\n"); 135055682Smarkm command("XPWD"); 135155682Smarkm } 135255682Smarkm verbose = oldverbose; 135355682Smarkm} 135455682Smarkm 135555682Smarkm/* 135655682Smarkm * Make a directory. 135755682Smarkm */ 135855682Smarkmvoid 135955682Smarkmmakedir(int argc, char **argv) 136055682Smarkm{ 136155682Smarkm 136255682Smarkm if (argc < 2 && !another(&argc, &argv, "directory-name")) { 136355682Smarkm printf("usage: %s directory-name\n", argv[0]); 136455682Smarkm code = -1; 136555682Smarkm return; 136655682Smarkm } 136755682Smarkm if (command("MKD %s", argv[1]) == ERROR && code == 500) { 136855682Smarkm if (verbose) 136955682Smarkm printf("MKD command not recognized, trying XMKD\n"); 137055682Smarkm command("XMKD %s", argv[1]); 137155682Smarkm } 137255682Smarkm} 137355682Smarkm 137455682Smarkm/* 137555682Smarkm * Remove a directory. 137655682Smarkm */ 137755682Smarkmvoid 137855682Smarkmremovedir(int argc, char **argv) 137955682Smarkm{ 138055682Smarkm 138155682Smarkm if (argc < 2 && !another(&argc, &argv, "directory-name")) { 138255682Smarkm printf("usage: %s directory-name\n", argv[0]); 138355682Smarkm code = -1; 138455682Smarkm return; 138555682Smarkm } 138655682Smarkm if (command("RMD %s", argv[1]) == ERROR && code == 500) { 138755682Smarkm if (verbose) 138855682Smarkm printf("RMD command not recognized, trying XRMD\n"); 138955682Smarkm command("XRMD %s", argv[1]); 139055682Smarkm } 139155682Smarkm} 139255682Smarkm 139355682Smarkm/* 139455682Smarkm * Send a line, verbatim, to the remote machine. 139555682Smarkm */ 139655682Smarkmvoid 139755682Smarkmquote(int argc, char **argv) 139855682Smarkm{ 139955682Smarkm 140055682Smarkm if (argc < 2 && !another(&argc, &argv, "command line to send")) { 140155682Smarkm printf("usage: %s line-to-send\n", argv[0]); 140255682Smarkm code = -1; 140355682Smarkm return; 140455682Smarkm } 140555682Smarkm quote1("", argc, argv); 140655682Smarkm} 140755682Smarkm 140855682Smarkm/* 140955682Smarkm * Send a SITE command to the remote machine. The line 141055682Smarkm * is sent verbatim to the remote machine, except that the 141155682Smarkm * word "SITE" is added at the front. 141255682Smarkm */ 141355682Smarkmvoid 141455682Smarkmsite(int argc, char **argv) 141555682Smarkm{ 141655682Smarkm 141755682Smarkm if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { 141855682Smarkm printf("usage: %s line-to-send\n", argv[0]); 141955682Smarkm code = -1; 142055682Smarkm return; 142155682Smarkm } 142255682Smarkm quote1("SITE ", argc, argv); 142355682Smarkm} 142455682Smarkm 142555682Smarkm/* 142655682Smarkm * Turn argv[1..argc) into a space-separated string, then prepend initial text. 142755682Smarkm * Send the result as a one-line command and get response. 142855682Smarkm */ 142955682Smarkmvoid 143055682Smarkmquote1(char *initial, int argc, char **argv) 143155682Smarkm{ 143255682Smarkm int i; 143355682Smarkm char buf[BUFSIZ]; /* must be >= sizeof(line) */ 143455682Smarkm 143555682Smarkm strlcpy(buf, initial, sizeof(buf)); 143655682Smarkm for(i = 1; i < argc; i++) { 143755682Smarkm if(i > 1) 143855682Smarkm strlcat(buf, " ", sizeof(buf)); 143955682Smarkm strlcat(buf, argv[i], sizeof(buf)); 144055682Smarkm } 144155682Smarkm if (command("%s", buf) == PRELIM) { 144255682Smarkm while (getreply(0) == PRELIM) 144355682Smarkm continue; 144455682Smarkm } 144555682Smarkm} 144655682Smarkm 144755682Smarkmvoid 144855682Smarkmdo_chmod(int argc, char **argv) 144955682Smarkm{ 145055682Smarkm 145155682Smarkm if (argc < 2 && !another(&argc, &argv, "mode")) 145255682Smarkm goto usage; 145355682Smarkm if (argc < 3 && !another(&argc, &argv, "file-name")) { 145455682Smarkmusage: 145555682Smarkm printf("usage: %s mode file-name\n", argv[0]); 145655682Smarkm code = -1; 145755682Smarkm return; 145855682Smarkm } 145955682Smarkm command("SITE CHMOD %s %s", argv[1], argv[2]); 146055682Smarkm} 146155682Smarkm 146255682Smarkmvoid 146355682Smarkmdo_umask(int argc, char **argv) 146455682Smarkm{ 146555682Smarkm int oldverbose = verbose; 146655682Smarkm 146755682Smarkm verbose = 1; 146855682Smarkm command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); 146955682Smarkm verbose = oldverbose; 147055682Smarkm} 147155682Smarkm 147255682Smarkmvoid 147355682Smarkmftp_idle(int argc, char **argv) 147455682Smarkm{ 147555682Smarkm int oldverbose = verbose; 147655682Smarkm 147755682Smarkm verbose = 1; 147855682Smarkm command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); 147955682Smarkm verbose = oldverbose; 148055682Smarkm} 148155682Smarkm 148255682Smarkm/* 148355682Smarkm * Ask the other side for help. 148455682Smarkm */ 148555682Smarkmvoid 148655682Smarkmrmthelp(int argc, char **argv) 148755682Smarkm{ 148855682Smarkm int oldverbose = verbose; 148955682Smarkm 149055682Smarkm verbose = 1; 149155682Smarkm command(argc == 1 ? "HELP" : "HELP %s", argv[1]); 149255682Smarkm verbose = oldverbose; 149355682Smarkm} 149455682Smarkm 149555682Smarkm/* 149655682Smarkm * Terminate session and exit. 149755682Smarkm */ 149855682Smarkm/*VARARGS*/ 149955682Smarkmvoid 150055682Smarkmquit(int argc, char **argv) 150155682Smarkm{ 150255682Smarkm 150355682Smarkm if (connected) 150455682Smarkm disconnect(0, 0); 150555682Smarkm pswitch(1); 150655682Smarkm if (connected) { 150755682Smarkm disconnect(0, 0); 150855682Smarkm } 150955682Smarkm exit(0); 151055682Smarkm} 151155682Smarkm 151255682Smarkm/* 151355682Smarkm * Terminate session, but don't exit. 151455682Smarkm */ 151555682Smarkmvoid 151655682Smarkmdisconnect(int argc, char **argv) 151755682Smarkm{ 151855682Smarkm 151955682Smarkm if (!connected) 152055682Smarkm return; 152155682Smarkm command("QUIT"); 152255682Smarkm if (cout) { 152355682Smarkm fclose(cout); 152455682Smarkm } 152555682Smarkm cout = NULL; 152655682Smarkm connected = 0; 152755682Smarkm sec_end(); 152855682Smarkm data = -1; 152955682Smarkm if (!proxy) { 153055682Smarkm macnum = 0; 153155682Smarkm } 153255682Smarkm} 153355682Smarkm 153455682Smarkmint 153555682Smarkmconfirm(char *cmd, char *file) 153655682Smarkm{ 1537178825Sdfr char buf[BUFSIZ]; 153855682Smarkm 153955682Smarkm if (!interactive) 154055682Smarkm return (1); 154155682Smarkm printf("%s %s? ", cmd, file); 154255682Smarkm fflush(stdout); 1543178825Sdfr if (fgets(buf, sizeof buf, stdin) == NULL) 154455682Smarkm return (0); 1545178825Sdfr return (*buf == 'y' || *buf == 'Y'); 154655682Smarkm} 154755682Smarkm 154855682Smarkmvoid 154955682Smarkmfatal(char *msg) 155055682Smarkm{ 155155682Smarkm 155255682Smarkm errx(1, "%s", msg); 155355682Smarkm} 155455682Smarkm 155555682Smarkm/* 155655682Smarkm * Glob a local file name specification with 155755682Smarkm * the expectation of a single return value. 155855682Smarkm * Can't control multiple values being expanded 155955682Smarkm * from the expression, we return only the first. 156055682Smarkm */ 156155682Smarkmint 156255682Smarkmglobulize(char **cpp) 156355682Smarkm{ 156455682Smarkm glob_t gl; 156555682Smarkm int flags; 156655682Smarkm 156755682Smarkm if (!doglob) 156855682Smarkm return (1); 156955682Smarkm 157055682Smarkm flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE; 157155682Smarkm memset(&gl, 0, sizeof(gl)); 157255682Smarkm if (glob(*cpp, flags, NULL, &gl) || 157355682Smarkm gl.gl_pathc == 0) { 157455682Smarkm warnx("%s: not found", *cpp); 157555682Smarkm globfree(&gl); 157655682Smarkm return (0); 157755682Smarkm } 157855682Smarkm *cpp = strdup(gl.gl_pathv[0]); /* XXX - wasted memory */ 157955682Smarkm globfree(&gl); 158055682Smarkm return (1); 158155682Smarkm} 158255682Smarkm 158355682Smarkmvoid 158455682Smarkmaccount(int argc, char **argv) 158555682Smarkm{ 1586178825Sdfr char acctstr[50]; 158755682Smarkm 158855682Smarkm if (argc > 1) { 158955682Smarkm ++argv; 159055682Smarkm --argc; 1591178825Sdfr strlcpy (acctstr, *argv, sizeof(acctstr)); 159255682Smarkm while (argc > 1) { 159355682Smarkm --argc; 159455682Smarkm ++argv; 1595178825Sdfr strlcat(acctstr, *argv, sizeof(acctstr)); 159655682Smarkm } 159755682Smarkm } 159855682Smarkm else { 1599178825Sdfr UI_UTIL_read_pw_string(acctstr, sizeof(acctstr), "Account:", 0); 160055682Smarkm } 1601178825Sdfr command("ACCT %s", acctstr); 160255682Smarkm} 160355682Smarkm 160455682Smarkmjmp_buf abortprox; 160555682Smarkm 160655682Smarkmstatic RETSIGTYPE 160755682Smarkmproxabort(int sig) 160855682Smarkm{ 160955682Smarkm 161055682Smarkm if (!proxy) { 161155682Smarkm pswitch(1); 161255682Smarkm } 161355682Smarkm if (connected) { 161455682Smarkm proxflag = 1; 161555682Smarkm } 161655682Smarkm else { 161755682Smarkm proxflag = 0; 161855682Smarkm } 161955682Smarkm pswitch(0); 162055682Smarkm longjmp(abortprox,1); 162155682Smarkm} 162255682Smarkm 162355682Smarkmvoid 162455682Smarkmdoproxy(int argc, char **argv) 162555682Smarkm{ 162655682Smarkm struct cmd *c; 162772445Sassar RETSIGTYPE (*oldintr)(int); 162855682Smarkm 162955682Smarkm if (argc < 2 && !another(&argc, &argv, "command")) { 163055682Smarkm printf("usage: %s command\n", argv[0]); 163155682Smarkm code = -1; 163255682Smarkm return; 163355682Smarkm } 163455682Smarkm c = getcmd(argv[1]); 163555682Smarkm if (c == (struct cmd *) -1) { 163655682Smarkm printf("?Ambiguous command\n"); 163755682Smarkm fflush(stdout); 163855682Smarkm code = -1; 163955682Smarkm return; 164055682Smarkm } 164155682Smarkm if (c == 0) { 164255682Smarkm printf("?Invalid command\n"); 164355682Smarkm fflush(stdout); 164455682Smarkm code = -1; 164555682Smarkm return; 164655682Smarkm } 164755682Smarkm if (!c->c_proxy) { 164855682Smarkm printf("?Invalid proxy command\n"); 164955682Smarkm fflush(stdout); 165055682Smarkm code = -1; 165155682Smarkm return; 165255682Smarkm } 165355682Smarkm if (setjmp(abortprox)) { 165455682Smarkm code = -1; 165555682Smarkm return; 165655682Smarkm } 165755682Smarkm oldintr = signal(SIGINT, proxabort); 165855682Smarkm pswitch(1); 165955682Smarkm if (c->c_conn && !connected) { 166055682Smarkm printf("Not connected\n"); 166155682Smarkm fflush(stdout); 166255682Smarkm pswitch(0); 166355682Smarkm signal(SIGINT, oldintr); 166455682Smarkm code = -1; 166555682Smarkm return; 166655682Smarkm } 166755682Smarkm (*c->c_handler)(argc-1, argv+1); 166855682Smarkm if (connected) { 166955682Smarkm proxflag = 1; 167055682Smarkm } 167155682Smarkm else { 167255682Smarkm proxflag = 0; 167355682Smarkm } 167455682Smarkm pswitch(0); 167555682Smarkm signal(SIGINT, oldintr); 167655682Smarkm} 167755682Smarkm 167855682Smarkmvoid 167955682Smarkmsetcase(int argc, char **argv) 168055682Smarkm{ 168155682Smarkm 168255682Smarkm mcase = !mcase; 168355682Smarkm printf("Case mapping %s.\n", onoff(mcase)); 168455682Smarkm code = mcase; 168555682Smarkm} 168655682Smarkm 168755682Smarkmvoid 168855682Smarkmsetcr(int argc, char **argv) 168955682Smarkm{ 169055682Smarkm 169155682Smarkm crflag = !crflag; 169255682Smarkm printf("Carriage Return stripping %s.\n", onoff(crflag)); 169355682Smarkm code = crflag; 169455682Smarkm} 169555682Smarkm 169655682Smarkmvoid 169755682Smarkmsetntrans(int argc, char **argv) 169855682Smarkm{ 169955682Smarkm if (argc == 1) { 170055682Smarkm ntflag = 0; 170155682Smarkm printf("Ntrans off.\n"); 170255682Smarkm code = ntflag; 170355682Smarkm return; 170455682Smarkm } 170555682Smarkm ntflag++; 170655682Smarkm code = ntflag; 170755682Smarkm strlcpy (ntin, argv[1], 17); 170855682Smarkm if (argc == 2) { 170955682Smarkm ntout[0] = '\0'; 171055682Smarkm return; 171155682Smarkm } 171255682Smarkm strlcpy (ntout, argv[2], 17); 171355682Smarkm} 171455682Smarkm 171555682Smarkmchar * 171655682Smarkmdotrans(char *name) 171755682Smarkm{ 171855682Smarkm static char new[MaxPathLen]; 171955682Smarkm char *cp1, *cp2 = new; 172055682Smarkm int i, ostop, found; 172155682Smarkm 172255682Smarkm for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++) 172355682Smarkm continue; 172455682Smarkm for (cp1 = name; *cp1; cp1++) { 172555682Smarkm found = 0; 172655682Smarkm for (i = 0; *(ntin + i) && i < 16; i++) { 172755682Smarkm if (*cp1 == *(ntin + i)) { 172855682Smarkm found++; 172955682Smarkm if (i < ostop) { 173055682Smarkm *cp2++ = *(ntout + i); 173155682Smarkm } 173255682Smarkm break; 173355682Smarkm } 173455682Smarkm } 173555682Smarkm if (!found) { 173655682Smarkm *cp2++ = *cp1; 173755682Smarkm } 173855682Smarkm } 173955682Smarkm *cp2 = '\0'; 174055682Smarkm return (new); 174155682Smarkm} 174255682Smarkm 174355682Smarkmvoid 174455682Smarkmsetnmap(int argc, char **argv) 174555682Smarkm{ 174655682Smarkm char *cp; 174755682Smarkm 174855682Smarkm if (argc == 1) { 174955682Smarkm mapflag = 0; 175055682Smarkm printf("Nmap off.\n"); 175155682Smarkm code = mapflag; 175255682Smarkm return; 175355682Smarkm } 175455682Smarkm if (argc < 3 && !another(&argc, &argv, "mapout")) { 175555682Smarkm printf("Usage: %s [mapin mapout]\n",argv[0]); 175655682Smarkm code = -1; 175755682Smarkm return; 175855682Smarkm } 175955682Smarkm mapflag = 1; 176055682Smarkm code = 1; 176155682Smarkm cp = strchr(altarg, ' '); 1762233294Sstas if (cp == NULL) { 1763233294Sstas printf("Usage: %s missing space\n",argv[0]); 1764233294Sstas code = -1; 1765233294Sstas return; 1766233294Sstas } 176755682Smarkm if (proxy) { 176855682Smarkm while(*++cp == ' ') 176955682Smarkm continue; 177055682Smarkm altarg = cp; 177155682Smarkm cp = strchr(altarg, ' '); 177255682Smarkm } 177355682Smarkm *cp = '\0'; 177455682Smarkm strlcpy(mapin, altarg, MaxPathLen); 177555682Smarkm while (*++cp == ' ') 177655682Smarkm continue; 177755682Smarkm strlcpy(mapout, cp, MaxPathLen); 177855682Smarkm} 177955682Smarkm 178055682Smarkmchar * 178155682Smarkmdomap(char *name) 178255682Smarkm{ 178355682Smarkm static char new[MaxPathLen]; 178455682Smarkm char *cp1 = name, *cp2 = mapin; 178555682Smarkm char *tp[9], *te[9]; 178655682Smarkm int i, toks[9], toknum = 0, match = 1; 178755682Smarkm 178855682Smarkm for (i=0; i < 9; ++i) { 178955682Smarkm toks[i] = 0; 179055682Smarkm } 179155682Smarkm while (match && *cp1 && *cp2) { 179255682Smarkm switch (*cp2) { 179355682Smarkm case '\\': 179455682Smarkm if (*++cp2 != *cp1) { 179555682Smarkm match = 0; 179655682Smarkm } 179755682Smarkm break; 179855682Smarkm case '$': 179955682Smarkm if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { 180055682Smarkm if (*cp1 != *(++cp2+1)) { 180155682Smarkm toks[toknum = *cp2 - '1']++; 180255682Smarkm tp[toknum] = cp1; 180355682Smarkm while (*++cp1 && *(cp2+1) 180455682Smarkm != *cp1); 180555682Smarkm te[toknum] = cp1; 180655682Smarkm } 180755682Smarkm cp2++; 180855682Smarkm break; 180955682Smarkm } 181055682Smarkm /* FALLTHROUGH */ 181155682Smarkm default: 181255682Smarkm if (*cp2 != *cp1) { 181355682Smarkm match = 0; 181455682Smarkm } 181555682Smarkm break; 181655682Smarkm } 181755682Smarkm if (match && *cp1) { 181855682Smarkm cp1++; 181955682Smarkm } 182055682Smarkm if (match && *cp2) { 182155682Smarkm cp2++; 182255682Smarkm } 182355682Smarkm } 182455682Smarkm if (!match && *cp1) /* last token mismatch */ 182555682Smarkm { 182655682Smarkm toks[toknum] = 0; 182755682Smarkm } 182855682Smarkm cp1 = new; 182955682Smarkm *cp1 = '\0'; 183055682Smarkm cp2 = mapout; 183155682Smarkm while (*cp2) { 183255682Smarkm match = 0; 183355682Smarkm switch (*cp2) { 183455682Smarkm case '\\': 183555682Smarkm if (*(cp2 + 1)) { 183655682Smarkm *cp1++ = *++cp2; 183755682Smarkm } 183855682Smarkm break; 183955682Smarkm case '[': 184055682SmarkmLOOP: 1841233294Sstas if (*++cp2 == '$' && isdigit((unsigned char)*(cp2+1))) { 184255682Smarkm if (*++cp2 == '0') { 184355682Smarkm char *cp3 = name; 184455682Smarkm 184555682Smarkm while (*cp3) { 184655682Smarkm *cp1++ = *cp3++; 184755682Smarkm } 184855682Smarkm match = 1; 184955682Smarkm } 185055682Smarkm else if (toks[toknum = *cp2 - '1']) { 185155682Smarkm char *cp3 = tp[toknum]; 185255682Smarkm 185355682Smarkm while (cp3 != te[toknum]) { 185455682Smarkm *cp1++ = *cp3++; 185555682Smarkm } 185655682Smarkm match = 1; 185755682Smarkm } 185855682Smarkm } 185955682Smarkm else { 1860233294Sstas while (*cp2 && *cp2 != ',' && 186155682Smarkm *cp2 != ']') { 186255682Smarkm if (*cp2 == '\\') { 186355682Smarkm cp2++; 186455682Smarkm } 186555682Smarkm else if (*cp2 == '$' && 186690926Snectar isdigit((unsigned char)*(cp2+1))) { 186755682Smarkm if (*++cp2 == '0') { 186855682Smarkm char *cp3 = name; 186955682Smarkm 187055682Smarkm while (*cp3) { 187155682Smarkm *cp1++ = *cp3++; 187255682Smarkm } 187355682Smarkm } 187455682Smarkm else if (toks[toknum = 187555682Smarkm *cp2 - '1']) { 187655682Smarkm char *cp3=tp[toknum]; 187755682Smarkm 187855682Smarkm while (cp3 != 187955682Smarkm te[toknum]) { 188055682Smarkm *cp1++ = *cp3++; 188155682Smarkm } 188255682Smarkm } 188355682Smarkm } 188455682Smarkm else if (*cp2) { 188555682Smarkm *cp1++ = *cp2++; 188655682Smarkm } 188755682Smarkm } 188855682Smarkm if (!*cp2) { 188955682Smarkm printf("nmap: unbalanced brackets\n"); 189055682Smarkm return (name); 189155682Smarkm } 189255682Smarkm match = 1; 189355682Smarkm cp2--; 189455682Smarkm } 189555682Smarkm if (match) { 189655682Smarkm while (*++cp2 && *cp2 != ']') { 189755682Smarkm if (*cp2 == '\\' && *(cp2 + 1)) { 189855682Smarkm cp2++; 189955682Smarkm } 190055682Smarkm } 190155682Smarkm if (!*cp2) { 190255682Smarkm printf("nmap: unbalanced brackets\n"); 190355682Smarkm return (name); 190455682Smarkm } 190555682Smarkm break; 190655682Smarkm } 190755682Smarkm switch (*++cp2) { 190855682Smarkm case ',': 190955682Smarkm goto LOOP; 191055682Smarkm case ']': 191155682Smarkm break; 191255682Smarkm default: 191355682Smarkm cp2--; 191455682Smarkm goto LOOP; 191555682Smarkm } 191655682Smarkm break; 191755682Smarkm case '$': 191890926Snectar if (isdigit((unsigned char)*(cp2 + 1))) { 191955682Smarkm if (*++cp2 == '0') { 192055682Smarkm char *cp3 = name; 192155682Smarkm 192255682Smarkm while (*cp3) { 192355682Smarkm *cp1++ = *cp3++; 192455682Smarkm } 192555682Smarkm } 192655682Smarkm else if (toks[toknum = *cp2 - '1']) { 192755682Smarkm char *cp3 = tp[toknum]; 192855682Smarkm 192955682Smarkm while (cp3 != te[toknum]) { 193055682Smarkm *cp1++ = *cp3++; 193155682Smarkm } 193255682Smarkm } 193355682Smarkm break; 193455682Smarkm } 193555682Smarkm /* intentional drop through */ 193655682Smarkm default: 193755682Smarkm *cp1++ = *cp2; 193855682Smarkm break; 193955682Smarkm } 194055682Smarkm cp2++; 194155682Smarkm } 194255682Smarkm *cp1 = '\0'; 194355682Smarkm if (!*new) { 194455682Smarkm return (name); 194555682Smarkm } 194655682Smarkm return (new); 194755682Smarkm} 194855682Smarkm 194955682Smarkmvoid 195055682Smarkmsetpassive(int argc, char **argv) 195155682Smarkm{ 195255682Smarkm 195355682Smarkm passivemode = !passivemode; 195455682Smarkm printf("Passive mode %s.\n", onoff(passivemode)); 195555682Smarkm code = passivemode; 195655682Smarkm} 195755682Smarkm 195855682Smarkmvoid 195955682Smarkmsetsunique(int argc, char **argv) 196055682Smarkm{ 196155682Smarkm 196255682Smarkm sunique = !sunique; 196355682Smarkm printf("Store unique %s.\n", onoff(sunique)); 196455682Smarkm code = sunique; 196555682Smarkm} 196655682Smarkm 196755682Smarkmvoid 196855682Smarkmsetrunique(int argc, char **argv) 196955682Smarkm{ 197055682Smarkm 197155682Smarkm runique = !runique; 197255682Smarkm printf("Receive unique %s.\n", onoff(runique)); 197355682Smarkm code = runique; 197455682Smarkm} 197555682Smarkm 197655682Smarkm/* change directory to perent directory */ 197755682Smarkmvoid 197855682Smarkmcdup(int argc, char **argv) 197955682Smarkm{ 198055682Smarkm 198155682Smarkm if (command("CDUP") == ERROR && code == 500) { 198255682Smarkm if (verbose) 198355682Smarkm printf("CDUP command not recognized, trying XCUP\n"); 198455682Smarkm command("XCUP"); 198555682Smarkm } 198655682Smarkm} 198755682Smarkm 198855682Smarkm/* restart transfer at specific point */ 198955682Smarkmvoid 199055682Smarkmrestart(int argc, char **argv) 199155682Smarkm{ 199255682Smarkm 199355682Smarkm if (argc != 2) 199455682Smarkm printf("restart: offset not specified\n"); 199555682Smarkm else { 199655682Smarkm restart_point = atol(argv[1]); 199755682Smarkm printf("restarting at %ld. %s\n", (long)restart_point, 199855682Smarkm "execute get, put or append to initiate transfer"); 199955682Smarkm } 200055682Smarkm} 200155682Smarkm 200255682Smarkm/* show remote system type */ 200355682Smarkmvoid 200455682Smarkmsyst(int argc, char **argv) 200555682Smarkm{ 200655682Smarkm 200755682Smarkm command("SYST"); 200855682Smarkm} 200955682Smarkm 201055682Smarkmvoid 201155682Smarkmmacdef(int argc, char **argv) 201255682Smarkm{ 201355682Smarkm char *tmp; 201455682Smarkm int c; 201555682Smarkm 201655682Smarkm if (macnum == 16) { 201755682Smarkm printf("Limit of 16 macros have already been defined\n"); 201855682Smarkm code = -1; 201955682Smarkm return; 202055682Smarkm } 202155682Smarkm if (argc < 2 && !another(&argc, &argv, "macro name")) { 202255682Smarkm printf("Usage: %s macro_name\n",argv[0]); 202355682Smarkm code = -1; 202455682Smarkm return; 202555682Smarkm } 202655682Smarkm if (interactive) { 202755682Smarkm printf("Enter macro line by line, terminating it with a null line\n"); 202855682Smarkm } 202955682Smarkm strlcpy(macros[macnum].mac_name, 203055682Smarkm argv[1], 203155682Smarkm sizeof(macros[macnum].mac_name)); 203255682Smarkm if (macnum == 0) { 203355682Smarkm macros[macnum].mac_start = macbuf; 203455682Smarkm } 203555682Smarkm else { 203655682Smarkm macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; 203755682Smarkm } 203855682Smarkm tmp = macros[macnum].mac_start; 203955682Smarkm while (tmp != macbuf+4096) { 204055682Smarkm if ((c = getchar()) == EOF) { 204155682Smarkm printf("macdef:end of file encountered\n"); 204255682Smarkm code = -1; 204355682Smarkm return; 204455682Smarkm } 204555682Smarkm if ((*tmp = c) == '\n') { 204655682Smarkm if (tmp == macros[macnum].mac_start) { 204755682Smarkm macros[macnum++].mac_end = tmp; 204855682Smarkm code = 0; 204955682Smarkm return; 205055682Smarkm } 205155682Smarkm if (*(tmp-1) == '\0') { 205255682Smarkm macros[macnum++].mac_end = tmp - 1; 205355682Smarkm code = 0; 205455682Smarkm return; 205555682Smarkm } 205655682Smarkm *tmp = '\0'; 205755682Smarkm } 205855682Smarkm tmp++; 205955682Smarkm } 206055682Smarkm while (1) { 206155682Smarkm while ((c = getchar()) != '\n' && c != EOF) 206255682Smarkm /* LOOP */; 206355682Smarkm if (c == EOF || getchar() == '\n') { 206455682Smarkm printf("Macro not defined - 4k buffer exceeded\n"); 206555682Smarkm code = -1; 206655682Smarkm return; 206755682Smarkm } 206855682Smarkm } 206955682Smarkm} 207055682Smarkm 207155682Smarkm/* 207255682Smarkm * get size of file on remote machine 207355682Smarkm */ 207455682Smarkmvoid 207555682Smarkmsizecmd(int argc, char **argv) 207655682Smarkm{ 207755682Smarkm 207855682Smarkm if (argc < 2 && !another(&argc, &argv, "filename")) { 207955682Smarkm printf("usage: %s filename\n", argv[0]); 208055682Smarkm code = -1; 208155682Smarkm return; 208255682Smarkm } 208355682Smarkm command("SIZE %s", argv[1]); 208455682Smarkm} 208555682Smarkm 208655682Smarkm/* 208755682Smarkm * get last modification time of file on remote machine 208855682Smarkm */ 208955682Smarkmvoid 209055682Smarkmmodtime(int argc, char **argv) 209155682Smarkm{ 209255682Smarkm int overbose; 209355682Smarkm 209455682Smarkm if (argc < 2 && !another(&argc, &argv, "filename")) { 209555682Smarkm printf("usage: %s filename\n", argv[0]); 209655682Smarkm code = -1; 209755682Smarkm return; 209855682Smarkm } 209955682Smarkm overbose = verbose; 210055682Smarkm if (debug == 0) 210155682Smarkm verbose = -1; 210255682Smarkm if (command("MDTM %s", argv[1]) == COMPLETE) { 210355682Smarkm int yy, mo, day, hour, min, sec; 210455682Smarkm sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, 210555682Smarkm &day, &hour, &min, &sec); 210655682Smarkm /* might want to print this in local time */ 210755682Smarkm printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], 210855682Smarkm mo, day, yy, hour, min, sec); 210955682Smarkm } else 211055682Smarkm printf("%s\n", reply_string); 211155682Smarkm verbose = overbose; 211255682Smarkm} 211355682Smarkm 211455682Smarkm/* 211555682Smarkm * show status on reomte machine 211655682Smarkm */ 211755682Smarkmvoid 211855682Smarkmrmtstatus(int argc, char **argv) 211955682Smarkm{ 212055682Smarkm 212155682Smarkm command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); 212255682Smarkm} 212355682Smarkm 212455682Smarkm/* 212555682Smarkm * get file if modtime is more recent than current file 212655682Smarkm */ 212755682Smarkmvoid 212855682Smarkmnewer(int argc, char **argv) 212955682Smarkm{ 213055682Smarkm 213155682Smarkm if (getit(argc, argv, -1, curtype == TYPE_I ? "wb" : "w")) 213255682Smarkm printf("Local file \"%s\" is newer than remote file \"%s\"\n", 213355682Smarkm argv[2], argv[1]); 213455682Smarkm} 2135178825Sdfr 2136178825Sdfrvoid 2137178825Sdfrklist(int argc, char **argv) 2138178825Sdfr{ 2139178825Sdfr int ret; 2140178825Sdfr if(argc != 1){ 2141178825Sdfr printf("usage: %s\n", argv[0]); 2142178825Sdfr code = -1; 2143178825Sdfr return; 2144178825Sdfr } 2145233294Sstas 2146178825Sdfr ret = command("SITE KLIST"); 2147178825Sdfr code = (ret == COMPLETE); 2148178825Sdfr} 2149