X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b36fc5105e258115b789bc62b067632dfc528a05..2c5d7f0d9c585d802fda462dedefa62250eeb73d:/usr/src/usr.bin/ftp/cmds.c diff --git a/usr/src/usr.bin/ftp/cmds.c b/usr/src/usr.bin/ftp/cmds.c index b2ca8ddee6..56cc42806f 100644 --- a/usr/src/usr.bin/ftp/cmds.c +++ b/usr/src/usr.bin/ftp/cmds.c @@ -1,28 +1,46 @@ /* - * Copyright (c) 1985 Regents of the University of California. + * Copyright (c) 1985, 1989 Regents of the University of California. * All rights reserved. * - * Redistribution and use in source and binary forms are permitted - * provided that the above copyright notice and this paragraph are - * duplicated in all such forms and that any documentation, - * advertising materials, and other materials related to such - * distribution and use acknowledge that the software was developed - * by the University of California, Berkeley. The name of the - * University may not be used to endorse or promote products derived - * from this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ #ifndef lint -static char sccsid[] = "@(#)cmds.c 5.8 (Berkeley) %G%"; +static char sccsid[] = "@(#)cmds.c 5.26 (Berkeley) 3/5/91"; #endif /* not lint */ /* * FTP User Program -- Command Routines. */ -#include "ftp_var.h" +#include +#include +#include #include #include @@ -32,21 +50,60 @@ static char sccsid[] = "@(#)cmds.c 5.8 (Berkeley) %G%"; #include #include #include -#include +#include +#include +#include "ftp_var.h" +#include "pathnames.h" extern char *globerr; -extern char **glob(); +extern char **ftpglob(); extern char *home; -extern short gflag; extern char *remglob(); extern char *getenv(); extern char *index(); extern char *rindex(); +extern char *strerror(); +extern int errno; +extern off_t restart_point; +extern char reply_string[]; + char *mname; jmp_buf jabort; char *dotrans(), *domap(); +/* + * `Another' gets another argument, and stores the new argc and argv. + * It reverts to the top level (via main.c's intr()) on EOF/error. + * + * Returns false if no new arguments have been added. + */ +another(pargc, pargv, prompt) + int *pargc; + char ***pargv; + char *prompt; +{ + int len = strlen(line), ret; + extern sig_t intr(); + + if (len >= sizeof(line) - 3) { + printf("sorry, arguments too long\n"); + intr(); + } + printf("(%s) ", prompt); + line[len++] = ' '; + if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) + intr(); + len += strlen(&line[len]); + if (len > 0 && line[len - 1] == '\n') + line[len - 1] = '\0'; + makeargv(); + ret = margc > *pargc; + *pargc = margc; + *pargv = margv; + return (ret); +} + /* * Connect to peer server and * auto-login, if possible. @@ -56,7 +113,7 @@ setpeer(argc, argv) char *argv[]; { char *host, *hookup(); - int port; + short port; if (connected) { printf("Already connected to %s, use close first.\n", @@ -64,15 +121,9 @@ setpeer(argc, argv) code = -1; return; } - if (argc < 2) { - (void) strcat(line, " "); - printf("(to) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc > 3) { + if (argc < 2) + (void) another(&argc, &argv, "to"); + if (argc < 2 || argc > 3) { printf("usage: %s host-name [port]\n", argv[0]); code = -1; return; @@ -90,9 +141,74 @@ setpeer(argc, argv) } host = hookup(argv[1], port); if (host) { + int overbose; + connected = 1; + /* + * Set up defaults for FTP. + */ + (void) strcpy(typename, "ascii"), type = TYPE_A; + curtype = TYPE_A; + (void) strcpy(formname, "non-print"), form = FORM_N; + (void) strcpy(modename, "stream"), mode = MODE_S; + (void) strcpy(structname, "file"), stru = STRU_F; + (void) strcpy(bytename, "8"), bytesize = 8; if (autologin) (void) login(argv[1]); + +#if defined(unix) && NBBY == 8 +/* + * this ifdef is to keep someone form "porting" this to an incompatible + * system and not checking this out. This way they have to think about it. + */ + overbose = verbose; + if (debug == 0) + verbose = -1; + if (command("SYST") == COMPLETE && overbose) { + register char *cp, c; + cp = index(reply_string+4, ' '); + if (cp == NULL) + cp = index(reply_string+4, '\r'); + if (cp) { + if (cp[-1] == '.') + cp--; + c = *cp; + *cp = '\0'; + } + + printf("Remote system type is %s.\n", + reply_string+4); + if (cp) + *cp = c; + } + if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) { + if (proxy) + unix_proxy = 1; + else + unix_server = 1; + /* + * Set type to 0 (not specified by user), + * meaning binary by default, but don't bother + * telling server. We can use binary + * for text files unless changed by the user. + */ + type = 0; + (void) strcpy(typename, "binary"); + if (overbose) + printf("Using %s mode to transfer files.\n", + typename); + } else { + if (proxy) + unix_proxy = 0; + else + unix_server = 0; + if (overbose && + !strncmp(reply_string, "215 TOPS20", 10)) + printf( +"Remember to set tenex mode when transfering binary files from this machine.\n"); + } + verbose = overbose; +#endif /* unix */ } } @@ -114,6 +230,7 @@ struct types { * Set transfer type. */ settype(argc, argv) + int argc; char *argv[]; { register struct types *p; @@ -126,8 +243,7 @@ settype(argc, argv) sep = " "; for (p = types; p->t_name; p++) { printf("%s%s", sep, p->t_name); - if (*sep == ' ') - sep = " | "; + sep = " | "; } printf(" ]\n"); code = -1; @@ -152,48 +268,77 @@ settype(argc, argv) comret = command("TYPE %s", p->t_mode); if (comret == COMPLETE) { (void) strcpy(typename, p->t_name); - type = p->t_type; + curtype = type = p->t_type; } } /* - * Set binary transfer type. + * Internal form of settype; changes current type in use with server + * without changing our notion of the type for data transfers. + * Used to change to and from ascii for listings. */ -/*VARARGS*/ -setbinary() +changetype(newtype, show) + int newtype, show; { + register struct types *p; + int comret, oldverbose = verbose; - call(settype, "type", "binary", 0); + if (newtype == 0) + newtype = TYPE_I; + if (newtype == curtype) + return; + if (debug == 0 && show == 0) + verbose = 0; + for (p = types; p->t_name; p++) + if (newtype == p->t_type) + break; + if (p->t_name == 0) { + printf("ftp: internal error: unknown type %d\n", newtype); + return; + } + if (newtype == TYPE_L && bytename[0] != '\0') + comret = command("TYPE %s %s", p->t_mode, bytename); + else + comret = command("TYPE %s", p->t_mode); + if (comret == COMPLETE) + curtype = newtype; + verbose = oldverbose; } +char *stype[] = { + "type", + "", + 0 +}; + /* - * Set ascii transfer type. + * Set binary transfer type. */ /*VARARGS*/ -setascii() +setbinary() { - - call(settype, "type", "ascii", 0); + stype[1] = "binary"; + settype(2, stype); } /* - * Set tenex transfer type. + * Set ascii transfer type. */ /*VARARGS*/ -settenex() +setascii() { - - call(settype, "type", "tenex", 0); + stype[1] = "ascii"; + settype(2, stype); } /* - * Set ebcdic transfer type. + * Set tenex transfer type. */ /*VARARGS*/ -setebcdic() +settenex() { - - call(settype, "type", "ebcdic", 0); + stype[1] = "tenex"; + settype(2, stype); } /* @@ -201,6 +346,7 @@ setebcdic() */ /*ARGSUSED*/ setmode(argc, argv) + int argc; char *argv[]; { @@ -213,6 +359,7 @@ setmode(argc, argv) */ /*ARGSUSED*/ setform(argc, argv) + int argc; char *argv[]; { @@ -225,6 +372,7 @@ setform(argc, argv) */ /*ARGSUSED*/ setstruct(argc, argv) + int argc; char *argv[]; { @@ -241,38 +389,23 @@ put(argc, argv) { char *cmd; int loc = 0; - char *oldargv1; + char *oldargv1, *oldargv2; if (argc == 2) { argc++; argv[2] = argv[1]; loc++; } - if (argc < 2) { - (void) strcat(line, " "); - printf("(local-file) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { + if (argc < 2 && !another(&argc, &argv, "local-file")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "remote-file")) { usage: - printf("usage:%s local-file remote-file\n", argv[0]); + printf("usage: %s local-file remote-file\n", argv[0]); code = -1; return; } - if (argc < 3) { - (void) strcat(line, " "); - printf("(remote-file) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 3) - goto usage; oldargv1 = argv[1]; + oldargv2 = argv[2]; if (!globulize(&argv[1])) { code = -1; return; @@ -291,30 +424,26 @@ usage: if (loc && mapflag) { argv[2] = domap(argv[2]); } - sendrequest(cmd, argv[1], argv[2]); + sendrequest(cmd, argv[1], argv[2], + argv[1] != oldargv1 || argv[2] != oldargv2); } /* * Send multiple files. */ mput(argc, argv) - char *argv[]; + int argc; + char **argv; { - register int i; - int ointer, (*oldintr)(), mabort(); extern jmp_buf jabort; + register int i; + sig_t oldintr; + int ointer; char *tp; + void mabort(); - if (argc < 2) { - (void) strcat(line, " "); - printf("(local-files) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { - printf("usage:%s local-files\n", argv[0]); + if (argc < 2 && !another(&argc, &argv, "local-files")) { + printf("usage: %s local-files\n", argv[0]); code = -1; return; } @@ -355,7 +484,8 @@ mput(argc, argv) if (mapflag) { tp = domap(tp); } - sendrequest((sunique) ? "STOU" : "STOR", cp,tp); + sendrequest((sunique) ? "STOU" : "STOR", + cp, tp, cp != tp || !interactive); if (!mflag && fromatty) { ointer = interactive; interactive = 1; @@ -378,7 +508,7 @@ mput(argc, argv) tp = (ntflag) ? dotrans(argv[i]) : argv[i]; tp = (mapflag) ? domap(tp) : tp; sendrequest((sunique) ? "STOU" : "STOR", - argv[i], tp); + argv[i], tp, tp != argv[i] || !interactive); if (!mflag && fromatty) { ointer = interactive; interactive = 1; @@ -390,11 +520,13 @@ mput(argc, argv) } continue; } - gargs = glob(argv[i]); + gargs = ftpglob(argv[i]); if (globerr != NULL) { printf("%s\n", globerr); - if (gargs) + if (gargs) { blkfree(gargs); + free((char *)gargs); + } continue; } for (cpp = gargs; cpp && *cpp != NULL; cpp++) { @@ -402,7 +534,7 @@ mput(argc, argv) tp = (ntflag) ? dotrans(*cpp) : *cpp; tp = (mapflag) ? domap(tp) : tp; sendrequest((sunique) ? "STOU" : "STOR", - *cpp, tp); + *cpp, tp, *cpp != tp || !interactive); if (!mflag && fromatty) { ointer = interactive; interactive = 1; @@ -413,53 +545,58 @@ mput(argc, argv) } } } - if (gargs != NULL) + if (gargs != NULL) { blkfree(gargs); + free((char *)gargs); + } } (void) signal(SIGINT, oldintr); mflag = 0; } +reget(argc, argv) + int argc; + char *argv[]; +{ + (void) getit(argc, argv, 1, "r+w"); +} + +get(argc, argv) + int argc; + char *argv[]; +{ + (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" ); +} + /* * Receive one file. */ -get(argc, argv) +getit(argc, argv, restartit, mode) + int argc; char *argv[]; + char *mode; { int loc = 0; + char *oldargv1, *oldargv2; if (argc == 2) { argc++; argv[2] = argv[1]; loc++; } - if (argc < 2) { - (void) strcat(line, " "); - printf("(remote-file) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { + if (argc < 2 && !another(&argc, &argv, "remote-file")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "local-file")) { usage: printf("usage: %s remote-file [ local-file ]\n", argv[0]); code = -1; - return; - } - if (argc < 3) { - (void) strcat(line, " "); - printf("(local-file) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; + return (0); } - if (argc < 3) - goto usage; + oldargv1 = argv[1]; + oldargv2 = argv[2]; if (!globulize(&argv[2])) { code = -1; - return; + return (0); } if (loc && mcase) { char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN]; @@ -480,15 +617,72 @@ usage: argv[2] = tmpbuf; } } - if (loc && ntflag) { + if (loc && ntflag) argv[2] = dotrans(argv[2]); - } - if (loc && mapflag) { + if (loc && mapflag) argv[2] = domap(argv[2]); + if (restartit) { + struct stat stbuf; + int ret; + + ret = stat(argv[2], &stbuf); + if (restartit == 1) { + if (ret < 0) { + fprintf(stderr, "local: %s: %s\n", argv[2], + strerror(errno)); + return (0); + } + restart_point = stbuf.st_size; + } else { + if (ret == 0) { + int overbose; + + overbose = verbose; + if (debug == 0) + verbose = -1; + if (command("MDTM %s", argv[1]) == COMPLETE) { + int yy, mo, day, hour, min, sec; + struct tm *tm; + verbose = overbose; + sscanf(reply_string, + "%*s %04d%02d%02d%02d%02d%02d", + &yy, &mo, &day, &hour, &min, &sec); + tm = gmtime(&stbuf.st_mtime); + tm->tm_mon++; + if (tm->tm_year > yy%100) + return (1); + else if (tm->tm_year == yy%100) { + if (tm->tm_mon > mo) + return (1); + } else if (tm->tm_mon == mo) { + if (tm->tm_mday > day) + return (1); + } else if (tm->tm_mday == day) { + if (tm->tm_hour > hour) + return (1); + } else if (tm->tm_hour == hour) { + if (tm->tm_min > min) + return (1); + } else if (tm->tm_min == min) { + if (tm->tm_sec > sec) + return (1); + } + } else { + printf("%s\n", reply_string); + verbose = overbose; + return (0); + } + } + } } - recvrequest("RETR", argv[2], argv[1], "w"); + + recvrequest("RETR", argv[2], argv[1], mode, + argv[1] != oldargv1 || argv[2] != oldargv2); + restart_point = 0; + return (0); } +void mabort() { int ointer; @@ -513,22 +707,17 @@ mabort() * Get multiple files. */ mget(argc, argv) - char *argv[]; + int argc; + char **argv; { - char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; - int ointer, (*oldintr)(), mabort(); extern jmp_buf jabort; + sig_t oldintr; + int ointer; + char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN]; + void mabort(); - if (argc < 2) { - (void) strcat(line, " "); - printf("(remote-files) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { - printf("usage:%s remote-files\n", argv[0]); + if (argc < 2 && !another(&argc, &argv, "remote-files")) { + printf("usage: %s remote-files\n", argv[0]); code = -1; return; } @@ -566,7 +755,8 @@ mget(argc, argv) if (mapflag) { tp = domap(tp); } - recvrequest("RETR", tp, cp, "w"); + recvrequest("RETR", tp, cp, "w", + tp != cp || !interactive); if (!mflag && fromatty) { ointer = interactive; interactive = 1; @@ -613,7 +803,7 @@ remglob(argv,doswitch) return (cp); } if (ftemp == NULL) { - (void) strcpy(temp, "/tmp/ftpXXXXXX"); + (void) strcpy(temp, _PATH_TMP); (void) mktemp(temp); oldverbose = verbose, verbose = 0; oldhash = hash, hash = 0; @@ -621,7 +811,7 @@ remglob(argv,doswitch) pswitch(!proxy); } for (mode = "w"; *++argv != NULL; mode = "a") - recvrequest ("NLST", temp, *argv, mode); + recvrequest ("NLST", temp, *argv, mode, 0); if (doswitch) { pswitch(!proxy); } @@ -655,6 +845,7 @@ onoff(bool) */ /*ARGSUSED*/ status(argc, argv) + int argc; char *argv[]; { int i; @@ -739,7 +930,7 @@ sethash() printf("Hash mark printing %s", onoff(hash)); code = hash; if (hash) - printf(" (%d bytes/hash mark)", BUFSIZ); + printf(" (%d bytes/hash mark)", 1024); printf(".\n"); } @@ -799,6 +990,7 @@ setglob() */ /*VARARGS*/ setdebug(argc, argv) + int argc; char *argv[]; { int val; @@ -826,23 +1018,20 @@ setdebug(argc, argv) * on remote machine. */ cd(argc, argv) + int argc; char *argv[]; { - if (argc < 2) { - (void) strcat(line, " "); - printf("(remote-directory) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { - printf("usage:%s remote-directory\n", argv[0]); + if (argc < 2 && !another(&argc, &argv, "remote-directory")) { + printf("usage: %s remote-directory\n", argv[0]); code = -1; return; } - (void) command("CWD %s", argv[1]); + if (command("CWD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("CWD command not recognized, trying XCWD\n"); + (void) command("XCWD %s", argv[1]); + } } /* @@ -850,14 +1039,16 @@ cd(argc, argv) * on local machine. */ lcd(argc, argv) + int argc; char *argv[]; { char buf[MAXPATHLEN]; + extern char *getwd(); if (argc < 2) argc++, argv[1] = home; if (argc != 2) { - printf("usage:%s local-directory\n", argv[0]); + printf("usage: %s local-directory\n", argv[0]); code = -1; return; } @@ -866,7 +1057,7 @@ lcd(argc, argv) return; } if (chdir(argv[1]) < 0) { - perror(argv[1]); + fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno)); code = -1; return; } @@ -878,19 +1069,12 @@ lcd(argc, argv) * Delete a single file. */ delete(argc, argv) + int argc; char *argv[]; { - if (argc < 2) { - (void) strcat(line, " "); - printf("(remote-file) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { - printf("usage:%s remote-file\n", argv[0]); + if (argc < 2 && !another(&argc, &argv, "remote-file")) { + printf("usage: %s remote-file\n", argv[0]); code = -1; return; } @@ -901,22 +1085,17 @@ delete(argc, argv) * Delete multiple files. */ mdelete(argc, argv) - char *argv[]; + int argc; + char **argv; { - char *cp; - int ointer, (*oldintr)(), mabort(); extern jmp_buf jabort; + sig_t oldintr; + int ointer; + char *cp; + void mabort(); - if (argc < 2) { - (void) strcat(line, " "); - printf("(remote-files) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { - printf("usage:%s remote-files\n", argv[0]); + if (argc < 2 && !another(&argc, &argv, "remote-files")) { + printf("usage: %s remote-files\n", argv[0]); code = -1; return; } @@ -949,33 +1128,18 @@ mdelete(argc, argv) * Rename a remote file. */ renamefile(argc, argv) + int argc; char *argv[]; { - if (argc < 2) { - (void) strcat(line, " "); - printf("(from-name) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { + if (argc < 2 && !another(&argc, &argv, "from-name")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "to-name")) { usage: printf("%s from-name to-name\n", argv[0]); code = -1; return; } - if (argc < 3) { - (void) strcat(line, " "); - printf("(to-name) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 3) - goto usage; if (command("RNFR %s", argv[1]) == CONTINUE) (void) command("RNTO %s", argv[2]); } @@ -985,6 +1149,7 @@ usage: * of remote files. */ ls(argc, argv) + int argc; char *argv[]; { char *cmd; @@ -998,7 +1163,7 @@ ls(argc, argv) code = -1; return; } - cmd = argv[0][0] == 'l' ? "NLST" : "LIST"; + cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; if (strcmp(argv[2], "-") && !globulize(&argv[2])) { code = -1; return; @@ -1008,7 +1173,7 @@ ls(argc, argv) code = -1; return; } - recvrequest(cmd, argv[2], argv[1], "w"); + recvrequest(cmd, argv[2], argv[1], "w", 0); } /* @@ -1016,37 +1181,28 @@ ls(argc, argv) * of multiple remote files. */ mls(argc, argv) - char *argv[]; + int argc; + char **argv; { - char *cmd, mode[1], *dest; - int ointer, i, (*oldintr)(), mabort(); extern jmp_buf jabort; + sig_t oldintr; + int ointer, i; + char *cmd, mode[1], *dest; + void mabort(); - if (argc < 2) { - (void) strcat(line, " "); - printf("(remote-files) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 3) { - (void) strcat(line, " "); - printf("(local-file) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 3) { - printf("usage:%s remote-files local-file\n", argv[0]); + if (argc < 2 && !another(&argc, &argv, "remote-files")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "local-file")) { +usage: + printf("usage: %s remote-files local-file\n", argv[0]); code = -1; return; } dest = argv[argc - 1]; argv[argc - 1] = NULL; if (strcmp(dest, "-") && *dest != '|') - if (!globulize(&dest) || !confirm("output to local-file:", dest)) { + if (!globulize(&dest) || + !confirm("output to local-file:", dest)) { code = -1; return; } @@ -1057,7 +1213,7 @@ mls(argc, argv) (void) setjmp(jabort); for (i = 1; mflag && i < argc-1; ++i) { *mode = (i == 1) ? 'w' : 'a'; - recvrequest(cmd, dest, argv[i], mode); + recvrequest(cmd, dest, argv[i], mode, 0); if (!mflag && fromatty) { ointer = interactive; interactive = 1; @@ -1076,9 +1232,11 @@ mls(argc, argv) */ /*ARGSUSED*/ shell(argc, argv) - char *argv[]; + int argc; + char **argv; { - int pid, (*old1)(), (*old2)(); + int pid; + sig_t old1, old2; char shellnam[40], *shell, *namep; union wait status; @@ -1091,7 +1249,7 @@ shell(argc, argv) (void) signal(SIGQUIT, SIG_DFL); shell = getenv("SHELL"); if (shell == NULL) - shell = "/bin/sh"; + shell = _PATH_BSHELL; namep = rindex(shell,'/'); if (namep == NULL) namep = shell; @@ -1114,7 +1272,7 @@ shell(argc, argv) exit(1); } if (pid > 0) - while (wait(&status) != pid) + while (wait((int *)&status) != pid) ; (void) signal(SIGINT, old1); (void) signal(SIGQUIT, old2); @@ -1135,18 +1293,12 @@ user(argc, argv) int argc; char **argv; { - char acct[80], *mygetpass(); + char acct[80], *getpass(); int n, aflag = 0; - if (argc < 2) { - (void) strcat(line, " "); - printf("(username) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc > 4) { + if (argc < 2) + (void) another(&argc, &argv, "username"); + if (argc < 2 || argc > 4) { printf("usage: %s username [password] [account]\n", argv[0]); code = -1; return (0); @@ -1154,7 +1306,7 @@ user(argc, argv) n = command("USER %s", argv[1]); if (n == CONTINUE) { if (argc < 3 ) - argv[2] = mygetpass("Password: "), argc++; + argv[2] = getpass("Password: "), argc++; n = command("PASS %s", argv[2]); } if (n == CONTINUE) { @@ -1183,92 +1335,162 @@ user(argc, argv) /*VARARGS*/ pwd() { + int oldverbose = verbose; - (void) command("PWD"); + /* + * If we aren't verbose, this doesn't do anything! + */ + verbose = 1; + if (command("PWD") == ERROR && code == 500) { + printf("PWD command not recognized, trying XPWD\n"); + (void) command("XPWD"); + } + verbose = oldverbose; } /* * Make a directory. */ makedir(argc, argv) + int argc; char *argv[]; { - if (argc < 2) { - (void) strcat(line, " "); - printf("(directory-name) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { + if (argc < 2 && !another(&argc, &argv, "directory-name")) { printf("usage: %s directory-name\n", argv[0]); code = -1; return; } - (void) command("MKD %s", argv[1]); + if (command("MKD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("MKD command not recognized, trying XMKD\n"); + (void) command("XMKD %s", argv[1]); + } } /* * Remove a directory. */ removedir(argc, argv) + int argc; char *argv[]; { - if (argc < 2) { - (void) strcat(line, " "); - printf("(directory-name) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { + if (argc < 2 && !another(&argc, &argv, "directory-name")) { printf("usage: %s directory-name\n", argv[0]); code = -1; return; } - (void) command("RMD %s", argv[1]); + if (command("RMD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("RMD command not recognized, trying XRMD\n"); + (void) command("XRMD %s", argv[1]); + } } /* * Send a line, verbatim, to the remote machine. */ quote(argc, argv) + int argc; char *argv[]; { - int i; - char buf[BUFSIZ]; - if (argc < 2) { - (void) strcat(line, " "); - printf("(command line to send) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; + if (argc < 2 && !another(&argc, &argv, "command line to send")) { + printf("usage: %s line-to-send\n", argv[0]); + code = -1; + return; } - if (argc < 2) { + quote1("", argc, argv); +} + +/* + * Send a SITE command to the remote machine. The line + * is sent verbatim to the remote machine, except that the + * word "SITE" is added at the front. + */ +site(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "arguments to SITE command")) { printf("usage: %s line-to-send\n", argv[0]); code = -1; return; } - (void) strcpy(buf, argv[1]); - for (i = 2; i < argc; i++) { - (void) strcat(buf, " "); - (void) strcat(buf, argv[i]); + quote1("SITE ", argc, argv); +} + +/* + * Turn argv[1..argc) into a space-separated string, then prepend initial text. + * Send the result as a one-line command and get response. + */ +quote1(initial, argc, argv) + char *initial; + int argc; + char **argv; +{ + register int i, len; + char buf[BUFSIZ]; /* must be >= sizeof(line) */ + + (void) strcpy(buf, initial); + if (argc > 1) { + len = strlen(buf); + len += strlen(strcpy(&buf[len], argv[1])); + for (i = 2; i < argc; i++) { + buf[len++] = ' '; + len += strlen(strcpy(&buf[len], argv[i])); + } } if (command(buf) == PRELIM) { while (getreply(0) == PRELIM); } } +do_chmod(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "mode")) + goto usage; + if (argc < 3 && !another(&argc, &argv, "file-name")) { +usage: + printf("usage: %s mode file-name\n", argv[0]); + code = -1; + return; + } + (void) command("SITE CHMOD %s %s", argv[1], argv[2]); +} + +do_umask(argc, argv) + int argc; + char *argv[]; +{ + int oldverbose = verbose; + + verbose = 1; + (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); + verbose = oldverbose; +} + +idle(argc, argv) + int argc; + char *argv[]; +{ + int oldverbose = verbose; + + verbose = 1; + (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); + verbose = oldverbose; +} + /* * Ask the other side for help. */ rmthelp(argc, argv) + int argc; char *argv[]; { int oldverbose = verbose; @@ -1325,7 +1547,8 @@ confirm(cmd, file) return (1); printf("%s %s? ", cmd, file); (void) fflush(stdout); - (void) gets(line); + if (fgets(line, sizeof line, stdin) == NULL) + return (0); return (*line != 'n' && *line != 'N'); } @@ -1350,34 +1573,37 @@ globulize(cpp) if (!doglob) return (1); - globbed = glob(*cpp); + globbed = ftpglob(*cpp); if (globerr != NULL) { printf("%s: %s\n", *cpp, globerr); - if (globbed) + if (globbed) { blkfree(globbed); + free((char *)globbed); + } return (0); } if (globbed) { *cpp = *globbed++; /* don't waste too much memory */ - if (*globbed) + if (*globbed) { blkfree(globbed); + free((char *)globbed); + } } return (1); } account(argc,argv) - int argc; char **argv; { - char acct[50], *mygetpass(), *ap; + char acct[50], *getpass(), *ap; if (argc > 1) { ++argv; --argc; (void) strncpy(acct,*argv,49); - acct[50] = '\0'; + acct[49] = '\0'; while (argc > 1) { --argc; ++argv; @@ -1386,13 +1612,14 @@ account(argc,argv) ap = acct; } else { - ap = mygetpass("Account:"); + ap = getpass("Account:"); } (void) command("ACCT %s", ap); } jmp_buf abortprox; +void proxabort() { extern int proxy; @@ -1414,22 +1641,15 @@ doproxy(argc,argv) int argc; char *argv[]; { - int (*oldintr)(), proxabort(); - register struct cmd *c; - struct cmd *getcmd(); extern struct cmd cmdtab[]; extern jmp_buf abortprox; + register struct cmd *c; + struct cmd *getcmd(); + sig_t oldintr; + void proxabort(); - if (argc < 2) { - (void) strcat(line, " "); - printf("(command) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 2) { - printf("usage:%s command\n", argv[0]); + if (argc < 2 && !another(&argc, &argv, "command")) { + printf("usage: %s command\n", argv[0]); code = -1; return; } @@ -1553,15 +1773,7 @@ setnmap(argc, argv) code = mapflag; return; } - if (argc < 3) { - (void) strcat(line, " "); - printf("(mapout) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc < 3) { + if (argc < 3 && !another(&argc, &argv, "mapout")) { printf("Usage: %s [mapin mapout]\n",argv[0]); code = -1; return; @@ -1587,7 +1799,7 @@ domap(name) static char new[MAXPATHLEN]; register char *cp1 = name, *cp2 = mapin; char *tp[9], *te[9]; - int i, toks[9], toknum, match = 1; + int i, toks[9], toknum = 0, match = 1; for (i=0; i < 9; ++i) { toks[i] = 0; @@ -1611,20 +1823,24 @@ domap(name) cp2++; break; } - /* intentional drop through */ + /* FALLTHROUGH */ default: if (*cp2 != *cp1) { match = 0; } break; } - if (*cp1) { + if (match && *cp1) { cp1++; } - if (*cp2) { + if (match && *cp2) { cp2++; } } + if (!match && *cp1) /* last token mismatch */ + { + toks[toknum] = 0; + } cp1 = new; *cp1 = '\0'; cp2 = mapout; @@ -1763,7 +1979,32 @@ setrunique() /* change directory to perent directory */ cdup() { - (void) command("CDUP"); + if (command("CDUP") == ERROR && code == 500) { + if (verbose) + printf("CDUP command not recognized, trying XCUP\n"); + (void) command("XCUP"); + } +} + +/* restart transfer at specific point */ +restart(argc, argv) + int argc; + char *argv[]; +{ + extern long atol(); + if (argc != 2) + printf("restart: offset not specified\n"); + else { + restart_point = atol(argv[1]); + printf("restarting at %ld. %s\n", restart_point, + "execute get, put or append to initiate transfer"); + } +} + +/* show remote system type */ +syst() +{ + (void) command("SYST"); } macdef(argc, argv) @@ -1778,15 +2019,7 @@ macdef(argc, argv) code = -1; return; } - if (argc < 2) { - (void) strcat(line, " "); - printf("(macro name) "); - (void) gets(&line[strlen(line)]); - makeargv(); - argc = margc; - argv = margv; - } - if (argc != 2) { + if (argc < 2 && !another(&argc, &argv, "macro name")) { printf("Usage: %s macro_name\n",argv[0]); code = -1; return; @@ -1824,7 +2057,8 @@ macdef(argc, argv) tmp++; } while (1) { - while ((c = getchar()) != '\n' && c != EOF); + while ((c = getchar()) != '\n' && c != EOF) + /* LOOP */; if (c == EOF || getchar() == '\n') { printf("Macro not defined - 4k buffer exceeded\n"); code = -1; @@ -1832,3 +2066,70 @@ macdef(argc, argv) } } } + +/* + * get size of file on remote machine + */ +sizecmd(argc, argv) + int argc; + char *argv[]; +{ + + if (argc < 2 && !another(&argc, &argv, "filename")) { + printf("usage: %s filename\n", argv[0]); + code = -1; + return; + } + (void) command("SIZE %s", argv[1]); +} + +/* + * get last modification time of file on remote machine + */ +modtime(argc, argv) + int argc; + char *argv[]; +{ + int overbose; + + if (argc < 2 && !another(&argc, &argv, "filename")) { + printf("usage: %s filename\n", argv[0]); + code = -1; + return; + } + overbose = verbose; + if (debug == 0) + verbose = -1; + if (command("MDTM %s", argv[1]) == COMPLETE) { + int yy, mo, day, hour, min, sec; + sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, + &day, &hour, &min, &sec); + /* might want to print this in local time */ + printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], + mo, day, yy, hour, min, sec); + } else + printf("%s\n", reply_string); + verbose = overbose; +} + +/* + * show status on reomte machine + */ +rmtstatus(argc, argv) + int argc; + char *argv[]; +{ + (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); +} + +/* + * get file if modtime is more recent than current file + */ +newer(argc, argv) + int argc; + char *argv[]; +{ + if (getit(argc, argv, -1, "w")) + printf("Local file \"%s\" is newer than remote file \"%s\"\n", + argv[1], argv[2]); +}