diff --git a/bin/ftp/Makefile b/bin/ftp/Makefile new file mode 100644 index 0000000..ec9b894 --- /dev/null +++ b/bin/ftp/Makefile @@ -0,0 +1,17 @@ +# $Id: Makefile 478 1998-02-17 02:44:05Z gdr $ + +PROG= ftp +MAIN= main +SRCS= main.c cmdtab.c domacro.c ruserpass.c ftp.c glob.c cmds.c ftp_var.c + +HAS_BSD_MANPAGE = true # use ftp.1G rather than ftp.1 + +STACK= 2048 +LDADD= -lnetdb +DEBUG= 25 + +.INCLUDE: /src/gno/prog.mk + +#%.o : %.c +# $(CC) -o $@ $(CFLAGS) $(__OFLAG) -c $< +# @gsh -c ${mktmp cd $(OBJ_DIR); nameobj -p $@} diff --git a/bin/ftp/cmds.c b/bin/ftp/cmds.c new file mode 100644 index 0000000..988e267 --- /dev/null +++ b/bin/ftp/cmds.c @@ -0,0 +1,2028 @@ +#ifdef __ORCAC__ +segment "ftpcmds "; +#endif + +static char sccsid[] = "@(#)cmds.c 5.26 (Berkeley) 3/5/91"; + +/* + * FTP User Program -- Command Routines. + */ +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "ftp.var.h" +#include "pathnames.h" +#include "cmds.h" +#include "ftp.h" +#include "main.h" +#include "glob.h" +#include "ruserpass.h" + +extern char *globerr; +extern char *home; +extern int errno; +extern off_t restart_point; +extern char reply_string[]; + +char *mname; +jmp_buf jabort; + +/* + * `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. + */ +int another (int *pargc, char ***pargv, char *prompt) +{ +int len = strlen(line), ret; + + if (len >= sizeof(line) - 3) { + printf("sorry, arguments too long\n"); + intr(0,0); + } + printf("(%s) ", prompt); + line[len++] = ' '; + if (fgets(&line[len], sizeof(line) - len, stdin) == NULL) + intr(0,0); + 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. + */ +void setpeer (int argc, char **argv) +{ +char *host; +short port; + + if (connected) { + printf("Already connected to %s, use close first.\n", + hostname); + code = -1; + return; + } + if (argc < 2) + another(&argc, &argv, "to"); + if (argc < 2 || argc > 3) { + printf("usage: %s host-name [port]\n", argv[0]); + code = -1; + return; + } + port = sp->s_port; + if (argc > 2) { + port = atoi(argv[2]); + if (port <= 0) { + printf("%s: bad port number-- %s\n", argv[1], argv[2]); + printf ("usage: %s host-name [port]\n", argv[0]); + code = -1; + return; + } + port = htons(port); + } + host = hookup(argv[1], port); + if (host) { + int overbose; + + connected = 1; + /* + * Set up defaults for FTP. + */ + strcpy(typename, "ascii"), type = TYPE_A; + curtype = TYPE_A; + strcpy(formname, "non-print"), form = FORM_N; + strcpy(modename, "stream"), mode = MODE_S; + strcpy(structname, "file"), stru = STRU_F; + strcpy(bytename, "8"), bytesize = 8; + if (autologin) + login(argv[1]); + + 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; + 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; + } +} + +struct types { + char *t_name; + char *t_mode; + int t_type; + char *t_arg; +} types[] = { + { "ascii", "A", TYPE_A, 0 }, + { "binary", "I", TYPE_I, 0 }, + { "image", "I", TYPE_I, 0 }, + { "ebcdic", "E", TYPE_E, 0 }, + { "tenex", "L", TYPE_L, bytename }, + 0 +}; + +/* + * Set transfer type. + */ +void settype (int argc, char **argv) +{ +register struct types *p; +int comret; + + if (argc > 2) { + char *sep; + + printf("usage: %s [", argv[0]); + sep = " "; + for (p = types; p->t_name; p++) { + printf("%s%s", sep, p->t_name); + sep = " | "; + } + printf(" ]\n"); + code = -1; + return; + } + if (argc < 2) { + printf("Using %s mode to transfer files.\n", typename); + code = 0; + return; + } + for (p = types; p->t_name; p++) + if (strcmp(argv[1], p->t_name) == 0) + break; + if (p->t_name == 0) { + printf("%s: unknown mode\n", argv[1]); + code = -1; + return; + } + if ((p->t_arg != NULL) && (*(p->t_arg) != '\0')) + comret = command ("TYPE %s %s", p->t_mode, p->t_arg); + else + comret = command("TYPE %s", p->t_mode); + if (comret == COMPLETE) { + strcpy(typename, p->t_name); + curtype = type = p->t_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. + */ +void changetype (int newtype, int show) +{ +register struct types *p; +int comret, oldverbose = verbose; + + 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 binary transfer type. + */ +/*VARARGS*/ +void setbinary (int argc, char **argv) +{ + stype[1] = "binary"; + settype(2, stype); +} + +/* + * Set ascii transfer type. + */ +/*VARARGS*/ +void setascii (int argc, char **argv) +{ + stype[1] = "ascii"; + settype(2, stype); +} + +/* + * Set tenex transfer type. + */ +/*VARARGS*/ +void settenex (int argc, char **argv) +{ + stype[1] = "tenex"; + settype(2, stype); +} + +/* + * Set file transfer mode. + */ +/*ARGSUSED*/ +void ftpsetmode (int argc, char **argv) +{ + printf("We only support %s mode, sorry.\n", modename); + code = -1; +} + +/* + * Set file transfer format. + */ +/*ARGSUSED*/ +void setform (int argc, char **argv) +{ + printf("We only support %s format, sorry.\n", formname); + code = -1; +} + +/* + * Set file transfer structure. + */ +/*ARGSUSED*/ +void setstruct (int argc, char **argv) +{ + printf("We only support %s structure, sorry.\n", structname); + code = -1; +} + +/* + * Send a single file. + */ +void put (int argc, char **argv) +{ +char *cmd; +int loc = 0; +char *oldargv1, *oldargv2; + + if (argc == 2) { + argc++; + argv[2] = argv[1]; + loc++; + } + 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]); + code = -1; + return; + } + oldargv1 = argv[1]; + oldargv2 = argv[2]; + if (!globulize(&argv[1])) { + code = -1; + return; + } + /* + * If "globulize" modifies argv[1], and argv[2] is a copy of + * the old argv[1], make it a copy of the new argv[1]. + */ + if (argv[1] != oldargv1 && argv[2] == oldargv1) { + argv[2] = argv[1]; + } + cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR"); + if (loc && ntflag) { + argv[2] = dotrans(argv[2]); + } + if (loc && mapflag) { + argv[2] = domap(argv[2]); + } + sendrequest(cmd, argv[1], argv[2], + argv[1] != oldargv1 || argv[2] != oldargv2); +} + +/* + * Send multiple files. + */ +void mput (int argc, char **argv) +{ +extern jmp_buf jabort; +register int i; +sig_t oldintr; +int ointer; +char *tp, *cp, *tp2; +static char tmpbuf[MAXPATHLEN]; +void mabort (int sig, int code); + + if (argc < 2 && !another(&argc, &argv, "local-files")) { + printf("usage: %s local-files\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + oldintr = signal(SIGINT, mabort); + setjmp(jabort); + if (proxy) { + while ((cp = remglob(argv,0)) != NULL) { + if (*cp == 0) { + mflag = 0; + continue; + } + if (mflag && confirm(argv[0], cp)) { + tp = cp; + if (mcase) { + while (*tp && !islower(*tp)) { + tp++; + } + if (!*tp) { + tp = cp; + tp2 = tmpbuf; + while ((*tp2 = *tp) != 0) { + if (isupper(*tp2)) { + *tp2 = 'a' + *tp2 - 'A'; + } + tp++; + tp2++; + } + } + tp = tmpbuf; + } + if (ntflag) { + tp = dotrans(tp); + } + if (mapflag) { + tp = domap(tp); + } + sendrequest((sunique) ? "STOU" : "STOR", + cp, tp, cp != tp || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with","mput")) { + mflag++; + } + interactive = ointer; + } + } + } + signal(SIGINT, oldintr); + mflag = 0; + return; + } + for (i = 1; i < argc; i++) { + register char **cpp, **gargs; + + if (!doglob) { + if (mflag && confirm(argv[0], argv[i])) { + tp = (ntflag) ? dotrans(argv[i]) : argv[i]; + tp = (mapflag) ? domap(tp) : tp; + sendrequest((sunique) ? "STOU" : "STOR", + argv[i], tp, tp != argv[i] || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with","mput")) { + mflag++; + } + interactive = ointer; + } + } + continue; + } + gargs = ftpglob(argv[i]); + if (globerr != NULL) { + printf("%s\n", globerr); + if (gargs) { + blkfree(gargs); + free((char *)gargs); + } + continue; + } + for (cpp = gargs; cpp && *cpp != NULL; cpp++) { + if (mflag && confirm(argv[0], *cpp)) { + tp = (ntflag) ? dotrans(*cpp) : *cpp; + tp = (mapflag) ? domap(tp) : tp; + sendrequest((sunique) ? "STOU" : "STOR", + *cpp, tp, *cpp != tp || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with","mput")) { + mflag++; + } + interactive = ointer; + } + } + } + if (gargs != NULL) { + blkfree(gargs); + free((char *)gargs); + } + } + signal(SIGINT, oldintr); + mflag = 0; +} + +void reget (int argc, char **argv) +{ + getit (argc, argv, 1, "r+wb"); +} + +void get (int argc, char **argv) +{ + getit (argc, argv, 0, restart_point ? "r+wb" : "wb" ); +} + +/* + * Receive one file. + */ +int getit (int argc, char **argv, int restartit, char *mode) +{ +int loc = 0; +char *oldargv1, *oldargv2; +char *tp = argv[1], *tp2; +static char tmpbuf[MAXPATHLEN]; + + if (argc == 2) { + argc++; + argv[2] = argv[1]; + loc++; + } + 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 (0); + } + oldargv1 = argv[1]; + oldargv2 = argv[2]; + if (!globulize(&argv[2])) { + code = -1; + return (0); + } + if (loc && mcase) { + while (*tp && !islower(*tp)) { + tp++; + } + if (!*tp) { + tp = argv[2]; + tp2 = tmpbuf; + while ((*tp2 = *tp) != 0) { + if (isupper(*tp2)) { + *tp2 = 'a' + *tp2 - 'A'; + } + tp++; + tp2++; + } + argv[2] = tmpbuf; + } + } + if (loc && ntflag) + argv[2] = dotrans(argv[2]); + 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], mode, + argv[1] != oldargv1 || argv[2] != oldargv2); + restart_point = 0; + return (0); +} + +#pragma databank 1 +void mabort (int sig, int code) +{ +int ointer; +extern jmp_buf jabort; + + printf("\n"); + fflush(stdout); + if (mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", mname)) { + interactive = ointer; + longjmp(jabort,0); + } + interactive = ointer; + } + mflag = 0; + longjmp(jabort,0); +} +#pragma databank 0 + +/* + * Get multiple files. + */ +void mget (int argc, char **argv) +{ +extern jmp_buf jabort; +sig_t oldintr; +int ointer; +char *cp, *tp, *tp2; +static char tmpbuf[MAXPATHLEN]; + + if (argc < 2 && !another(&argc, &argv, "remote-files")) { + printf("usage: %s remote-files\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + oldintr = signal(SIGINT,mabort); + setjmp(jabort); + while ((cp = remglob(argv,proxy)) != NULL) { + if (*cp == '\0') { + mflag = 0; + continue; + } + if (mflag && confirm(argv[0], cp)) { + tp = cp; + if (mcase) { + while (*tp && !islower(*tp)) { + tp++; + } + if (!*tp) { + tp = cp; + tp2 = tmpbuf; + while ((*tp2 = *tp) != 0) { + if (isupper(*tp2)) { + *tp2 = 'a' + *tp2 - 'A'; + } + tp++; + tp2++; + } + } + tp = tmpbuf; + } + if (ntflag) { + tp = dotrans(tp); + } + if (mapflag) { + tp = domap(tp); + } + recvrequest("RETR", tp, cp, "wb", + tp != cp || !interactive); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with","mget")) { + mflag++; + } + interactive = ointer; + } + } + } + signal(SIGINT,oldintr); + mflag = 0; +} + +char *remglob (char **argv, int doswitch) +{ +static char temp[16]; +static char buf[MAXPATHLEN]; +static FILE *ftemp = NULL; +static char **args; +int oldverbose, oldhash; +char *cp, *mode; + + if (!mflag) { + if (!doglob) { + args = NULL; + } + else { + if (ftemp) { + fclose(ftemp); ftemp = NULL; + unlink(temp); + } + } + return(NULL); + } + if (!doglob) { + if (args == NULL) + args = argv; + if ((cp = *++args) == NULL) + args = NULL; + return (cp); + } + if (ftemp == NULL) { + strcpy(temp, _PATH_TMP); + mktemp(temp); + oldverbose = verbose, verbose = 0; + oldhash = hash, hash = 0; + if (doswitch) { + pswitch(!proxy); + } + for (mode = "wb"; *++argv != NULL; mode = "ab") + recvrequest ("NLST", temp, *argv, mode, 0); + if (doswitch) { + pswitch(!proxy); + } + verbose = oldverbose; hash = oldhash; + ftemp = fopen(temp, "rb"); + if (ftemp == NULL) { + printf("can't find list of remote files, oops\n"); + return (NULL); + } + } + if (fgets(buf, sizeof (buf), ftemp) == NULL) { + fclose(ftemp); ftemp = NULL; + unlink(temp); + return (NULL); + } + if ((cp = index(buf, '\n')) != NULL) + *cp = '\0'; + return (buf); +} + +char *onoff (int bool) +{ + return (bool ? "on" : "off"); +} + +/* + * Show status. + */ +/*ARGSUSED*/ +void status (int argc, char **argv) +{ +int i; + + if (connected) + printf("Connected to %s.\n", hostname); + else + printf("Not connected.\n"); + if (!proxy) { + pswitch(1); + if (connected) { + printf("Connected for proxy commands to %s.\n", hostname); + } + else { + printf("No proxy connection.\n"); + } + pswitch(0); + } + printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n", + modename, typename, formname, structname); + printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", + onoff(verbose), onoff(bell), onoff(interactive), + onoff(doglob)); + printf("Store unique: %s; Receive unique: %s\n", onoff(sunique), + onoff(runique)); + printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag)); + if (ntflag) { + printf("Ntrans: (in) %s (out) %s\n", ntin,ntout); + } + else { + printf("Ntrans: off\n"); + } + if (mapflag) { + printf("Nmap: (in) %s (out) %s\n", mapin, mapout); + } + else { + printf("Nmap: off\n"); + } + printf("Hash mark printing: %s; Use of PORT cmds: %s\n", + onoff(hash), onoff(sendport)); + if (macnum > 0) { + printf("Macros:\n"); + for (i=0; i 1) { + val = atoi(argv[1]); + if (val < 0) { + printf("%s: bad debugging value.\n", argv[1]); + code = -1; + return; + } + } else + val = !debug; + debug = val; + if (debug) + options |= SO_DEBUG; + else + options &= ~SO_DEBUG; + printf("Debugging %s (debug=%d).\n", onoff(debug), debug); + code = debug > 0; +} + +/* + * Set current working directory + * on remote machine. + */ +void cd (int argc, char **argv) +{ + if (argc < 2 && !another(&argc, &argv, "remote-directory")) { + printf("usage: %s remote-directory\n", argv[0]); + code = -1; + return; + } + if (command("CWD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("CWD command not recognized, trying XCWD\n"); + command("XCWD %s", argv[1]); + } +} + +/* + * Set current working directory + * on local machine. + */ +void lcd (int argc, char **argv) +{ +static char buf[MAXPATHLEN]; + + if (argc < 2) + argc++, argv[1] = home; + if (argc != 2) { + printf("usage: %s local-directory\n", argv[0]); + code = -1; + return; + } + if (!globulize(&argv[1])) { + code = -1; + return; + } + if (chdir(argv[1]) < 0) { + fprintf(stderr, "local: %s: %s\n", argv[1], strerror(errno)); + code = -1; + return; + } + printf("Local directory now %s\n", getwd(buf)); + code = 0; +} + +/* + * Delete a single file. + */ +void delete (int argc, char **argv) +{ + if (argc < 2 && !another(&argc, &argv, "remote-file")) { + printf("usage: %s remote-file\n", argv[0]); + code = -1; + return; + } + command("DELE %s", argv[1]); +} + +/* + * Delete multiple files. + */ +void mdelete (int argc, char **argv) +{ +extern jmp_buf jabort; +sig_t oldintr; +int ointer; +char *cp; + + if (argc < 2 && !another(&argc, &argv, "remote-files")) { + printf("usage: %s remote-files\n", argv[0]); + code = -1; + return; + } + mname = argv[0]; + mflag = 1; + oldintr = signal(SIGINT, mabort); + setjmp(jabort); + while ((cp = remglob(argv,0)) != NULL) { + if (*cp == '\0') { + mflag = 0; + continue; + } + if (mflag && confirm(argv[0], cp)) { + command("DELE %s", cp); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", "mdelete")) { + mflag++; + } + interactive = ointer; + } + } + } + signal(SIGINT, oldintr); + mflag = 0; +} + +/* + * Rename a remote file. + */ +void renamefile (int argc, char **argv) +{ + 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 (command("RNFR %s", argv[1]) == CONTINUE) + command("RNTO %s", argv[2]); +} + +/* + * Get a directory listing + * of remote files. + */ +void ls (int argc, char **argv) +{ +char *cmd; + + if (argc < 2) + argc++, argv[1] = NULL; + if (argc < 3) + argc++, argv[2] = "-"; + if (argc > 3) { + printf("usage: %s remote-directory local-file\n", argv[0]); + code = -1; + return; + } + cmd = argv[0][0] == 'n' ? "NLST" : "LIST"; + if (strcmp(argv[2], "-") && !globulize(&argv[2])) { + code = -1; + return; + } + if (strcmp(argv[2], "-") && *argv[2] != '|') + if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) { + code = -1; + return; + } + recvrequest(cmd, argv[2], argv[1], "wb", 0); +} + +/* + * Get a directory listing + * of multiple remote files. + */ +void mls (int argc, char **argv) +{ +extern jmp_buf jabort; +sig_t oldintr; +int ointer, i; +char *cmd, mode[1], *dest; +void mabort(int sig, int code); + + 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)) { + code = -1; + return; + } + cmd = argv[0][1] == 'l' ? "NLST" : "LIST"; + mname = argv[0]; + mflag = 1; + oldintr = signal(SIGINT, mabort); + setjmp(jabort); + for (i = 1; mflag && i < argc-1; ++i) { + *mode = (i == 1) ? 'w' : 'a'; + recvrequest(cmd, dest, argv[i], mode, 0); + if (!mflag && fromatty) { + ointer = interactive; + interactive = 1; + if (confirm("Continue with", argv[0])) { + mflag ++; + } + interactive = ointer; + } + } + signal(SIGINT, oldintr); + mflag = 0; +} + +/* + * Do a shell escape + */ +/*ARGSUSED*/ +void shell (int argc, char **argv) +{ +#ifndef __GNO__ +int pid; +sig_t old1, old2; +char shellnam[40], *shell, *namep; +union wait status; + + old1 = signal (SIGINT, SIG_IGN); + old2 = signal (SIGQUIT, SIG_IGN); + if ((pid = fork()) == 0) { + for (pid = 3; pid < 20; pid++) + close(pid); + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + shell = getenv("SHELL"); + if (shell == NULL) + shell = _PATH_BSHELL; + namep = rindex(shell,'/'); + if (namep == NULL) + namep = shell; + strcpy(shellnam,"-"); + strcat(shellnam, ++namep); + if (strcmp(namep, "sh") != 0) + shellnam[0] = '+'; + if (debug) { + printf ("%s\n", shell); + fflush (stdout); + } + if (argc > 1) { + execl(shell,shellnam,"-c",altarg,(char *)0); + } + else { + execl(shell,shellnam,(char *)0); + } + perror(shell); + code = -1; + exit(1); + } + if (pid > 0) + while (wait((int *)&status) != pid) + ; + signal(SIGINT, old1); + signal(SIGQUIT, old2); + if (pid == -1) { + perror("Try again later"); + code = -1; + } + else { + code = 0; + } +#else + if (argc <= 1) { + printf("Shell only not supported under GNO. Please specify a command also.\n"); + code = -1; + return; + } + if (debug) { + printf ("system(%s)\n", altarg); + fflush (stdout); + } + if (system(altarg)) code = -1; + else code = 0; +#endif +} + +/* + * Send new user information (re-login) + */ +void user (int argc, char **argv) +{ +static char acct[80]; +int n, aflag = 0; + + if (argc < 2) + another(&argc, &argv, "username"); + if (argc < 2 || argc > 4) { + printf("usage: %s username [password] [account]\n", argv[0]); + code = -1; + } + n = command("USER %s", argv[1]); + if (n == CONTINUE) { + if (argc < 3 ) + argv[2] = getpass("Password: "), argc++; + n = command("PASS %s", argv[2]); + } + if (n == CONTINUE) { + if (argc < 4) { + printf("Account: "); fflush(stdout); + fgets(acct, sizeof(acct) - 1, stdin); + acct[strlen(acct) - 1] = '\0'; + argv[3] = acct; argc++; + } + n = command("ACCT %s", argv[3]); + aflag++; + } + if (n != COMPLETE) { + fprintf(stdout, "Login failed.\n"); + } + if (!aflag && argc == 4) { + command("ACCT %s", argv[3]); + } +} + +/* + * Print working directory. + */ +/*VARARGS*/ +void pwd (int argc, char **argv) +{ +int oldverbose = verbose; + + /* + * 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"); + command("XPWD"); + } + verbose = oldverbose; +} + +/* + * Make a directory. + */ +void makedir (int argc, char **argv) +{ + if (argc < 2 && !another(&argc, &argv, "directory-name")) { + printf("usage: %s directory-name\n", argv[0]); + code = -1; + return; + } + if (command("MKD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("MKD command not recognized, trying XMKD\n"); + command("XMKD %s", argv[1]); + } +} + +/* + * Remove a directory. + */ +void removedir (int argc, char **argv) +{ + if (argc < 2 && !another(&argc, &argv, "directory-name")) { + printf("usage: %s directory-name\n", argv[0]); + code = -1; + return; + } + if (command("RMD %s", argv[1]) == ERROR && code == 500) { + if (verbose) + printf("RMD command not recognized, trying XRMD\n"); + command("XRMD %s", argv[1]); + } +} + +/* + * Send a line, verbatim, to the remote machine. + */ +void quote (int argc, char **argv) +{ + if (argc < 2 && !another(&argc, &argv, "command line to send")) { + printf("usage: %s line-to-send\n", argv[0]); + code = -1; + return; + } + 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. + */ +void site (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; + } + 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. + */ +void quote1 (char *initial, int argc, char **argv) +{ +register int i, len; +static char buf[BUFSIZ]; /* must be >= sizeof(line) */ + + 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); + } +} + +void do_chmod (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; + } + command("SITE CHMOD %s %s", argv[1], argv[2]); +} + +void do_umask (int argc, char **argv) +{ +int oldverbose = verbose; + + verbose = 1; +#ifndef __ORCAC__ + command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]); +#else + if (argc == 1) command("SITE UMASK"); + else command("SITE UMASK %s", argv[1]); +#endif + verbose = oldverbose; +} + +void idle (int argc, char **argv) +{ +int oldverbose = verbose; + + verbose = 1; +#ifndef __ORCAC__ + command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]); +#else + if (argc == 1) command("SITE IDLE"); + else command("SITE IDLE %s", argv[1]); +#endif + verbose = oldverbose; +} + +/* + * Ask the other side for help. + */ +void rmthelp (int argc, char **argv) +{ +int oldverbose = verbose; + + verbose = 1; +#ifndef __ORCAC__ + command(argc == 1 ? "HELP" : "HELP %s", argv[1]); +#else + if (argc == 1) command("HELP"); + else command("HELP %s", argv[1]); +#endif + verbose = oldverbose; +} + +/* + * Terminate session and exit. + */ +/*VARARGS*/ +void quit (int argc, char **argv) +{ + if (connected) + disconnect(argc, argv); + pswitch(1); + if (connected) { + disconnect(argc, argv); + } + exit(0); +} + +/* + * Terminate session, but don't exit. + */ +void disconnect (int argc, char **argv) +{ +extern FILE *cout; +extern int data; + + if (!connected) + return; + command("QUIT"); + if (cout) { + fclose(cout); + } + cout = NULL; + connected = 0; + data = -1; + if (!proxy) { + macnum = 0; + } +} + +int confirm (char *cmd, char *file) +{ +static char line[BUFSIZ]; + + if (!interactive) + return (1); + printf("%s %s? ", cmd, file); + fflush(stdout); + if (fgets(line, sizeof line, stdin) == NULL) + return (0); + return (*line != 'n' && *line != 'N'); +} + +void fatal (char *msg) +{ + fprintf(stderr, "ftp: %s\n", msg); + exit(1); +} + +/* + * Glob a local file name specification with + * the expectation of a single return value. + * Can't control multiple values being expanded + * from the expression, we return only the first. + */ +int globulize (char *cpp[]) +{ +char **globbed; + + if (!doglob) + return (1); + globbed = ftpglob(*cpp); + if (globerr != NULL) { + printf("%s: %s\n", *cpp, globerr); + if (globbed) { + blkfree(globbed); + free((char *)globbed); + } + return (0); + } + if (globbed) { + *cpp = *globbed++; + /* don't waste too much memory */ + if (*globbed) { + blkfree(globbed); + free((char *)globbed); + } + } + return (1); +} + +void account (int argc, char **argv) +{ +static char acct[50]; +char *ap; + + if (argc > 1) { + ++argv; + --argc; + strncpy(acct,*argv,49); + acct[49] = '\0'; + while (argc > 1) { + --argc; + ++argv; + strncat(acct,*argv, 49-strlen(acct)); + } + ap = acct; + } + else { + ap = getpass("Account:"); + } + command("ACCT %s", ap); +} + +jmp_buf abortprox; + +#pragma databank 1 +void proxabort (int sig, int code) +{ +extern int proxy; + + if (!proxy) { + pswitch(1); + } + if (connected) { + proxflag = 1; + } + else { + proxflag = 0; + } + pswitch(0); + longjmp(abortprox,1); +} +#pragma databank 0 + +void doproxy (int argc, char **argv) +{ +extern struct cmd cmdtab[]; +extern jmp_buf abortprox; +register struct cmd *c; +sig_t oldintr; +void proxabort(int sig, int code); + + if (argc < 2 && !another(&argc, &argv, "command")) { + printf("usage: %s command\n", argv[0]); + code = -1; + return; + } + c = getcmd(argv[1]); + if (c == (struct cmd *) -1) { + printf("?Ambiguous command\n"); + fflush(stdout); + code = -1; + return; + } + if (c == 0) { + printf("?Invalid command\n"); + fflush(stdout); + code = -1; + return; + } + if (!c->c_proxy) { + printf("?Invalid proxy command\n"); + fflush(stdout); + code = -1; + return; + } + if (setjmp(abortprox)) { + code = -1; + return; + } + oldintr = signal(SIGINT, proxabort); + pswitch(1); + if (c->c_conn && !connected) { + printf("Not connected\n"); + fflush(stdout); + pswitch(0); + signal(SIGINT, oldintr); + code = -1; + return; + } + (*c->c_handler)(argc-1, argv+1); + if (connected) { + proxflag = 1; + } + else { + proxflag = 0; + } + pswitch(0); + signal(SIGINT, oldintr); +} + +void setcase (int argc, char **argv) +{ + mcase = !mcase; + printf("Case mapping %s.\n", onoff(mcase)); + code = mcase; +} + +void setcr (int argc, char **argv) +{ + crflag = !crflag; + printf("Carriage Return stripping %s.\n", onoff(crflag)); + code = crflag; +} + +void setntrans (int argc, char **argv) +{ + if (argc == 1) { + ntflag = 0; + printf("Ntrans off.\n"); + code = ntflag; + return; + } + ntflag++; + code = ntflag; + strncpy(ntin, argv[1], 16); + ntin[16] = '\0'; + if (argc == 2) { + ntout[0] = '\0'; + return; + } + strncpy(ntout, argv[2], 16); + ntout[16] = '\0'; +} + +char *dotrans (char *name) +{ +static char new[MAXPATHLEN]; +char *cp1, *cp2 = new; +register int i, ostop, found; + + for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++); + for (cp1 = name; *cp1; cp1++) { + found = 0; + for (i = 0; *(ntin + i) && i < 16; i++) { + if (*cp1 == *(ntin + i)) { + found++; + if (i < ostop) { + *cp2++ = *(ntout + i); + } + break; + } + } + if (!found) { + *cp2++ = *cp1; + } + } + *cp2 = '\0'; + return(new); +} + +void setnmap (int argc, char **argv) +{ +char *cp; + + if (argc == 1) { + mapflag = 0; + printf("Nmap off.\n"); + code = mapflag; + return; + } + if (argc < 3 && !another(&argc, &argv, "mapout")) { + printf("Usage: %s [mapin mapout]\n",argv[0]); + code = -1; + return; + } + mapflag = 1; + code = 1; + cp = index(altarg, ' '); + if (proxy) { + while(*++cp == ' '); + altarg = cp; + cp = index(altarg, ' '); + } + *cp = '\0'; + strncpy(mapin, altarg, MAXPATHLEN - 1); + while (*++cp == ' '); + strncpy(mapout, cp, MAXPATHLEN - 1); +} + +char *domap (char *name) +{ +static char new[MAXPATHLEN]; +register char *cp1 = name, *cp2 = mapin; +char *tp[9], *te[9]; +int i, toks[9], toknum = 0, match = 1; + + for (i=0; i < 9; ++i) { + toks[i] = 0; + } + while (match && *cp1 && *cp2) { + switch (*cp2) { + case '\\': + if (*++cp2 != *cp1) { + match = 0; + } + break; + case '$': + if (*(cp2+1) >= '1' && (*cp2+1) <= '9') { + if (*cp1 != *(++cp2+1)) { + toks[toknum = *cp2 - '1']++; + tp[toknum] = cp1; + while (*++cp1 && *(cp2+1) + != *cp1); + te[toknum] = cp1; + } + cp2++; + break; + } + /* FALLTHROUGH */ + default: + if (*cp2 != *cp1) { + match = 0; + } + break; + } + if (match && *cp1) { + cp1++; + } + if (match && *cp2) { + cp2++; + } + } + if (!match && *cp1) /* last token mismatch */ + { + toks[toknum] = 0; + } + cp1 = new; + *cp1 = '\0'; + cp2 = mapout; + while (*cp2) { + match = 0; + switch (*cp2) { + case '\\': + if (*(cp2 + 1)) { + *cp1++ = *++cp2; + } + break; + case '[': +LOOP: + if (*++cp2 == '$' && isdigit(*(cp2+1))) { + if (*++cp2 == '0') { + char *cp3 = name; + + while (*cp3) { + *cp1++ = *cp3++; + } + match = 1; + } + else if (toks[toknum = *cp2 - '1']) { + char *cp3 = tp[toknum]; + + while (cp3 != te[toknum]) { + *cp1++ = *cp3++; + } + match = 1; + } + } + else { + while (*cp2 && *cp2 != ',' && + *cp2 != ']') { + if (*cp2 == '\\') { + cp2++; + } + else if (*cp2 == '$' && + isdigit(*(cp2+1))) { + if (*++cp2 == '0') { + char *cp3 = name; + + while (*cp3) { + *cp1++ = *cp3++; + } + } + else if (toks[toknum = + *cp2 - '1']) { + char *cp3=tp[toknum]; + + while (cp3 != + te[toknum]) { + *cp1++ = *cp3++; + } + } + } + else if (*cp2) { + *cp1++ = *cp2++; + } + } + if (!*cp2) { + printf("nmap: unbalanced brackets\n"); + return(name); + } + match = 1; + cp2--; + } + if (match) { + while (*++cp2 && *cp2 != ']') { + if (*cp2 == '\\' && *(cp2 + 1)) { + cp2++; + } + } + if (!*cp2) { + printf("nmap: unbalanced brackets\n"); + return(name); + } + break; + } + switch (*++cp2) { + case ',': + goto LOOP; + case ']': + break; + default: + cp2--; + goto LOOP; + } + break; + case '$': + if (isdigit(*(cp2 + 1))) { + if (*++cp2 == '0') { + char *cp3 = name; + + while (*cp3) { + *cp1++ = *cp3++; + } + } + else if (toks[toknum = *cp2 - '1']) { + char *cp3 = tp[toknum]; + + while (cp3 != te[toknum]) { + *cp1++ = *cp3++; + } + } + break; + } + /* intentional drop through */ + default: + *cp1++ = *cp2; + break; + } + cp2++; + } + *cp1 = '\0'; + if (!*new) { + return(name); + } + return(new); +} + +void setsunique (int argc, char **argv) +{ + sunique = !sunique; + printf("Store unique %s.\n", onoff(sunique)); + code = sunique; +} + +void setrunique (int argc, char **argv) +{ + runique = !runique; + printf("Receive unique %s.\n", onoff(runique)); + code = runique; +} + +/* change directory to perent directory */ +void cdup (int argc, char **argv) +{ + if (command("CDUP") == ERROR && code == 500) { + if (verbose) + printf("CDUP command not recognized, trying XCUP\n"); + command("XCUP"); + } +} + +/* restart transfer at specific point */ +void restart (int argc, char **argv) +{ + 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 */ +void syst (int argc, char **argv) +{ + command ("SYST"); +} + +void macdef (int argc, char **argv) +{ +char *tmp; +int c; + + if (macnum == 16) { + printf("Limit of 16 macros have already been defined\n"); + code = -1; + return; + } + if (argc < 2 && !another(&argc, &argv, "macro name")) { + printf("Usage: %s macro_name\n",argv[0]); + code = -1; + return; + } + if (interactive) { + printf("Enter macro line by line, terminating it with a null line\n"); + } + strncpy(macros[macnum].mac_name, argv[1], 8); + if (macnum == 0) { + macros[macnum].mac_start = macbuf; + } + else { + macros[macnum].mac_start = macros[macnum - 1].mac_end + 1; + } + tmp = macros[macnum].mac_start; + while (tmp != macbuf+4096) { + if ((c = getchar()) == EOF) { + printf("macdef:end of file encountered\n"); + code = -1; + return; + } + if ((*tmp = c) == '\n') { + if (tmp == macros[macnum].mac_start) { + macros[macnum++].mac_end = tmp; + code = 0; + return; + } + if (*(tmp-1) == '\0') { + macros[macnum++].mac_end = tmp - 1; + code = 0; + return; + } + *tmp = '\0'; + } + tmp++; + } + while (1) { + while ((c = getchar()) != '\n' && c != EOF) + /* LOOP */; + if (c == EOF || getchar() == '\n') { + printf("Macro not defined - 4k buffer exceeded\n"); + code = -1; + return; + } + } +} + +/* + * get size of file on remote machine + */ +void sizecmd (int argc, char **argv) +{ + if (argc < 2 && !another(&argc, &argv, "filename")) { + printf("usage: %s filename\n", argv[0]); + code = -1; + return; + } + command("SIZE %s", argv[1]); +} + +/* + * get last modification time of file on remote machine + */ +void modtime (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 + */ +void rmtstatus (int argc, char **argv) +{ +#ifndef __ORCAC__ + command(argc > 1 ? "STAT %s" : "STAT" , argv[1]); +#else + if (argc > 1) command("STAT %s", argv[1]); + else command("STAT"); +#endif +} + +/* + * get file if modtime is more recent than current file + */ +void newer (int argc, char **argv) +{ + if (getit(argc, argv, -1, "wb")) + printf("Local file \"%s\" is newer than remote file \"%s\"\n", + argv[1], argv[2]); +} + +void reset (int argc, char **argv) +{ +struct fd_set mask; +int nfnd = 1; +extern FILE *cin, *cout; + + FD_ZERO(&mask); + while (nfnd > 0) { + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask,0)) < 0) { + perror("reset"); + code = -1; + lostpeer (0, 0); + } + else if (nfnd) { + getreply(0); + } + } +} diff --git a/bin/ftp/cmds.h b/bin/ftp/cmds.h new file mode 100644 index 0000000..72101ac --- /dev/null +++ b/bin/ftp/cmds.h @@ -0,0 +1,74 @@ +int another (int *pargc, char ***pargv, char *prompt); +void changetype (int newtype, int show); +void setbinary (int argc, char **argv); +void setascii (int argc, char **argv); +void settenex (int argc, char **argv); +int getit (int argc, char **argv, int restartit, char *mode); +char *remglob (char **argv, int doswitch); +char *onoff (int bool); +void setbell (int argc, char **argv); +void settrace (int argc, char **argv); +void sethash (int argc, char **argv); +void setverbose (int argc, char **argv); +void setport (int argc, char **argv); +void setprompt (int argc, char **argv); +void setglob (int argc, char **argv); +void mabort (int sig, int code); +void pwd (int argc, char **argv); +void quote1 (char *initial, int argc, char **argv); +void quit (int argc, char **argv); +void disconnect (int argc, char **argv); +int confirm (char *cmd, char *file); +void fatal (char *msg); +int globulize (char *cpp[]); +void proxabort (int sig, int code); +void setcase (int argc, char **argv); +void setcr (int argc, char **argv); +char *dotrans (char *name); +char *domap (char *name); +void setsunique (int argc, char **argv); +void setrunique (int argc, char **argv); +void cdup (int argc, char **argv); +void syst (int argc, char **argv); + +void ftpsetdebug (int argc, char **argv); +void setpeer (int argc, char **argv); +void settype (int argc, char **argv); +void ftpsetmode (int argc, char **argv); +void setform (int argc, char **argv); +void setstruct (int argc, char **argv); +void put (int argc, char **argv); +void mput (int argc, char **argv); +void reget (int argc, char **argv); +void get (int argc, char **argv); +void mget (int argc, char **argv); +void status (int argc, char **argv); +void cd (int argc, char **argv); +void lcd (int argc, char **argv); +void delete (int argc, char **argv); +void mdelete (int argc, char **argv); +void renamefile (int argc, char **argv); +void ls (int argc, char **argv); +void mls (int argc, char **argv); +void shell (int argc, char **argv); +void user (int argc, char **argv); +void makedir (int argc, char **argv); +void removedir (int argc, char **argv); +void quote (int argc, char **argv); +void site (int argc, char **argv); +void do_chmod (int argc, char **argv); +void do_umask (int argc, char **argv); +void idle (int argc, char **argv); +void rmthelp (int argc, char **argv); +void account (int argc, char **argv); +void doproxy (int argc, char **argv); +void setntrans (int argc, char **argv); +void setnmap (int argc, char **argv); +void restart (int argc, char **argv); +void macdef (int argc, char **argv); +void sizecmd (int argc, char **argv); +void modtime (int argc, char **argv); +void rmtstatus (int argc, char **argv); +void newer (int argc, char **argv); +void reset (int argc, char **argv); + diff --git a/bin/ftp/cmdtab.c b/bin/ftp/cmdtab.c new file mode 100644 index 0000000..9f32813 --- /dev/null +++ b/bin/ftp/cmdtab.c @@ -0,0 +1,156 @@ +#ifdef __ORCAC__ +segment "ftpmain "; +#endif + +static char sccsid[] = "@(#)cmdtab.c 5.10 (Berkeley) 6/1/90"; + +#include "ftp.var.h" +#include "cmds.h" +#include "main.h" +#include "domacro.h" + +/* + * User FTP -- Command Tables. + */ +char accounthelp[] = "send account command to remote server"; +char appendhelp[] = "append to a file"; +char asciihelp[] = "set ascii transfer type"; +char beephelp[] = "beep when command completed"; +char binaryhelp[] = "set binary transfer type"; +char casehelp[] = "toggle mget upper/lower case id mapping"; +char cdhelp[] = "change remote working directory"; +char cduphelp[] = "change remote working directory to parent directory"; +char chmodhelp[] = "change file permissions of remote file"; +char connecthelp[] = "connect to remote tftp"; +char crhelp[] = "toggle carriage return stripping on ascii gets"; +char deletehelp[] = "delete remote file"; +char debughelp[] = "toggle/set debugging mode"; +char dirhelp[] = "list contents of remote directory"; +char disconhelp[] = "terminate ftp session"; +char domachelp[] = "execute macro"; +char formhelp[] = "set file transfer format"; +char globhelp[] = "toggle metacharacter expansion of local file names"; +char hashhelp[] = "toggle printing `#' for each buffer transferred"; +char helphelp[] = "print local help information"; +char idlehelp[] = "get (set) idle timer on remote side"; +char lcdhelp[] = "change local working directory"; +char lshelp[] = "list contents of remote directory"; +char macdefhelp[] = "define a macro"; +char mdeletehelp[] = "delete multiple files"; +char mdirhelp[] = "list contents of multiple remote directories"; +char mgethelp[] = "get multiple files"; +char mkdirhelp[] = "make directory on the remote machine"; +char mlshelp[] = "list contents of multiple remote directories"; +char modtimehelp[] = "show last modification time of remote file"; +char modehelp[] = "set file transfer mode"; +char mputhelp[] = "send multiple files"; +char newerhelp[] = "get file if remote file is newer than local file "; +char nlisthelp[] = "nlist contents of remote directory"; +char nmaphelp[] = "set templates for default file name mapping"; +char ntranshelp[] = "set translation table for default file name mapping"; +char porthelp[] = "toggle use of PORT cmd for each data connection"; +char prompthelp[] = "force interactive prompting on multiple commands"; +char proxyhelp[] = "issue command on alternate connection"; +char pwdhelp[] = "print working directory on remote machine"; +char quithelp[] = "terminate ftp session and exit"; +char quotehelp[] = "send arbitrary ftp command"; +char receivehelp[] = "receive file"; +char regethelp[] = "get file restarting at end of local file"; +char remotehelp[] = "get help from remote server"; +char renamehelp[] = "rename file"; +char restarthelp[]= "restart file transfer at bytecount"; +char rmdirhelp[] = "remove directory on the remote machine"; +char rmtstatushelp[]="show status of remote machine"; +char runiquehelp[] = "toggle store unique for local files"; +char resethelp[] = "clear queued command replies"; +char sendhelp[] = "send one file"; +char sitehelp[] = "send site specific command to remote server\n\t\tTry \"rhelp site\" or \"site help\" for more information"; +char shellhelp[] = "escape to the shell"; +char sizecmdhelp[] = "show size of remote file"; +char statushelp[] = "show current status"; +char structhelp[] = "set file transfer structure"; +char suniquehelp[] = "toggle store unique on remote machine"; +char systemhelp[] = "show remote system type"; +char tenexhelp[] = "set tenex file transfer type"; +char tracehelp[] = "toggle packet tracing"; +char typehelp[] = "set file transfer type"; +char umaskhelp[] = "get (set) umask on remote side"; +char userhelp[] = "send new user information"; +char verbosehelp[] = "toggle verbose mode"; + +struct cmd cmdtab[] = { + { "!", shellhelp, 0, 0, 0, shell }, + { "$", domachelp, 1, 0, 0, domacro }, + { "account", accounthelp, 0, 1, 1, account}, + { "append", appendhelp, 1, 1, 1, put }, + { "ascii", asciihelp, 0, 1, 1, setascii }, + { "bell", beephelp, 0, 0, 0, setbell }, + { "binary", binaryhelp, 0, 1, 1, setbinary }, + { "bye", quithelp, 0, 0, 0, quit }, + { "case", casehelp, 0, 0, 1, setcase }, + { "cd", cdhelp, 0, 1, 1, cd }, + { "cdup", cduphelp, 0, 1, 1, cdup }, + { "chmod", chmodhelp, 0, 1, 1, do_chmod }, + { "close", disconhelp, 0, 1, 1, disconnect }, + { "cr", crhelp, 0, 0, 0, setcr }, + { "delete", deletehelp, 0, 1, 1, delete }, + { "debug", debughelp, 0, 0, 0, ftpsetdebug }, + { "dir", dirhelp, 1, 1, 1, ls }, + { "disconnect", disconhelp, 0, 1, 1, disconnect }, + { "form", formhelp, 0, 1, 1, setform }, + { "get", receivehelp, 1, 1, 1, get }, + { "glob", globhelp, 0, 0, 0, setglob }, + { "hash", hashhelp, 0, 0, 0, sethash }, + { "help", helphelp, 0, 0, 1, help }, + { "idle", idlehelp, 0, 1, 1, idle }, + { "image", binaryhelp, 0, 1, 1, setbinary }, + { "lcd", lcdhelp, 0, 0, 0, lcd }, + { "ls", lshelp, 1, 1, 1, ls }, + { "macdef", macdefhelp, 0, 0, 0, macdef }, + { "mdelete", mdeletehelp, 1, 1, 1, mdelete }, + { "mdir", mdirhelp, 1, 1, 1, mls }, + { "mget", mgethelp, 1, 1, 1, mget }, + { "mkdir", mkdirhelp, 0, 1, 1, makedir }, + { "mls", mlshelp, 1, 1, 1, mls }, + { "mode", modehelp, 0, 1, 1, ftpsetmode }, + { "modtime", modtimehelp, 0, 1, 1, modtime }, + { "mput", mputhelp, 1, 1, 1, mput }, + { "newer", newerhelp, 1, 1, 1, newer }, + { "nmap", nmaphelp, 0, 0, 1, setnmap }, + { "nlist", nlisthelp, 1, 1, 1, ls }, + { "ntrans", ntranshelp, 0, 0, 1, setntrans }, + { "open", connecthelp, 0, 0, 1, setpeer }, + { "prompt", prompthelp, 0, 0, 0, setprompt }, + { "proxy", proxyhelp, 0, 0, 1, doproxy }, + { "sendport", porthelp, 0, 0, 0, setport }, + { "put", sendhelp, 1, 1, 1, put }, + { "pwd", pwdhelp, 0, 1, 1, pwd }, + { "quit", quithelp, 0, 0, 0, quit }, + { "quote", quotehelp, 1, 1, 1, quote }, + { "recv", receivehelp, 1, 1, 1, get }, + { "reget", regethelp, 1, 1, 1, reget }, + { "rstatus", rmtstatushelp, 0, 1, 1, rmtstatus }, + { "rhelp", remotehelp, 0, 1, 1, rmthelp }, + { "rename", renamehelp, 0, 1, 1, renamefile }, + { "reset", resethelp, 0, 1, 1, reset }, + { "restart", restarthelp, 1, 1, 1, restart }, + { "rmdir", rmdirhelp, 0, 1, 1, removedir }, + { "runique", runiquehelp, 0, 0, 1, setrunique }, + { "send", sendhelp, 1, 1, 1, put }, + { "site", sitehelp, 0, 1, 1, site }, + { "size", sizecmdhelp, 1, 1, 1, sizecmd }, + { "status", statushelp, 0, 0, 1, status }, + { "struct", structhelp, 0, 1, 1, setstruct }, + { "system", systemhelp, 0, 1, 1, syst }, + { "sunique", suniquehelp, 0, 0, 1, setsunique }, + { "tenex", tenexhelp, 0, 1, 1, settenex }, + { "trace", tracehelp, 0, 0, 0, settrace }, + { "type", typehelp, 0, 1, 1, settype }, + { "user", userhelp, 0, 1, 1, user }, + { "umask", umaskhelp, 0, 1, 1, do_umask }, + { "verbose", verbosehelp, 0, 0, 0, setverbose }, + { "?", helphelp, 0, 0, 1, help }, + { 0 }, +}; + +int NCMDS = (sizeof (cmdtab) / sizeof (cmdtab[0])) - 1; diff --git a/bin/ftp/domacro.c b/bin/ftp/domacro.c new file mode 100644 index 0000000..f200c80 --- /dev/null +++ b/bin/ftp/domacro.c @@ -0,0 +1,121 @@ +#ifdef __ORCAC__ +segment "ftpmain "; +#endif + +static char sccsid[] = "@(#)domacro.c 1.8 (Berkeley) 9/28/90"; + +#include +#include +#include +#include +#include +#include + +#include "ftp.var.h" +#include "cmds.h" +#include "main.h" +#include "domacro.h" + +void domacro (int argc, char **argv) +{ +int i, j; +char *cp1, *cp2; +int count = 2, loopflg = 0; +static char line2[200]; +struct cmd *c; + + if (argc < 2 && !another(&argc, &argv, "macro name")) { + printf("Usage: %s macro_name.\n", argv[0]); + code = -1; + return; + } + for (i = 0; i < macnum; ++i) { + if (!strncmp(argv[1], macros[i].mac_name, 9)) { + break; + } + } + if (i == macnum) { + printf("'%s' macro not found.\n", argv[1]); + code = -1; + return; + } + (void) strcpy(line2, line); +TOP: + cp1 = macros[i].mac_start; + while (cp1 != macros[i].mac_end) { + while (isspace(*cp1)) { + cp1++; + } + cp2 = line; + while (*cp1 != '\0') { + switch(*cp1) { + case '\\': + *cp2++ = *++cp1; + break; + case '$': + if (isdigit(*(cp1+1))) { + j = 0; + while (isdigit(*++cp1)) { + j = 10*j + *cp1 - '0'; + } + cp1--; + if (argc - 2 >= j) { + (void) strcpy(cp2, argv[j+1]); + cp2 += strlen(argv[j+1]); + } + break; + } + if (*(cp1+1) == 'i') { + loopflg = 1; + cp1++; + if (count < argc) { + (void) strcpy(cp2, argv[count]); + cp2 += strlen(argv[count]); + } + break; + } + /* intentional drop through */ + default: + *cp2++ = *cp1; + break; + } + if (*cp1 != '\0') { + cp1++; + } + } + *cp2 = '\0'; + makeargv(); + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + code = -1; + } + else if (c == 0) { + printf("?Invalid command\n"); + code = -1; + } + else if (c->c_conn && !connected) { + printf("Not connected.\n"); + code = -1; + } + else { + if (verbose) { + printf("%s\n",line); + } + (*c->c_handler)(margc, margv); + if (bell && c->c_bell) { + (void) putchar('\007'); + } + (void) strcpy(line, line2); + makeargv(); + argc = margc; + argv = margv; + } + if (cp1 != macros[i].mac_end) { + cp1++; + } + } + if (loopflg && ++count < argc) { + goto TOP; + } +} diff --git a/bin/ftp/domacro.h b/bin/ftp/domacro.h new file mode 100644 index 0000000..219a960 --- /dev/null +++ b/bin/ftp/domacro.h @@ -0,0 +1 @@ +void domacro (int argc, char **argv); diff --git a/bin/ftp/ftp.1 b/bin/ftp/ftp.1 new file mode 100644 index 0000000..9f69ff2 --- /dev/null +++ b/bin/ftp/ftp.1 @@ -0,0 +1,1136 @@ +.\" Copyright (c) 1985, 1989, 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" 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. +.\" +.\" @(#)ftp.1 6.18 (Berkeley) 7/30/91 +.\" +.Dd July 30, 1991 +.Dt FTP 1 +.Os BSD 4.2 +.Sh NAME +.Nm ftp +.Nd +.Tn ARPANET +file transfer program +.Sh SYNOPSIS +.Nm ftp +.Op Fl v +.Op Fl d +.Op Fl i +.Op Fl n +.Op Fl g +.Op Ar host +.Sh DESCRIPTION +.Nm Ftp +is the user interface to the +.Tn ARPANET +standard File Transfer Protocol. +The program allows a user to transfer files to and from a +remote network site. +.Pp +Options may be specified at the command line, or to the +command interpreter. +.Bl -tag -width flag +.It Fl v +Verbose option forces +.Nm ftp +to show all responses from the remote server, as well +as report on data transfer statistics. +.It Fl n +Restrains +.Nm ftp +from attempting \*(Lqauto-login\*(Rq upon initial connection. +If auto-login is enabled, +.Nm ftp +will check the +.Pa .netrc +(see below) file in the user's home directory for an entry describing +an account on the remote machine. +If no entry exists, +.Nm ftp +will prompt for the remote machine login name (default is the user +identity on the local machine), and, if necessary, prompt for a password +and an account with which to login. +.It Fl i +Turns off interactive prompting during +multiple file transfers. +.It Fl d +Enables debugging. +.It Fl g +Disables file name globbing. +.El +.Pp +The client host with which +.Nm ftp +is to communicate may be specified on the command line. +If this is done, +.Nm ftp +will immediately attempt to establish a connection to an +.Tn FTP +server on that host; otherwise, +.Nm ftp +will enter its command interpreter and await instructions +from the user. +When +.Nm ftp +is awaiting commands from the user the prompt +.Ql ftp> +is provided to the user. +The following commands are recognized +by +.Nm ftp : +.Bl -tag -width Fl +.It Ic \&! Op Ar command Op Ar args +Invoke an interactive shell on the local machine. +If there are arguments, the first is taken to be a command to execute +directly, with the rest of the arguments as its arguments. +.It Ic \&$ Ar macro-name Op Ar args +Execute the macro +.Ar macro-name +that was defined with the +.Ic macdef +command. +Arguments are passed to the macro unglobbed. +.It Ic account Op Ar passwd +Supply a supplemental password required by a remote system for access +to resources once a login has been successfully completed. +If no argument is included, the user will be prompted for an account +password in a non-echoing input mode. +.It Ic append Ar local-file Op Ar remote-file +Append a local file to a file on the remote machine. +If +.Ar remote-file +is left unspecified, the local file name is used in naming the +remote file after being altered by any +.Ic ntrans +or +.Ic nmap +setting. +File transfer uses the current settings for +.Ic type , +.Ic format , +.Ic mode , +and +.Ic structure . +.It Ic ascii +Set the file transfer +.Ic type +to network +.Tn ASCII . +This is the default type. +.It Ic bell +Arrange that a bell be sounded after each file transfer +command is completed. +.It Ic binary +Set the file transfer +.Ic type +to support binary image transfer. +.It Ic bye +Terminate the +.Tn FTP +session with the remote server +and exit +.Nm ftp . +An end of file will also terminate the session and exit. +.It Ic case +Toggle remote computer file name case mapping during +.Ic mget +commands. +When +.Ic case +is on (default is off), remote computer file names with all letters in +upper case are written in the local directory with the letters mapped +to lower case. +.It Ic \&cd Ar remote-directory +Change the working directory on the remote machine +to +.Ar remote-directory . +.It Ic cdup +Change the remote machine working directory to the parent of the +current remote machine working directory. +.It Ic chmod Ar mode file-name +Change the permission modes of the file +.Ar file-name +on the remote +sytem to +.Ar mode . +.It Ic close +Terminate the +.Tn FTP +session with the remote server, and +return to the command interpreter. +Any defined macros are erased. +.It Ic \&cr +Toggle carriage return stripping during +ascii type file retrieval. +Records are denoted by a carriage return/linefeed sequence +during ascii type file transfer. +When +.Ic \&cr +is on (the default), carriage returns are stripped from this +sequence to conform with the +.Ux +single linefeed record +delimiter. +Records on +.Pf non\- Ns Ux +remote systems may contain single linefeeds; +when an ascii type transfer is made, these linefeeds may be +distinguished from a record delimiter only when +.Ic \&cr +is off. +.It Ic delete Ar remote-file +Delete the file +.Ar remote-file +on the remote machine. +.It Ic debug Op Ar debug-value +Toggle debugging mode. +If an optional +.Ar debug-value +is specified it is used to set the debugging level. +When debugging is on, +.Nm ftp +prints each command sent to the remote machine, preceded +by the string +.Ql \-\-> +.It Xo +.Ic dir +.Op Ar remote-directory +.Op Ar local-file +.Xc +Print a listing of the directory contents in the +directory, +.Ar remote-directory , +and, optionally, placing the output in +.Ar local-file . +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic dir +output. +If no directory is specified, the current working +directory on the remote machine is used. +If no local +file is specified, or +.Ar local-file +is +.Fl , +output comes to the terminal. +.It Ic disconnect +A synonym for +.Ar close . +.It Ic form Ar format +Set the file transfer +.Ic form +to +.Ar format . +The default format is \*(Lqfile\*(Rq. +.It Ic get Ar remote-file Op Ar local-file +Retrieve the +.Ar remote-file +and store it on the local machine. +If the local +file name is not specified, it is given the same +name it has on the remote machine, subject to +alteration by the current +.Ic case , +.Ic ntrans , +and +.Ic nmap +settings. +The current settings for +.Ic type , +.Ic form , +.Ic mode , +and +.Ic structure +are used while transferring the file. +.It Ic glob +Toggle filename expansion for +.Ic mdelete , +.Ic mget +and +.Ic mput . +If globbing is turned off with +.Ic glob , +the file name arguments +are taken literally and not expanded. +Globbing for +.Ic mput +is done as in +.Xr csh 1 . +For +.Ic mdelete +and +.Ic mget , +each remote file name is expanded +separately on the remote machine and the lists are not merged. +Expansion of a directory name is likely to be +different from expansion of the name of an ordinary file: +the exact result depends on the foreign operating system and ftp server, +and can be previewed by doing +.Ql mls remote-files \- +Note: +.Ic mget +and +.Ic mput +are not meant to transfer +entire directory subtrees of files. +That can be done by +transferring a +.Xr tar 1 +archive of the subtree (in binary mode). +.It Ic hash +Toggle hash-sign (``#'') printing for each data block +transferred. +The size of a data block is 1024 bytes. +.It Ic help Op Ar command +Print an informative message about the meaning of +.Ar command . +If no argument is given, +.Nm ftp +prints a list of the known commands. +.It Ic idle Op Ar seconds +Set the inactivity timer on the remote server to +.Ar seconds +seconds. +If +.Ar seconds +is ommitted, the current inactivity timer is printed. +.It Ic lcd Op Ar directory +Change the working directory on the local machine. +If +no +.Ar directory +is specified, the user's home directory is used. +.It Xo +.Ic \&ls +.Op Ar remote-directory +.Op Ar local-file +.Xc +Print a listing of the contents of a +directory on the remote machine. +The listing includes any system-dependent information that the server +chooses to include; for example, most +.Ux +systems will produce +output from the command +.Ql ls \-l . +(See also +.Ic nlist . ) +If +.Ar remote-directory +is left unspecified, the current working directory is used. +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic \&ls +output. +If no local file is specified, or if +.Ar local-file +is +.Sq Fl , +the output is sent to the terminal. +.It Ic macdefNs Ar macro-name +Define a macro. +Subsequent lines are stored as the macro +.Ar macro-name ; +a null line (consecutive newline characters +in a file or +carriage returns from the terminal) terminates macro input mode. +There is a limit of 16 macros and 4096 total characters in all +defined macros. +Macros remain defined until a +.Ic close +command is executed. +The macro processor interprets `$' and `\e' as special characters. +A `$' followed by a number (or numbers) is replaced by the +corresponding argument on the macro invocation command line. +A `$' followed by an `i' signals that macro processor that the +executing macro is to be looped. +On the first pass `$i' is +replaced by the first argument on the macro invocation command line, +on the second pass it is replaced by the second argument, and so on. +A `\e' followed by any character is replaced by that character. +Use the `\e' to prevent special treatment of the `$'. +.It Ic mdelete Op Ar remote-files +Delete the +.Ar remote-files +on the remote machine. +.It Ic mdir Ar remote-files local-file +Like +.Ic dir , +except multiple remote files may be specified. +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic mdir +output. +.It Ic mget Ar remote-files +Expand the +.Ar remote-files +on the remote machine +and do a +.Ic get +for each file name thus produced. +See +.Ic glob +for details on the filename expansion. +Resulting file names will then be processed according to +.Ic case , +.Ic ntrans , +and +.Ic nmap +settings. +Files are transferred into the local working directory, +which can be changed with +.Ql lcd directory ; +new local directories can be created with +.Ql "\&! mkdir directory" . +.It Ic mkdir Ar directory-name +Make a directory on the remote machine. +.It Ic mls Ar remote-files local-file +Like +.Ic nlist , +except multiple remote files may be specified, +and the +.Ar local-file +must be specified. +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic mls +output. +.It Ic mode Op Ar mode-name +Set the file transfer +.Ic mode +to +.Ar mode-name . +The default mode is \*(Lqstream\*(Rq mode. +.It Ic modtime Ar file-name +Show the last modification time of the file on the remote machine. +.It Ic mput Ar local-files +Expand wild cards in the list of local files given as arguments +and do a +.Ic put +for each file in the resulting list. +See +.Ic glob +for details of filename expansion. +Resulting file names will then be processed according to +.Ic ntrans +and +.Ic nmap +settings. +.It Ic newer Ar file-name +Get the file only if the modification time of the remote file is more +recent that the file on the current system. +If the file does not +exist on the current system, the remote file is considered +.Ic newer . +Otherwise, this command is identical to +.Ar get . +.It Xo +.Ic nlist +.Op Ar remote-directory +.Op Ar local-file +.Xc +Print a list of the files in a +directory on the remote machine. +If +.Ar remote-directory +is left unspecified, the current working directory is used. +If interactive prompting is on, +.Nm ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.Ic nlist +output. +If no local file is specified, or if +.Ar local-file +is +.Fl , +the output is sent to the terminal. +.It Ic nmap Op Ar inpattern outpattern +Set or unset the filename mapping mechanism. +If no arguments are specified, the filename mapping mechanism is unset. +If arguments are specified, remote filenames are mapped during +.Ic mput +commands and +.Ic put +commands issued without a specified remote target filename. +If arguments are specified, local filenames are mapped during +.Ic mget +commands and +.Ic get +commands issued without a specified local target filename. +This command is useful when connecting to a +.No non\- Ns Ux +remote computer +with different file naming conventions or practices. +The mapping follows the pattern set by +.Ar inpattern +and +.Ar outpattern . +.Op Ar Inpattern +is a template for incoming filenames (which may have already been +processed according to the +.Ic ntrans +and +.Ic case +settings). +Variable templating is accomplished by including the +sequences `$1', `$2', ..., `$9' in +.Ar inpattern . +Use `\\' to prevent this special treatment of the `$' character. +All other characters are treated literally, and are used to determine the +.Ic nmap +.Op Ar inpattern +variable values. +For example, given +.Ar inpattern +$1.$2 and the remote file name "mydata.data", $1 would have the value +"mydata", and $2 would have the value "data". +The +.Ar outpattern +determines the resulting mapped filename. +The sequences `$1', `$2', ...., `$9' are replaced by any value resulting +from the +.Ar inpattern +template. +The sequence `$0' is replace by the original filename. +Additionally, the sequence +.Ql Op Ar seq1 , Ar seq2 +is replaced by +.Op Ar seq1 +if +.Ar seq1 +is not a null string; otherwise it is replaced by +.Ar seq2 . +For example, the command +.Pp +.Bd -literal -offset indent -compact +nmap $1.$2.$3 [$1,$2].[$2,file] +.Ed +.Pp +would yield +the output filename "myfile.data" for input filenames "myfile.data" and +"myfile.data.old", "myfile.file" for the input filename "myfile", and +"myfile.myfile" for the input filename ".myfile". +Spaces may be included in +.Ar outpattern , +as in the example: `nmap $1 sed "s/ *$//" > $1' . +Use the `\e' character to prevent special treatment +of the `$','[','[', and `,' characters. +.It Ic ntrans Op Ar inchars Op Ar outchars +Set or unset the filename character translation mechanism. +If no arguments are specified, the filename character +translation mechanism is unset. +If arguments are specified, characters in +remote filenames are translated during +.Ic mput +commands and +.Ic put +commands issued without a specified remote target filename. +If arguments are specified, characters in +local filenames are translated during +.Ic mget +commands and +.Ic get +commands issued without a specified local target filename. +This command is useful when connecting to a +.No non\- Ns Ux +remote computer +with different file naming conventions or practices. +Characters in a filename matching a character in +.Ar inchars +are replaced with the corresponding character in +.Ar outchars . +If the character's position in +.Ar inchars +is longer than the length of +.Ar outchars , +the character is deleted from the file name. +.It Ic open Ar host Op Ar port +Establish a connection to the specified +.Ar host +.Tn FTP +server. +An optional port number may be supplied, +in which case, +.Nm ftp +will attempt to contact an +.Tn FTP +server at that port. +If the +.Ic auto-login +option is on (default), +.Nm ftp +will also attempt to automatically log the user in to +the +.Tn FTP +server (see below). +.It Ic prompt +Toggle interactive prompting. +Interactive prompting +occurs during multiple file transfers to allow the +user to selectively retrieve or store files. +If prompting is turned off (default is on), any +.Ic mget +or +.Ic mput +will transfer all files, and any +.Ic mdelete +will delete all files. +.It Ic proxy Ar ftp-command +Execute an ftp command on a secondary control connection. +This command allows simultaneous connection to two remote ftp +servers for transferring files between the two servers. +The first +.Ic proxy +command should be an +.Ic open , +to establish the secondary control connection. +Enter the command "proxy ?" to see other ftp commands executable on the +secondary connection. +The following commands behave differently when prefaced by +.Ic proxy : +.Ic open +will not define new macros during the auto-login process, +.Ic close +will not erase existing macro definitions, +.Ic get +and +.Ic mget +transfer files from the host on the primary control connection +to the host on the secondary control connection, and +.Ic put , +.Ic mput , +and +.Ic append +transfer files from the host on the secondary control connection +to the host on the primary control connection. +Third party file transfers depend upon support of the ftp protocol +.Dv PASV +command by the server on the secondary control connection. +.It Ic put Ar local-file Op Ar remote-file +Store a local file on the remote machine. +If +.Ar remote-file +is left unspecified, the local file name is used +after processing according to any +.Ic ntrans +or +.Ic nmap +settings +in naming the remote file. +File transfer uses the +current settings for +.Ic type , +.Ic format , +.Ic mode , +and +.Ic structure . +.It Ic pwd +Print the name of the current working directory on the remote +machine. +.It Ic quit +A synonym for +.Ic bye . +.It Ic quote Ar arg1 arg2 ... +The arguments specified are sent, verbatim, to the remote +.Tn FTP +server. +.It Ic recv Ar remote-file Op Ar local-file +A synonym for get. +.It Ic reget Ar remote-file Op Ar local-file +Reget acts like get, except that if +.Ar local-file +exists and is +smaller than +.Ar remote-file , +.Ar local-file +is presumed to be +a partially transferred copy of +.Ar remote-file +and the transfer +is continued from the apparent point of failure. +This command +is useful when transferring very large files over networks that +are prone to dropping connections. +.It Ic remotehelp Op Ar command-name +Request help from the remote +.Tn FTP +server. +If a +.Ar command-name +is specified it is supplied to the server as well. +.It Ic remotestatus Op Ar file-name +With no arguments, show status of remote machine. +If +.Ar file-name +is specified, show status of +.Ar file-name +on remote machine. +.It Xo +.Ic rename +.Op Ar from +.Op Ar to +.Xc +Rename the file +.Ar from +on the remote machine, to the file +.Ar to . +.It Ic reset +Clear reply queue. +This command re-synchronizes command/reply sequencing with the remote +ftp server. +Resynchronization may be necessary following a violation of the ftp protocol +by the remote server. +.It Ic restart Ar marker +Restart the immediately following +.Ic get +or +.Ic put +at the +indicated +.Ar marker . +On +.Ux +systems, marker is usually a byte +offset into the file. +.It Ic rmdir Ar directory-name +Delete a directory on the remote machine. +.It Ic runique +Toggle storing of files on the local system with unique filenames. +If a file already exists with a name equal to the target +local filename for a +.Ic get +or +.Ic mget +command, a ".1" is appended to the name. +If the resulting name matches another existing file, +a ".2" is appended to the original name. +If this process continues up to ".99", an error +message is printed, and the transfer does not take place. +The generated unique filename will be reported. +Note that +.Ic runique +will not affect local files generated from a shell command +(see below). +The default value is off. +.It Ic send Ar local-file Op Ar remote-file +A synonym for put. +.It Ic sendport +Toggle the use of +.Dv PORT +commands. +By default, +.Nm ftp +will attempt to use a +.Dv PORT +command when establishing +a connection for each data transfer. +The use of +.Dv PORT +commands can prevent delays +when performing multiple file transfers. +If the +.Dv PORT +command fails, +.Nm ftp +will use the default data port. +When the use of +.Dv PORT +commands is disabled, no attempt will be made to use +.Dv PORT +commands for each data transfer. +This is useful +for certain +.Tn FTP +implementations which do ignore +.Dv PORT +commands but, incorrectly, indicate they've been accepted. +.It Ic site Ar arg1 arg2 ... +The arguments specified are sent, verbatim, to the remote +.Tn FTP +server as a +.Dv SITE +command. +.It Ic size Ar file-name +Return size of +.Ar file-name +on remote machine. +.It Ic status +Show the current status of +.Nm ftp . +.It Ic struct Op Ar struct-name +Set the file transfer +.Ar structure +to +.Ar struct-name . +By default \*(Lqstream\*(Rq structure is used. +.It Ic sunique +Toggle storing of files on remote machine under unique file names. +Remote ftp server must support ftp protocol +.Dv STOU +command for +successful completion. +The remote server will report unique name. +Default value is off. +.It Ic system +Show the type of operating system running on the remote machine. +.It Ic tenex +Set the file transfer type to that needed to +talk to +.Tn TENEX +machines. +.It Ic trace +Toggle packet tracing. +.It Ic type Op Ar type-name +Set the file transfer +.Ic type +to +.Ar type-name . +If no type is specified, the current type +is printed. +The default type is network +.Tn ASCII . +.It Ic umask Op Ar newmask +Set the default umask on the remote server to +.Ar newmask . +If +.Ar newmask +is ommitted, the current umask is printed. +.It Xo +.Ic user Ar user-name +.Op Ar password +.Op Ar account +.Xc +Identify yourself to the remote +.Tn FTP +server. +If the +.Ar password +is not specified and the server requires it, +.Nm ftp +will prompt the user for it (after disabling local echo). +If an +.Ar account +field is not specified, and the +.Tn FTP +server +requires it, the user will be prompted for it. +If an +.Ar account +field is specified, an account command will +be relayed to the remote server after the login sequence +is completed if the remote server did not require it +for logging in. +Unless +.Nm ftp +is invoked with \*(Lqauto-login\*(Rq disabled, this +process is done automatically on initial connection to +the +.Tn FTP +server. +.It Ic verbose +Toggle verbose mode. +In verbose mode, all responses from +the +.Tn FTP +server are displayed to the user. +In addition, +if verbose is on, when a file transfer completes, statistics +regarding the efficiency of the transfer are reported. +By default, +verbose is on. +.It Ic ? Op Ar command +A synonym for help. +.El +.Pp +Command arguments which have embedded spaces may be quoted with +quote `"' marks. +.Sh ABORTING A FILE TRANSFER +To abort a file transfer, use the terminal interrupt key +(usually Ctrl-C). +Sending transfers will be immediately halted. +Receiving transfers will be halted by sending a ftp protocol +.Dv ABOR +command to the remote server, and discarding any further data received. +The speed at which this is accomplished depends upon the remote +server's support for +.Dv ABOR +processing. +If the remote server does not support the +.Dv ABOR +command, an +.Ql ftp> +prompt will not appear until the remote server has completed +sending the requested file. +.Pp +The terminal interrupt key sequence will be ignored when +.Nm ftp +has completed any local processing and is awaiting a reply +from the remote server. +A long delay in this mode may result from the ABOR processing described +above, or from unexpected behavior by the remote server, including +violations of the ftp protocol. +If the delay results from unexpected remote server behavior, the local +.Nm ftp +program must be killed by hand. +.Sh FILE NAMING CONVENTIONS +Files specified as arguments to +.Nm ftp +commands are processed according to the following rules. +.Bl -enum +.It +If the file name +.Sq Fl +is specified, the +.Ar stdin +(for reading) or +.Ar stdout +(for writing) is used. +.It +If the first character of the file name is +.Sq \&| , +the +remainder of the argument is interpreted as a shell command. +.Nm Ftp +then forks a shell, using +.Xr popen 3 +with the argument supplied, and reads (writes) from the stdout +(stdin). +If the shell command includes spaces, the argument +must be quoted; e.g. +\*(Lq" ls -lt"\*(Rq. +A particularly +useful example of this mechanism is: \*(Lqdir more\*(Rq. +.It +Failing the above checks, if ``globbing'' is enabled, +local file names are expanded +according to the rules used in the +.Xr csh 1 ; +c.f. the +.Ic glob +command. +If the +.Nm ftp +command expects a single local file (.e.g. +.Ic put ) , +only the first filename generated by the "globbing" operation is used. +.It +For +.Ic mget +commands and +.Ic get +commands with unspecified local file names, the local filename is +the remote filename, which may be altered by a +.Ic case , +.Ic ntrans , +or +.Ic nmap +setting. +The resulting filename may then be altered if +.Ic runique +is on. +.It +For +.Ic mput +commands and +.Ic put +commands with unspecified remote file names, the remote filename is +the local filename, which may be altered by a +.Ic ntrans +or +.Ic nmap +setting. +The resulting filename may then be altered by the remote server if +.Ic sunique +is on. +.El +.Sh FILE TRANSFER PARAMETERS +The FTP specification specifies many parameters which may +affect a file transfer. +The +.Ic type +may be one of \*(Lqascii\*(Rq, \*(Lqimage\*(Rq (binary), +\*(Lqebcdic\*(Rq, and \*(Lqlocal byte size\*(Rq (for +.Tn PDP Ns -10's +and +.Tn PDP Ns -20's +mostly). +.Nm Ftp +supports the ascii and image types of file transfer, +plus local byte size 8 for +.Ic tenex +mode transfers. +.Pp +.Nm Ftp +supports only the default values for the remaining +file transfer parameters: +.Ic mode , +.Ic form , +and +.Ic struct . +.Sh THE .netrc FILE +The +.Pa .netrc +file contains login and initialization information +used by the auto-login process. +It resides in the user's home directory. +The following tokens are recognized; they may be separated by spaces, +tabs, or new-lines: +.Bl -tag -width password +.It Ic machine Ar name +Identify a remote machine +.Ar name . +The auto-login process searches the +.Pa .netrc +file for a +.Ic machine +token that matches the remote machine specified on the +.Nm ftp +command line or as an +.Ic open +command argument. +Once a match is made, the subsequent +.Pa .netrc +tokens are processed, +stopping when the end of file is reached or another +.Ic machine +or a +.Ic default +token is encountered. +.It Ic default +This is the same as +.Ic machine +.Ar name +except that +.Ic default +matches any name. +There can be only one +.Ic default +token, and it must be after all +.Ic machine +tokens. +This is normally used as: +.Pp +.Dl default login anonymous password user@site +.Pp +thereby giving the user +.Ar automatic +anonymous ftp login to +machines not specified in +.Pa .netrc . +This can be overridden +by using the +.Fl n +flag to disable auto-login. +.It Ic login Ar name +Identify a user on the remote machine. +If this token is present, the auto-login process will initiate +a login using the specified +.Ar name . +.It Ic password Ar string +Supply a password. +If this token is present, the auto-login process will supply the +specified string if the remote server requires a password as part +of the login process. +Note that if this token is present in the +.Pa .netrc +file for any user other +than +.Ar anonymous , +.Nm ftp +will abort the auto-login process if the +.Pa .netrc +is readable by +anyone besides the user. +.It Ic account Ar string +Supply an additional account password. +If this token is present, the auto-login process will supply the +specified string if the remote server requires an additional +account password, or the auto-login process will initiate an +.Dv ACCT +command if it does not. +.It Ic macdef Ar name +Define a macro. +This token functions like the +.Nm ftp +.Ic macdef +command functions. +A macro is defined with the specified name; its contents begin with the +next +.Pa .netrc +line and continue until a null line (consecutive new-line +characters) is encountered. +If a macro named +.Ic init +is defined, it is automatically executed as the last step in the +auto-login process. +.El +.Sh ENVIRONMENT +.Nm Ftp +utilizes the following environment variables. +.Bl -tag -width Fl +.It Ev HOME +For default location of a +.Pa .netrc +file, if one exists. +.It Ev SHELL +For default shell. +.El +.Sh SEE ALSO +.Xr ftpd 8 +.Sh HISTORY +The +.Nm ftp +command appeared in +.Bx 4.2 . +.Sh BUGS +Correct execution of many commands depends upon proper behavior +by the remote server. +.Pp +An error in the treatment of carriage returns +in the +.Bx 4.2 +ascii-mode transfer code +has been corrected. +This correction may result in incorrect transfers of binary files +to and from +.Bx 4.2 +servers using the ascii type. +Avoid this problem by using the binary image type. diff --git a/bin/ftp/ftp.1G b/bin/ftp/ftp.1G new file mode 100644 index 0000000..3f059cd --- /dev/null +++ b/bin/ftp/ftp.1G @@ -0,0 +1,1042 @@ +.\" Copyright (c) 1985, 1989, 1990 The Regents of the University of California. +.\" All rights reserved. +.\" +.\" 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. +.\" +.\" @(#)ftp.1 6.18 (Berkeley) 7/30/91 +.\" +.\" $Id: ftp.1G 467 1998-02-15 00:31:01Z gdr $ +.\" +.TH FTP 1 "October 1997" GNO "Commands and Applications" +.SH NAME +.BR ftp +\- ARPANET file transfer program +.SH SYNOPSIS +.BR ftp +.RB [ -vding ] +.RI [ host ] +.SH DESCRIPTION +.BR Ftp +is the user interface to the ARPANET +standard File Transfer Protocol. +The program allows a user to transfer files to and from a +remote network site. +.LP +Options may be specified at the command line, or to the +command interpreter. +.IP "\fB-v\fR" +Verbose option forces +.BR ftp +to show all responses from the remote server, as well +as report on data transfer statistics. +.IP "\fB-n\fR" +Restrains +.BR ftp +from attempting \`auto-login\' upon initial connection. +If auto-login is enabled, +.BR ftp +will check the +.BR .netrc +(see below) file in the user's home directory for an entry describing +an account on the remote machine. +If no entry exists, +.BR ftp +will prompt for the remote machine login name (default is the user +identity on the local machine), and, if necessary, prompt for a password +and an account with which to login. +.IP "\fB-i\fR" +Turns off interactive prompting during +multiple file transfers. +.IP "\fB-d\fR" +Enables debugging. +.IP "\fB-g\fR" +Disables file name globbing. +.LP +The client host with which +.BR ftp +is to communicate may be specified on the command line. +If this is done, +.BR ftp +will immediately attempt to establish a connection to an FTP +server on that host; otherwise, +.BR ftp +will enter its command interpreter and await instructions +from the user. +When +.BR ftp +is awaiting commands from the user the prompt +.BR "ftp>" +is provided to the user. +The following commands are recognized +by +.BR ftp : +.IP "\fB\&!\fR [\fIcommand\fR [\fIargs\fR]]" +Invoke an interactive shell on the local machine. +If there are arguments, the first is taken to be a command to execute +directly, with the rest of the arguments as its arguments. +.IP "\fB\&$\fR \fImacro-name\fR [\fIargs\fR]" +Execute the macro +.IR macro-name +that was defined with the +.B macdef +command. +Arguments are passed to the macro unglobbed. +.IP "\fBaccount\fR [\fIpasswd\fR]" +Supply a supplemental password required by a remote system for access +to resources once a login has been successfully completed. +If no argument is included, the user will be prompted for an account +password in a non-echoing input mode. +.IP "\fBappend\fR \fIlocal-file\fR [\fIremote-file\fR]" +Append a local file to a file on the remote machine. +If +.IR remote-file +is left unspecified, the local file name is used in naming the +remote file after being altered by any +.B ntrans +or +.B nmap +setting. +File transfer uses the current settings for +.BR type , +.BR format , +.BR mode , +and +.BR structure . +.IP "\fBascii\fR" +Set the file transfer +.B type +to network ASCII. +This is the default type. +.IP "\fBbell\fR" +Arrange that a bell be sounded after each file transfer +command is completed. +.IP "\fBbinary\fR" +Set the file transfer +.BR type +to support binary image transfer. +.IP "\fBbye\fR" +Terminate the FTP +session with the remote server +and exit +.BR ftp . +An end of file will also terminate the session and exit. +.IP "\fBcase\fR" +Toggle remote computer file name case mapping during +.BR mget +commands. +When +.BR case +is on (default is off), remote computer file names with all letters in +upper case are written in the local directory with the letters mapped +to lower case. +.IP "\fB\&cd\fR \fIremote-directory\fR" +Change the working directory on the remote machine +to +.IR remote-directory . +.IP "\fBcdup\fR" +Change the remote machine working directory to the parent of the +current remote machine working directory. +.IP "\fBchmod\fR \fImode\fR \fIfile-name\fR" +Change the permission modes of the file +.IR file-name +on the remote +sytem to +.IR mode . +.IP "\fBclose\fR" +Terminate the FTP +session with the remote server, and +return to the command interpreter. +Any defined macros are erased. +.IP "\fB\&cr\fR" +Toggle carriage return stripping during +ascii type file retrieval. +Records are denoted by a carriage return/linefeed sequence +during ascii type file transfer. +When +.BR \&cr +is on (the default), carriage returns are stripped from this +sequence to conform with the +UNIX +single linefeed record +delimiter. +Records on non\-UNIX +remote systems may contain single linefeeds; +when an ascii type transfer is made, these linefeeds may be +distinguished from a record delimiter only when +.BR \&cr +is off. +.IP "\fBdelete\fR \fIremote-file\fR" +Delete the file +.IR remote-file +on the remote machine. +.IP "\fBdebug\fR [\fIdebug-value\fR]" +Toggle debugging mode. +If an optional +.IR debug-value +is specified it is used to set the debugging level. +When debugging is on, +.BR ftp +prints each command sent to the remote machine, preceded +by the string +.BR "\-\->" +.IP "\fBdir\fR [\fIremote-directory\fR] [\fIlocal-file\fR]" +Print a listing of the directory contents in the +directory, +.IR remote-directory , +and, optionally, placing the output in +.IR local-file . +If interactive prompting is on, +.BR ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.BR dir +output. +If no directory is specified, the current working +directory on the remote machine is used. +If no local +file is specified, or +.IR local-file +is +.BR - , +output comes to the terminal. +.IP "\fBdisconnect\fR" +A synonym for +.BR close . +.IP "\fBform\fR \fIformat\fR" +Set the file transfer +.BR form +to +.IR format . +The default format is \`file\'. +.IP "\fBget\fR \fIremote-file\fR [\fIlocal-file\fR]" +Retrieve the +.IR remote-file +and store it on the local machine. +If the local +file name is not specified, it is given the same +name it has on the remote machine, subject to +alteration by the current +.BR case , +.BR ntrans , +and +.BR nmap +settings. +The current settings for +.BR type , +.BR form , +.BR mode , +and +.BR structure +are used while transferring the file. +.IP "\fBglob\fR" +Toggle filename expansion for +.BR mdelete , +.BR mget +and +.BR mput . +If globbing is turned off with +.BR glob , +the file name arguments +are taken literally and not expanded. +Globbing for +.BR mput +is done as in +.BR csh (1). +For +.BR mdelete +and +.BR mget , +each remote file name is expanded +separately on the remote machine and the lists are not merged. +Expansion of a directory name is likely to be +different from expansion of the name of an ordinary file: +the exact result depends on the foreign operating system and ftp server, +and can be previewed by doing +.B "mls remote-files \-" +Note: +.BR mget +and +.BR mput +are not meant to transfer +entire directory subtrees of files. +That can be done by +transferring a +.BR tar (1) +archive of the subtree (in binary mode). +.IP "\fBhash\fR" +Toggle hash-sign (``#'') printing for each data block +transferred. +The size of a data block is 1024 bytes. +.IP "\fBhelp\fR [\fIcommand\fR]" +Print an informative message about the meaning of +.IR command . +If no argument is given, +.BR ftp +prints a list of the known commands. +.IP "\fBidle\fR [\fIseconds\fR]" +Set the inactivity timer on the remote server to +.IR seconds +seconds. +If +.IR seconds +is ommitted, the current inactivity timer is printed. +.IP "\fBlcd\fR [\fIdirectory\fR]" +Change the working directory on the local machine. +If +no +.IR directory +is specified, the user's home directory is used. +.IP "\fBls\fR [\fIremote-directory\fR] [\fIlocal-file\fR]" +Print a listing of the contents of a +directory on the remote machine. +The listing includes any system-dependent information that the server +chooses to include; for example, most +UNIX +systems will produce +output from the command +.BR "ls \-l" . +(See also +.BR nlist .) +If +.IR remote-directory +is left unspecified, the current working directory is used. +If interactive prompting is on, +.BR ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.BR \&ls +output. +If no local file is specified, or if +.IR local-file +is +.BR \&- , +the output is sent to the terminal. +.IP "\fBmacdefNs\fR \fImacro-name\fR" +Define a macro. +Subsequent lines are stored as the macro +.IR macro-name ; +a null line (consecutive newline characters +in a file or +carriage returns from the terminal) terminates macro input mode. +There is a limit of 16 macros and 4096 total characters in all +defined macros. +Macros remain defined until a +.BR close +command is executed. +The macro processor interprets `$' and `\e' as special characters. +A `$' followed by a number (or numbers) is replaced by the +corresponding argument on the macro invocation command line. +A `$' followed by an `i' signals that macro processor that the +executing macro is to be looped. +On the first pass `$i' is +replaced by the first argument on the macro invocation command line, +on the second pass it is replaced by the second argument, and so on. +A `\e' followed by any character is replaced by that character. +Use the `\e' to prevent special treatment of the `$'. +.IP "\fBmdelete\fR [\fIremote-files\fR]" +Delete the +.IR remote-files +on the remote machine. +.IP "\fBmdir\fR \fIremote-files\fR \fIlocal-file\fR" +Like +.BR dir , +except multiple remote files may be specified. +If interactive prompting is on, +.BR ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.BR mdir +output. +.IP "\fBmget\fR \fIremote-files\fR" +Expand the +.IR remote-files +on the remote machine +and do a +.BR get +for each file name thus produced. +See +.BR glob +for details on the filename expansion. +Resulting file names will then be processed according to +.BR case , +.BR ntrans , +and +.BR nmap +settings. +Files are transferred into the local working directory, +which can be changed with +.BR "lcd directory" ; +new local directories can be created with +.BR "\&! mkdir directory" . +.IP "\fBmkdir\fR \fIdirectory-name\fR" +Make a directory on the remote machine. +.IP "\fBmls\fR \fIremote-files\fR \fIlocal-file\fR" +Like +.BR nlist , +except multiple remote files may be specified, +and the +.IR local-file +must be specified. +If interactive prompting is on, +.BR ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.BR mls +output. +.IP "\fBmode\fR [\fImode-name\fR]" +Set the file transfer +.BR mode +to +.IR mode-name . +The default mode is \`stream\' mode. +.IP "\fBmodtime\fR \fIfile-name\fR" +Show the last modification time of the file on the remote machine. +.IP "\fBmput\fR \fIlocal-files\fR" +Expand wild cards in the list of local files given as arguments +and do a +.BR put +for each file in the resulting list. +See +.BR glob +for details of filename expansion. +Resulting file names will then be processed according to +.BR ntrans +and +.BR nmap +settings. +.IP "\fBnewer\fR \fIfile-name\fR" +Get the file only if the modification time of the remote file is more +recent that the file on the current system. +If the file does not +exist on the current system, the remote file is considered +.BR newer . +Otherwise, this command is identical to +.BR get . +.IP "\fBnlist\fR [\fIremote-directory\fR] [\fIlocal-file\fR]" +Print a list of the files in a +directory on the remote machine. +If +.IR remote-directory +is left unspecified, the current working directory is used. +If interactive prompting is on, +.BR ftp +will prompt the user to verify that the last argument is indeed the +target local file for receiving +.BR nlist +output. +If no local file is specified, or if +.IR local-file +is +.BR \&- , +the output is sent to the terminal. +.IP "\fBnmap\fR [\fIinpattern\fR \fIoutpattern\fR]" +Set or unset the filename mapping mechanism. +If no arguments are specified, the filename mapping mechanism is unset. +If arguments are specified, remote filenames are mapped during +.BR mput +commands and +.BR put +commands issued without a specified remote target filename. +If arguments are specified, local filenames are mapped during +.BR mget +commands and +.BR get +commands issued without a specified local target filename. +This command is useful when connecting to a non\-UNIX +remote computer +with different file naming conventions or practices. +The mapping follows the pattern set by +.IR inpattern +and +.IR outpattern . +.I Inpattern +is a template for incoming filenames (which may have already been +processed according to the +.BR ntrans +and +.BR case +settings). +Variable templating is accomplished by including the +sequences `$1', `$2', ..., `$9' in +.IR inpattern . +Use `\\' to prevent this special treatment of the `$' character. +All other characters are treated literally, and are used to determine the +.BR nmap +.I inpattern +variable values. +For example, given +.IR inpattern +$1.$2 and the remote file name "mydata.data", $1 would have the value +"mydata", and $2 would have the value "data". +The +.IR outpattern +determines the resulting mapped filename. +The sequences `$1', `$2', ...., `$9' are replaced by any value resulting +from the +.IR inpattern +template. +The sequence `$0' is replace by the original filename. +Additionally, the sequence +.RI "'[" seq1 , " seq2" "]'" +is replaced by +.I seq1 +if +.I seq1 +is not a null string; otherwise it is replaced by +.IR seq2 . +For example, the command +.nf + + nmap $1.$2.$3 [$1,$2].[$2,file] + +.fi +would yield +the output filename "myfile.data" for input filenames "myfile.data" and +"myfile.data.old", "myfile.file" for the input filename "myfile", and +"myfile.myfile" for the input filename ".myfile". +Spaces may be included in +.IR outpattern , +as in the example: `nmap $1 sed "s/ *$//" > $1' . +Use the `\e' character to prevent special treatment +of the `$','[','[', and `,' characters. +.IP "\fBntrans\fR [\fIinchars\fR [\fIoutchars\fR]]" +Set or unset the filename character translation mechanism. +If no arguments are specified, the filename character +translation mechanism is unset. +If arguments are specified, characters in +remote filenames are translated during +.BR mput +commands and +.BR put +commands issued without a specified remote target filename. +If arguments are specified, characters in +local filenames are translated during +.BR mget +commands and +.BR get +commands issued without a specified local target filename. +This command is useful when connecting to a non\-UNIX +remote computer +with different file naming conventions or practices. +Characters in a filename matching a character in +.IR inchars +are replaced with the corresponding character in +.IR outchars . +If the character's position in +.IR inchars +is longer than the length of +.IR outchars , +the character is deleted from the file name. +.IP "\fBopen\fR \fIhost\fR [\fIport\fR]" +Establish a connection to the specified +.IR host +FTP server. +An optional port number may be supplied, +in which case, +.BR ftp +will attempt to contact an FTP +server at that port. +If the +.BR auto-login +option is on (default), +.BR ftp +will also attempt to automatically log the user in to +the FTP +server (see below). +.IP "\fBprompt\fR" +Toggle interactive prompting. +Interactive prompting +occurs during multiple file transfers to allow the +user to selectively retrieve or store files. +If prompting is turned off (default is on), any +.BR mget +or +.BR mput +will transfer all files, and any +.BR mdelete +will delete all files. +.IP "\fBproxy\fR \fIftp-command\fR" +Execute an ftp command on a secondary control connection. +This command allows simultaneous connection to two remote ftp +servers for transferring files between the two servers. +The first +.BR proxy +command should be an +.BR open , +to establish the secondary control connection. +Enter the command "proxy ?" to see other ftp commands executable on the +secondary connection. +The following commands behave differently when prefaced by +.BR proxy : +.BR open +will not define new macros during the auto-login process, +.BR close +will not erase existing macro definitions, +.BR get +and +.BR mget +transfer files from the host on the primary control connection +to the host on the secondary control connection, and +.BR put , +.BR mput , +and +.BR append +transfer files from the host on the secondary control connection +to the host on the primary control connection. +Third party file transfers depend upon support of the ftp protocol +.BR PASV +command by the server on the secondary control connection. +.IP "\fBput\fR \fIlocal-file\fR [\fIremote-file\fR]" +Store a local file on the remote machine. +If +.IR remote-file +is left unspecified, the local file name is used +after processing according to any +.BR ntrans +or +.BR nmap +settings +in naming the remote file. +File transfer uses the +current settings for +.BR type , +.BR format , +.BR mode , +and +.BR structure . +.IP "\fBpwd\fR" +Print the name of the current working directory on the remote +machine. +.IP "\fBquit\fR" +A synonym for +.BR bye . +.IP "\fBquot\fR \fIarg1\fR \fIarg2\fR \fI...\fR" +The arguments specified are sent, verbatim, to the remote FTP +server. +.IP "\fBrecv\fR \fIremote-file\fR [\fIlocal-file\fR]" +A synonym for get. +.IP "\fBreget\fR \fIremote-file\fR [\fIlocal-file\fR]" +Reget acts like get, except that if +.IR local-file +exists and is +smaller than +.IR remote-file , +.IR local-file +is presumed to be +a partially transferred copy of +.IR remote-file +and the transfer +is continued from the apparent point of failure. +This command +is useful when transferring very large files over networks that +are prone to dropping connections. +.IP "\fBremotehelp\fR [\fIcommand-name\fR]" +Request help from the remote FTP +server. +If a +.IR command-name +is specified it is supplied to the server as well. +.IP "\fBremotestatus\fR [\fIfile-name\fR]" +With no arguments, show status of remote machine. +If +.IR file-name +is specified, show status of +.IR file-name +on remote machine. +.IP "\fBrename\fR [\fIfrom\fR] [\fIto\fR]" +Rename the file +.IR from +on the remote machine, to the file +.IR to . +.IP "\fBreset\fR" +Clear reply queue. +This command re-synchronizes command/reply sequencing with the remote +ftp server. +Resynchronization may be necessary following a violation of the ftp protocol +by the remote server. +.IP "\fBrestart\fR \fImarker\fR" +Restart the immediately following +.BR get +or +.BR put +at the +indicated +.IR marker . +On +UNIX +systems, marker is usually a byte +offset into the file. +.IP "\fBrmdir\fR \fIdirectory-name\fR" +Delete a directory on the remote machine. +.IP "\fBrunique\fR" +Toggle storing of files on the local system with unique filenames. +If a file already exists with a name equal to the target +local filename for a +.BR get +or +.BR mget +command, a ".1" is appended to the name. +If the resulting name matches another existing file, +a ".2" is appended to the original name. +If this process continues up to ".99", an error +message is printed, and the transfer does not take place. +The generated unique filename will be reported. +Note that +.BR runique +will not affect local files generated from a shell command +(see below). +The default value is off. +.IP "\fBsend\fR \fIlocal-file\fR [\fIremote-file\fR]" +A synonym for put. +.IP "\fBsendport\fR" +Toggle the use of PORT commands. +By default, +.BR ftp +will attempt to use a PORT command when establishing +a connection for each data transfer. +The use of PORT commands can prevent delays +when performing multiple file transfers. +If the PORT command fails, +.BR ftp +will use the default data port. +When the use of PORT commands is disabled, no attempt will be made to use +PORT commands for each data transfer. This is useful +for certain FTP implementations which do ignore PORT +commands but, incorrectly, indicate they've been accepted. +.IP "\fBsite\fR \fIarg1\fR \fIarg2\fR \fI...\fR" +The arguments specified are sent, verbatim, to the remote FTP +server as a SITE command. +.IP "\fBsize\fR \fIfile-name\fR" +Return size of +.IR file-name +on remote machine. +.IP \fBstatus\fR +Show the current status of +.BR ftp . +.IP "\fBstruct\fR [\fIstruct-name\fR]" +Set the file transfer +.IR structure +to +.IR struct-name . +By default \`stream\' structure is used. +.IP \fBsunique\fR +Toggle storing of files on remote machine under unique file names. +Remote ftp server must support ftp protocol STOU command for +successful completion. +The remote server will report unique name. +Default value is off. +.IP \fBsystem\fR +Show the type of operating system running on the remote machine. +.IP \fBtenex\fR +Set the file transfer type to that needed to +talk to TENEX machines. +.IP \fBtrace\fR +Toggle packet tracing. +.IP "\fBtype\fR [\fItype-name\fR]" +Set the file transfer +.BR type +to +.IR type-name . +If no type is specified, the current type +is printed. +The default type is network ASCII. +.IP "\fBumask\fR [\fInewmask\fR]" +Set the default umask on the remote server to +.IR newmask . +If +.IR newmask +is ommitted, the current umask is printed. +.IP "\fBuser\fR \fIuser-name\fR [\fIpassword\fR] [\fIaccount\fR]" +Identify yourself to the remote FTP +server. If the +.IR password +is not specified and the server requires it, +.BR ftp +will prompt the user for it (after disabling local echo). +If an +.IR account +field is not specified, and the FTP server +requires it, the user will be prompted for it. If an +.IR account +field is specified, an account command will +be relayed to the remote server after the login sequence +is completed if the remote server did not require it +for logging in. +Unless +.BR ftp +is invoked with \`auto-login\' disabled, this +process is done automatically on initial connection to +the FTP server. +.IP \fBverbose\fR +Toggle verbose mode. +In verbose mode, all responses from +the FTP +server are displayed to the user. +In addition, +if verbose is on, when a file transfer completes, statistics +regarding the efficiency of the transfer are reported. +By default, +verbose is on. +.IP "\fB\&?\fR [\fIcommand\fR]" +A synonym for help. +.LP +Command arguments which have embedded spaces may be quoted with +quote `"' marks. +.SH ABORTING A FILE TRANSFER +To abort a file transfer, use the terminal interrupt key +(usually Ctrl-C). +Sending transfers will be immediately halted. +Receiving transfers will be halted by sending a ftp protocol ABOR +command to the remote server, and discarding any further data received. +The speed at which this is accomplished depends upon the remote +server's support for ABOR processing. +If the remote server does not support the ABOR command, an +.BR "ftp>" +prompt will not appear until the remote server has completed +sending the requested file. +.LP +The terminal interrupt key sequence will be ignored when +.BR ftp +has completed any local processing and is awaiting a reply +from the remote server. +A long delay in this mode may result from the ABOR processing described +above, or from unexpected behavior by the remote server, including +violations of the ftp protocol. +If the delay results from unexpected remote server behavior, the local +.BR ftp +program must be killed by hand. +.SH "FILE NAMING CONVENTIONS" +Files specified as arguments to +.BR ftp +commands are processed according to the following rules. +.IP 1. +If the file name +.BR \- +is specified, the +.BR stdin +(for reading) or +.BR stdout +(for writing) is used. +.IP 2. +If the first character of the file name is +.BR \&| , +the remainder of the argument is interpreted as a shell command. +.BR Ftp +then forks a shell, using +.BR popen (3) +with the argument supplied, and reads (writes) from the stdout +(stdin). +If the shell command includes spaces, the argument +must be quoted; e.g. +\`" ls -lt"\'. +A particularly +useful example of this mechanism is: \`dir more\'. +.IP 3. +Failing the above checks, if ``globbing'' is enabled, +local file names are expanded +according to the rules used in the +.BR csh (1); +c.f. the +.BR glob +command. +If the +.BR ftp +command expects a single local file (.e.g. +.BR put ), +only the first filename generated by the "globbing" operation is used. +.IP 4. +For +.BR mget +commands and +.BR get +commands with unspecified local file names, the local filename is +the remote filename, which may be altered by a +.BR case , +.BR ntrans , +or +.BR nmap +setting. +The resulting filename may then be altered if +.BR runique +is on. +.IP 5. +For +.BR mput +commands and +.BR put +commands with unspecified remote file names, the remote filename is +the local filename, which may be altered by a +.BR ntrans +or +.BR nmap +setting. +The resulting filename may then be altered by the remote server if +.BR sunique +is on. +.SH "FILE TRANSFER PARAMETERS" +The FTP specification specifies many parameters which may +affect a file transfer. +The +.BR type +may be one of \`ascii\', \`image\' (binary), +\`ebcdic\', and \`local byte size\' (for PDP-10's and PDP-20's +mostly). +.BR Ftp +supports the ascii and image types of file transfer, +plus local byte size 8 for +.BR tenex +mode transfers. +.LP +.BR Ftp +supports only the default values for the remaining +file transfer parameters: +.BR mode , +.BR form , +and +.BR struct . +.SH "THE .netrc FILE" +The +.BR .netrc +file contains login and initialization information +used by the auto-login process. +It resides in the user's home directory. +The following tokens are recognized; they may be separated by spaces, +tabs, or new-lines: +.IP "\fBmachine\fR \fIname\fR" +Identify a remote machine +.IR name . +The auto-login process searches the +.IR .netrc +file for a +.BR machine +token that matches the remote machine specified on the +.BR ftp +command line or as an +.BR open +command argument. +Once a match is made, the subsequent +.IR .netrc +tokens are processed, +stopping when the end of file is reached or another +.BR machine +or a +.BR default +token is encountered. +.IP \fBdefault\fR +This is the same as +.BR machine +.IR name +except that +.BR default +matches any name. +There can be only one +.BR default +token, and it must be after all +.BR machine +tokens. +This is normally used as: +.nf + + default login anonymous password user@site + +.fi +thereby giving the user +.IR automatic +anonymous ftp login to +machines not specified in +.IR .netrc . +This can be overridden +by using the +.BR \-n +flag to disable auto-login. +.IP "\fBlogin\fR \fIname\fR" +Identify a user on the remote machine. +If this token is present, the auto-login process will initiate +a login using the specified +.BR name . +.IP "\fBpassword\fR \fIstring\fR" +Supply a password. +If this token is present, the auto-login process will supply the +specified string if the remote server requires a password as part +of the login process. +Note that if this token is present in the +.IR .netrc +file for any user other +than +.IR anonymous , +.BR ftp +will abort the auto-login process if the +.IR .netrc +is readable by +anyone besides the user. +.IP "\fBaccount\fR \fIstring\fR" +Supply an additional account password. +If this token is present, the auto-login process will supply the +specified string if the remote server requires an additional +account password, or the auto-login process will initiate an +ACCT command if it does not. +.IP "\fBmacdef\fR \fIname\fR" +Define a macro. +This token functions like the +.BR ftp +.BR macdef +command functions. +A macro is defined with the specified name; its contents begin with the +next +.IR .netrc +line and continue until a null line (consecutive new-line +characters) is encountered. +If a macro named +.BR init +is defined, it is automatically executed as the last step in the +auto-login process. +.SH ENVIRONMENT +.BR Ftp +utilizes the following environment variables. +.IP \fBHOME\fR +For default location of a +.IR .netrc +file, if one exists. +.IP \fBSHELL\fR +For default shell. +.SH SEE ALSO +.BR ftpd (8) +.SH HISTORY +The +.BR ftp +command appeared in 4.2BSD. +.SH BUGS +Correct execution of many commands depends upon proper behavior +by the remote server. +.LP +An error in the treatment of carriage returns in the 4.2BSD +ascii-mode transfer code has been corrected. +This correction may result in incorrect transfers of binary files +to and from 4.2BSD servers using the ascii type. +Avoid this problem by using the binary image type. diff --git a/bin/ftp/ftp.c b/bin/ftp/ftp.c new file mode 100644 index 0000000..242f167 --- /dev/null +++ b/bin/ftp/ftp.c @@ -0,0 +1,1405 @@ +#ifdef __ORCAC__ +segment "ftpftp1 "; +#endif + +static char sccsid[] = "@(#)ftp.c 5.38 (Berkeley) 4/22/91"; + +#ifdef __GNO__ +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include + +#ifndef __GNO__ +#include +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "ftp.var.h" +#include "cmds.h" +#include "main.h" +#include "domacro.h" +#include "ruserpass.h" +#include "ftp.h" + +struct sockaddr_in hisctladdr; +struct sockaddr_in data_addr; +int data = -1; +int abrtflag = 0; +int ptflag = 0; +struct sockaddr_in myctladdr; +off_t restart_point = 0; + +#ifndef __GNO__ +extern int connected, errno; +#endif + +FILE *cin, *cout; + +char *hookup (char *host, int port) +{ +struct hostent *hp = 0; +int s, len, tos; +static char hostnamebuf[80]; + + bzero((char *)&hisctladdr, sizeof (hisctladdr)); + hisctladdr.sin_addr.s_addr = inet_addr(host); + if (hisctladdr.sin_addr.s_addr != -1) { + hisctladdr.sin_family = AF_INET; + strncpy(hostnamebuf, host, sizeof(hostnamebuf)); + } else { + hp = gethostbyname(host); + if (hp == NULL) { + fprintf(stderr, "ftp: %s: ", host); + perror ("gethostbyname"); + code = -1; + return((char *) 0); + } + hisctladdr.sin_family = hp->h_addrtype; + bcopy(hp->h_addr_list[0], + (caddr_t)&hisctladdr.sin_addr, hp->h_length); + strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf)); + } + hostname = hostnamebuf; + s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); + if (s < 0) { + perror("ftp: socket"); + code = -1; + return (0); + } + hisctladdr.sin_port = port; + while (connect(s, (struct __SOCKADDR *)&hisctladdr, sizeof (hisctladdr)) < 0) { + if (hp && hp->h_addr_list[1]) { + int oerrno = errno; + + fprintf(stderr, "ftp: connect to address %s: ", + inet_ntoa(hisctladdr.sin_addr)); + errno = oerrno; + perror((char *) 0); + hp->h_addr_list++; + bcopy(hp->h_addr_list[0], + (caddr_t)&hisctladdr.sin_addr, hp->h_length); + fprintf(stdout, "Trying %s...\n", + inet_ntoa(hisctladdr.sin_addr)); + close(s); + s = socket(hisctladdr.sin_family, SOCK_STREAM, 0); + if (s < 0) { + perror("ftp: socket"); + code = -1; + return (0); + } + continue; + } + perror("ftp: connect"); + code = -1; + goto bad; + } + len = sizeof (myctladdr); + if (getsockname(s, (struct __SOCKADDR *)&myctladdr, &len) < 0) { + perror("ftp: getsockname"); + code = -1; + goto bad; + } + cin = fdopen(s, "rb"); + cout = fdopen(s, "wb"); + if (cin == NULL || cout == NULL) { + fprintf(stderr, "ftp: fdopen failed.\n"); + if (cin) + fclose(cin); + if (cout) + fclose(cout); + code = -1; + goto bad; + } + if (verbose) + printf("Connected to %s.\n", hostname); + if (getreply(0) > 2) { /* read startup message from server */ + if (cin) + fclose(cin); + if (cout) + fclose(cout); + code = -1; + goto bad; + } + + return (hostname); +bad: + close(s); + return ((char *)0); +} + +char *getlogin (void) +{ + return (getenv ("USER")); +} + +int login (char *host) +{ +static char tmp[80]; +char *user, *pass, *acct; +int n, aflag = 0; + + user = pass = acct = 0; + if (ruserpass(host, &user, &pass, &acct) < 0) { + code = -1; + return(0); + } + while (user == NULL) { + char *myname = getlogin(); + + if (myname == NULL) { + struct passwd *pp = getpwuid(getuid()); + + if (pp != NULL) + myname = pp->pw_name; + } + if (myname) + printf("Name (%s:%s): ", host, myname); + else + printf("Name (%s): ", host); + fgets(tmp, sizeof(tmp) - 1, stdin); + tmp[strlen(tmp) - 1] = '\0'; + if (*tmp == '\0') + user = myname; + else + user = tmp; + } + n = command("USER %s", user); + if (n == CONTINUE) { + if (pass == NULL) + pass = getpass("Password:"); + n = command("PASS %s", pass); + } + if (n == CONTINUE) { + aflag++; + acct = getpass("Account:"); + n = command("ACCT %s", acct); + } + if (n != COMPLETE) { + fprintf(stderr, "Login failed.\n"); + return (0); + } + if (!aflag && acct != NULL) + command("ACCT %s", acct); + if (proxy) + return(1); + for (n = 0; n < macnum; ++n) { + if (!strcmp("init", macros[n].mac_name)) { + strcpy(line, "$init"); + makeargv(); + domacro(margc, margv); + break; + } + } + return (1); +} + +#pragma databank 1 +void cmdabort (int sig, int code) +{ +extern jmp_buf ptabort; + + printf("\n"); + fflush(stdout); + abrtflag++; + if (ptflag) + longjmp(ptabort, 1); +} +#pragma databank 0 + +#pragma debug 0 +/* assume at least #pragma optimize 8 */ +/*VARARGS*/ +int command (char *string, ...) +{ +va_list ap; +char *fmt; +static char buf[255]; +int r; +sig_t oldintr; + + abrtflag = 0; + if (cout == NULL) + { + perror ("No control connection for command"); + code = -1; + return (0); + } + oldintr = signal (SIGINT, cmdabort); + va_start (ap, string); + vsprintf (buf, string, ap); + va_end(ap); + if (debug) { + printf("---> "); + if (strncmp("PASS ", buf, 5) == 0) + printf("PASS XXXX\n"); + else + printf("%s\n", buf); + fflush(stdout); + } + fprintf (cout, "%s\r\n", buf); + fflush(cout); + cpend = 1; + r = getreply(!strncmp(string, "QUIT", 4)); + if (abrtflag && oldintr != SIG_IGN) + (*oldintr)(SIGINT, 0); + signal(SIGINT, oldintr); + + return(r); +} +/* find some way to put #pragma options back */ + +char reply_string[BUFSIZ]; /* last line of previous reply */ + +#include + +int getreply (int expecteof) +{ +int c, n; +int dig; +char *cp; +int originalcode = 0, continuation = 0; +sig_t oldintr; +int pflag = 0; +char *pt = pasv; + + oldintr = signal (SIGINT, cmdabort); + for (;;) { + dig = n = code = 0; + cp = reply_string; + while ((c = getc(cin)) != '\n') { + if (c == IAC) { /* handle telnet commands */ + switch (c = getc(cin)) { + case WILL: + case WONT: + c = getc(cin); + fprintf(cout, "%c%c%c", IAC, DONT, c); + fflush(cout); + break; + case DO: + case DONT: + c = getc(cin); + fprintf(cout, "%c%c%c", IAC, WONT, c); + fflush(cout); + break; + default: + break; + } + continue; + } + dig++; + if (c == EOF) { + if (expecteof) { + signal(SIGINT,oldintr); + code = 221; + return (0); + } + lostpeer(0,0); + if (verbose) { + printf("421 Service not available, remote server has closed connection\n"); + fflush(stdout); + } + code = 421; + return(4); + } + if (c != '\r' && (verbose > 0 || + (verbose > -1 && n == '5' && dig > 4))) { + if (proxflag && + (dig == 1 || dig == 5 && verbose == 0)) + printf("%s:",hostname); + putchar(c); + } + if (dig < 4 && isdigit(c)) + code = code * 10 + (c - '0'); + if (!pflag && code == 227) + pflag = 1; + if (dig > 4 && pflag == 1 && isdigit(c)) + pflag = 2; + if (pflag == 2) { + if (c != '\r' && c != ')') + *pt++ = c; + else { + *pt = '\0'; + pflag = 3; + } + } + if (dig == 4 && c == '-') { + if (continuation) + code = 0; + continuation++; + } + if (n == 0) + n = c; + if (cp < &reply_string[sizeof(reply_string) - 1]) + *cp++ = c; + } + if (verbose > 0 || verbose > -1 && n == '5') { + putchar(c); + fflush (stdout); + } + if (continuation && code != originalcode) { + if (originalcode == 0) + originalcode = code; + continue; + } + cp[0] = '\0'; + if (n != '1') + cpend = 0; + signal(SIGINT,oldintr); + if (code == 421 || originalcode == 421) + lostpeer(0,0); + if (abrtflag && oldintr != cmdabort && oldintr != SIG_IGN) + (*oldintr)(SIGINT, 0); + return (n - '0'); + } +} + +int empty (struct fd_set *mask, int sec) +{ +struct timeval t; + + t.tv_sec = (long) sec; + t.tv_usec = 0; + return(select(32, mask, (struct fd_set *) 0, (struct fd_set *) 0, &t)); +} + +jmp_buf sendabort; + +#pragma databank 1 +void abortsend (int sig, int code) +{ + mflag = 0; + abrtflag = 0; + printf("\nsend aborted\nwaiting for remote to finish abort\n"); + fflush(stdout); + longjmp(sendabort, 1); +} +#pragma databank 0 + +#define HASHBYTES 1024 + +void sendrequest (char *cmd, char *local, char *remote, int printnames) +{ +struct stat st; +struct timeval start, stop; +int c, d; +FILE *fin, *dout = 0; +sig_t oldintr, oldintp; +long bytes = 0, hashbytes = HASHBYTES; +char *lmode, *bufp; +static char buf[BUFSIZ]; +int (*closefunc)(FILE *); + + if (verbose && printnames) { + if (local && *local != '-') + printf("local: %s ", local); + if (remote) + printf("remote: %s\n", remote); + } + if (proxy) { + proxtrans(cmd, local, remote); + return; + } + if (curtype != type) + changetype(type, 0); + closefunc = NULL; + oldintr = NULL; + oldintp = NULL; + lmode = "wb"; + if (setjmp(sendabort)) { + while (cpend) { + getreply(0); + } + if (data >= 0) { + close(data); + data = -1; + } + if (oldintr) + signal(SIGINT,oldintr); + if (oldintp) + signal(SIGPIPE,oldintp); + code = -1; + return; + } + oldintr = signal(SIGINT, abortsend); + if (strcmp(local, "-") == 0) + fin = stdin; + else if (*local == '|') { + oldintp = signal(SIGPIPE,SIG_IGN); + fin = popen(local + 1, "r"); + if (fin == NULL) { + perror(local + 1); + signal(SIGINT, oldintr); + signal(SIGPIPE, oldintp); + code = -1; + return; + } + closefunc = pclose; + } else { + switch (curtype) { + case TYPE_I: + case TYPE_L: + fin = fopen(local, "rb"); + break; + case TYPE_A: + fin = fopen(local, "r"); + break; + default: /* shouldn't ever happen */ + fin = NULL; + break; + } + if (fin == NULL) { + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + signal(SIGINT, oldintr); + code = -1; + return; + } + closefunc = fclose; + if (fstat(fileno(fin), &st) < 0 || + (st.st_mode&S_IFMT) != S_IFREG) { + fprintf(stdout, "%s: not a plain file.\n", local); + signal(SIGINT, oldintr); + fclose(fin); + code = -1; + return; + } + } + if (initconn()) { + signal(SIGINT, oldintr); + if (oldintp) + signal(SIGPIPE, oldintp); + code = -1; + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + if (setjmp(sendabort)) + goto abort; + + if (restart_point && + (strcmp(cmd, "STOR") == 0 || strcmp(cmd, "APPE") == 0)) { + if (fseek(fin, (long) restart_point, 0) < 0) { + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + restart_point = 0; + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + if (command("REST %ld", (long) restart_point) + != CONTINUE) { + restart_point = 0; + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + restart_point = 0; + lmode = "r+wb"; + } + if (remote) { + if (command("%s %s", cmd, remote) != PRELIM) { + signal(SIGINT, oldintr); + if (oldintp) + signal(SIGPIPE, oldintp); + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + } else + if (command("%s", cmd) != PRELIM) { + signal(SIGINT, oldintr); + if (oldintp) + signal(SIGPIPE, oldintp); + if (closefunc != NULL) + (*closefunc)(fin); + return; + } + dout = dataconn(lmode); + if (dout == NULL) + goto abort; + gettimeofday(&start, (struct timezone *)0); + oldintp = signal(SIGPIPE, SIG_IGN); + switch (curtype) { + + case TYPE_I: + case TYPE_L: + errno = d = 0; + while ((c = read(fileno(fin), buf, sizeof (buf))) > 0) { + bytes += c; + for (bufp = buf; c > 0; c -= d, bufp += d) + if ((d = write(fileno(dout), bufp, c)) <= 0) + break; + if (hash) { + while (bytes >= hashbytes) { + putchar('#'); + hashbytes += HASHBYTES; + } + fflush(stdout); + } + } + if (hash && bytes > 0) { + if (bytes < HASHBYTES) + putchar('#'); + putchar('\n'); + fflush(stdout); + } + if (c < 0) + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + if (d < 0) { + if (errno != EPIPE) + perror("netout"); + bytes = -1; + } + break; + + case TYPE_A: + while ((c = getc(fin)) != EOF) { + if (c == '\n') { + while (hash && (bytes >= hashbytes)) { + putchar('#'); + fflush(stdout); + hashbytes += HASHBYTES; + } + if (ferror(dout)) + break; + putc('\r', dout); + bytes++; + } + putc(c, dout); + bytes++; + /* if (c == '\r') { */ + /* (void) putc('\0', dout); /* this violates rfc */ + /* bytes++; */ + /* } */ + } + if (hash) { + if (bytes < hashbytes) + putchar('#'); + putchar('\n'); + fflush(stdout); + } + if (ferror(fin)) + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + if (ferror(dout)) { + if (errno != EPIPE) + perror("netout"); + bytes = -1; + } + break; + } + gettimeofday(&stop, (struct timezone *)0); + if (closefunc != NULL) + (*closefunc)(fin); + fclose(dout); + getreply(0); + signal(SIGINT, oldintr); + if (oldintp) + signal(SIGPIPE, oldintp); + if (bytes > 0) + ptransfer("sent", bytes, &start, &stop); + return; +abort: + gettimeofday(&stop, (struct timezone *)0); + signal(SIGINT, oldintr); + if (oldintp) + signal(SIGPIPE, oldintp); + if (!cpend) { + code = -1; + return; + } + if (data >= 0) { + close(data); + data = -1; + } + if (dout) + fclose(dout); + getreply(0); + code = -1; + if (closefunc != NULL && fin != NULL) + (*closefunc)(fin); + if (bytes > 0) + ptransfer("sent", bytes, &start, &stop); +} + +segment "ftpftp2 "; + +jmp_buf recvabort; + +#pragma databank 1 +void abortrecv (int sig, int code) +{ + mflag = 0; + abrtflag = 0; + printf("\nreceive aborted\nwaiting for remote to finish abort\n"); + fflush(stdout); + longjmp(recvabort, 1); +} +#pragma databank 0 + +void recvrequest (char *cmd, char *local, char *remote, char *lmode, int printnames) +{ +FILE *fout, *din = 0; +sig_t oldintr, oldintp; +int is_retr, tcrflag, bare_lfs = 0; +static int bufsize; +static char *buf; +long bytes = 0, hashbytes = HASHBYTES; +int c, d; +struct timeval start, stop; +struct stat st; +int (*closefunc)(FILE *); + + is_retr = strcmp(cmd, "RETR") == 0; + if (is_retr && verbose && printnames) { + if (local && *local != '-') + printf("local: %s ", local); + if (remote) + printf("remote: %s\n", remote); + } + if (proxy && is_retr) { + proxtrans(cmd, local, remote); + return; + } + closefunc = NULL; + oldintr = NULL; + oldintp = NULL; + tcrflag = !crflag && is_retr; + if (setjmp(recvabort)) { + while (cpend) { + getreply(0); + } + if (data >= 0) { + close(data); + data = -1; + } + if (oldintr) + signal(SIGINT, oldintr); + code = -1; + return; + } + oldintr = signal(SIGINT, abortrecv); + if (strcmp(local, "-") && *local != '|') { + if (access(local, 2) < 0) { + char *dir; + + if (errno != ENOENT && errno != EACCES) { + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + signal(SIGINT, oldintr); + code = -1; + return; + } + dir = rindex(local, (int) '/'); + if (dir != NULL) + *dir = 0; + d = access(dir ? local : ".", 2); + if (dir != NULL) + *dir = '/'; + if (d < 0) { + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + signal(SIGINT, oldintr); + code = -1; + return; + } + if (!runique && errno == EACCES && + chmod(local, 0600) < 0) { + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + signal(SIGINT, oldintr); + signal(SIGINT, oldintr); + code = -1; + return; + } + if (runique && errno == EACCES && + (local = gunique(local)) == NULL) { + signal(SIGINT, oldintr); + code = -1; + return; + } + } + else if (runique && (local = gunique(local)) == NULL) { + signal(SIGINT, oldintr); + code = -1; + return; + } + } + if (!is_retr) { + if (curtype != TYPE_A) + changetype(TYPE_A, 0); + } else if (curtype != type) + changetype(type, 0); + if (initconn()) { + signal(SIGINT, oldintr); + code = -1; + return; + } + if (setjmp(recvabort)) + goto abort; + if (is_retr && restart_point && + command("REST %ld", (long) restart_point) != CONTINUE) + return; + if (remote) { + if (command("%s %s", cmd, remote) != PRELIM) { + signal(SIGINT, oldintr); + return; + } + } else { + if (command("%s", cmd) != PRELIM) { + signal(SIGINT, oldintr); + return; + } + } + din = dataconn("rb"); + if (din == NULL) + goto abort; + if (strcmp(local, "-") == 0) + fout = stdout; + else if (*local == '|') { + oldintp = signal(SIGPIPE, SIG_IGN); + fout = popen(local + 1, "w"); + if (fout == NULL) { + perror(local+1); + goto abort; + } + closefunc = pclose; + } else { + fout = fopen(local, lmode); + if (fout == NULL) { + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + goto abort; + } + closefunc = fclose; + } + if (fstat(fileno(fout), &st) < 0 || st.st_blksize == 0) + st.st_blksize = BUFSIZ; + if (st.st_blksize > bufsize) { + if (buf) + free(buf); + buf = malloc((unsigned)st.st_blksize); + if (buf == NULL) { + perror("malloc"); + bufsize = 0; + goto abort; + } + bufsize = st.st_blksize; + } + gettimeofday(&start, (struct timezone *)0); + switch (curtype) { + + case TYPE_I: + case TYPE_L: + if (restart_point && + lseek(fileno(fout), (long) restart_point, L_SET) < 0) { + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + if (closefunc != NULL) + (*closefunc)(fout); + return; + } + errno = d = 0; + while ((c = read(fileno(din), buf, bufsize)) > 0) { + if ((d = write(fileno(fout), buf, c)) != c) + break; + bytes += c; + if (hash) { + while (bytes >= hashbytes) { + putchar('#'); + hashbytes += HASHBYTES; + } + fflush(stdout); + } + } + if (hash && bytes > 0) { + if (bytes < HASHBYTES) + putchar('#'); + putchar('\n'); + fflush(stdout); + } + if (c < 0) { + if (errno != EPIPE) + perror("netin"); + bytes = -1; + } + if (d < c) { + if (d < 0) + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + else + fprintf(stderr, "%s: short write\n", local); + } + break; + + case TYPE_A: + if (restart_point) { + int i, n, ch; + + if (fseek(fout, 0L, L_SET) < 0) + goto done; + n = restart_point; + for (i = 0; i++ < n;) { + if ((ch = getc(fout)) == EOF) + goto done; + if (ch == '\n') + i++; + } + if (fseek(fout, 0L, L_INCR) < 0) { +done: + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + if (closefunc != NULL) + (*closefunc)(fout); + return; + } + } + while ((c = getc(din)) != EOF) { + if (c == '\n') + bare_lfs++; + while (c == '\r') { + while (hash && (bytes >= hashbytes)) { + putchar('#'); + fflush(stdout); + hashbytes += HASHBYTES; + } + bytes++; + if ((c = getc(din)) != '\n' || tcrflag) { + if (ferror(fout)) + goto break2; + putc('\r', fout); + if (c == '\0') { + bytes++; + goto contin2; + } + if (c == EOF) + goto contin2; + } + } + putc(c, fout); + bytes++; + contin2: ; + } +break2: + if (bare_lfs) { + printf("WARNING! %d bare linefeeds received in ASCII mode\n", bare_lfs); + printf("File may not have transferred correctly.\n"); + } + if (hash) { + if (bytes < hashbytes) + putchar('#'); + putchar('\n'); + fflush(stdout); + } + if (ferror(din)) { + if (errno != EPIPE) + perror("netin"); + bytes = -1; + } + if (ferror(fout)) + fprintf(stderr, "local: %s: %s\n", local, + strerror(errno)); + break; + } + if (closefunc != NULL) + (*closefunc)(fout); + signal(SIGINT, oldintr); + if (oldintp) + signal(SIGPIPE, oldintp); + gettimeofday(&stop, (struct timezone *)0); + fclose(din); + getreply(0); + if (bytes > 0 && is_retr) + ptransfer("received", bytes, &start, &stop); + return; +abort: + +/* abort using RFC959 recommended IP,SYNC sequence */ + gettimeofday(&stop, (struct timezone *)0); + if (oldintp) + signal(SIGPIPE, oldintr); + signal(SIGINT, SIG_IGN); + if (!cpend) { + code = -1; + signal(SIGINT, oldintr); + return; + } + + abort_remote(din); + code = -1; + if (data >= 0) { + close(data); + data = -1; + } + if (closefunc != NULL && fout != NULL) + (*closefunc)(fout); + if (din) + fclose(din); + if (bytes > 0) + ptransfer("received", bytes, &start, &stop); + signal(SIGINT, oldintr); +} + +/* + * Need to start a listen on the data channel before we send the command, + * otherwise the server's connect may fail. + */ +int initconn (void) +{ +unsigned char *p, *a; +int result, len, tmpno = 0; +int on = 1; + +noport: + data_addr = myctladdr; + if (sendport) + data_addr.sin_port = 0; /* let system pick one */ + if (data != -1) + close(data); + data = socket(AF_INET, SOCK_STREAM, 0); + if (data < 0) { + perror("ftp: socket"); + if (tmpno) + sendport = 1; + return (1); + } + + if (!sendport) + if (setsockopt(data, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { + perror("ftp: setsockopt (reuse address)"); + goto bad; + } + + if (bind(data, (struct __SOCKADDR *)&data_addr, sizeof (data_addr)) < 0) { + perror("ftp: bind"); + goto bad; + } + + if (options & SO_DEBUG && setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on, sizeof (on)) < 0) + perror("ftp: setsockopt (ignored)"); + + len = sizeof (data_addr); + + if (getsockname(data, (struct __SOCKADDR *)&data_addr, &len) < 0) { + perror("ftp: getsockname"); + goto bad; + } + + if (listen(data, 1) < 0) + perror("ftp: listen"); + if (sendport) { + a = (unsigned char *)&data_addr.sin_addr; + p = (unsigned char *)&data_addr.sin_port; +#define UC(b) (((unsigned int)b)&0xff) + result = + command("PORT %d,%d,%d,%d,%d,%d", + UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), + UC(p[0]), UC(p[1])); + if (result == ERROR && sendport == -1) { + sendport = 0; + tmpno = 1; + goto noport; + } + return (result != COMPLETE); + } + if (tmpno) + sendport = 1; + return (0); +bad: + close(data), data = -1; + if (tmpno) + sendport = 1; + return (1); +} + +FILE *dataconn (char *lmode) +{ +struct sockaddr_in from; +int s, fromlen = sizeof (from), tos; + + s = accept(data, (struct __SOCKADDR *) &from, &fromlen); + if (s < 0) { + perror("ftp: accept"); + close(data), data = -1; + return (NULL); + } + close(data); + data = s; + return (fdopen(data, lmode)); +} + +void ptransfer(char *direction, long bytes, struct timeval *t0, struct timeval *t1) +{ +struct timeval td; +float s, bs; + + if (verbose) { + tvsub(&td, t1, t0); + s = td.tv_sec + (td.tv_usec / 1000000.); +#define nz(x) ((x) == 0 ? 1. : (x)) + bs = bytes / nz(s); + printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n", + bytes, direction, s, bs / 1024.); + } +} + +void tvadd (struct timeval *tsum, struct timeval *t0) +{ + tsum->tv_sec += t0->tv_sec; + tsum->tv_usec += t0->tv_usec; + if (tsum->tv_usec > 1000000) + tsum->tv_sec++, tsum->tv_usec -= 1000000; +} + +void tvsub (struct timeval *tdiff, struct timeval *t1, struct timeval *t0) +{ + tdiff->tv_sec = t1->tv_sec - t0->tv_sec; + tdiff->tv_usec = t1->tv_usec - t0->tv_usec; + if (tdiff->tv_usec < 0) + tdiff->tv_sec--, tdiff->tv_usec += 1000000; +} + +#pragma databank 1 +void psabort (int sig, int code) +{ +extern int abrtflag; + + abrtflag++; +} +#pragma databank 0 + +void pswitch (int flag) +{ +extern int proxy, abrtflag; +sig_t oldintr; +static struct comvars { + int connect; + char name[MAXHOSTNAMELEN]; + struct sockaddr_in mctl; + struct sockaddr_in hctl; + FILE *in; + FILE *out; + int tpe; + int curtpe; + int cpnd; + int sunqe; + int runqe; + int mcse; + int ntflg; + char nti[17]; + char nto[17]; + int mapflg; + char mi[MAXPATHLEN]; + char mo[MAXPATHLEN]; +} proxstruct, tmpstruct; +struct comvars *ip, *op; + + abrtflag = 0; + oldintr = signal(SIGINT, psabort); + if (flag) { + if (proxy) + return; + ip = &tmpstruct; + op = &proxstruct; + proxy++; + } else { + if (!proxy) + return; + ip = &proxstruct; + op = &tmpstruct; + proxy = 0; + } + ip->connect = connected; + connected = op->connect; + if (hostname) { + strncpy(ip->name, hostname, sizeof(ip->name) - 1); + ip->name[strlen(ip->name)] = '\0'; + } else + ip->name[0] = 0; + hostname = op->name; + ip->hctl = hisctladdr; + hisctladdr = op->hctl; + ip->mctl = myctladdr; + myctladdr = op->mctl; + ip->in = cin; + cin = op->in; + ip->out = cout; + cout = op->out; + ip->tpe = type; + type = op->tpe; + ip->curtpe = curtype; + curtype = op->curtpe; + ip->cpnd = cpend; + cpend = op->cpnd; + ip->sunqe = sunique; + sunique = op->sunqe; + ip->runqe = runique; + runique = op->runqe; + ip->mcse = mcase; + mcase = op->mcse; + ip->ntflg = ntflag; + ntflag = op->ntflg; + strncpy(ip->nti, ntin, 16); + (ip->nti)[strlen(ip->nti)] = '\0'; + strcpy(ntin, op->nti); + strncpy(ip->nto, ntout, 16); + (ip->nto)[strlen(ip->nto)] = '\0'; + strcpy(ntout, op->nto); + ip->mapflg = mapflag; + mapflag = op->mapflg; + strncpy(ip->mi, mapin, MAXPATHLEN - 1); + (ip->mi)[strlen(ip->mi)] = '\0'; + strcpy(mapin, op->mi); + strncpy(ip->mo, mapout, MAXPATHLEN - 1); + (ip->mo)[strlen(ip->mo)] = '\0'; + strcpy(mapout, op->mo); + signal(SIGINT, oldintr); + if (abrtflag) { + abrtflag = 0; + (*oldintr)(SIGINT, 0); + } +} + +jmp_buf ptabort; +int ptabflg; + +#pragma databank 1 +void abortpt (int sig, int code) +{ + printf("\n"); + fflush(stdout); + ptabflg++; + mflag = 0; + abrtflag = 0; + longjmp(ptabort, 1); +} +#pragma databank 0 + +void proxtrans (char *cmd, char *local, char *remote) +{ +sig_t oldintr; +int secndflag = 0, prox_type, nfnd; +extern jmp_buf ptabort; +char *cmd2; +struct fd_set mask; +void abortpt (int sig, int code); + + if (strcmp(cmd, "RETR")) + cmd2 = "RETR"; + else + cmd2 = runique ? "STOU" : "STOR"; + if ((prox_type = type) == 0) { + if (unix_server && unix_proxy) + prox_type = TYPE_I; + else + prox_type = TYPE_A; + } + if (curtype != prox_type) + changetype(prox_type, 1); + if (command("PASV") != COMPLETE) { + printf("proxy server does not support third party transfers.\n"); + return; + } + pswitch(0); + if (!connected) { + printf("No primary connection\n"); + pswitch(1); + code = -1; + return; + } + if (curtype != prox_type) + changetype(prox_type, 1); + if (command("PORT %s", pasv) != COMPLETE) { + pswitch(1); + return; + } + if (setjmp(ptabort)) + goto abort; + oldintr = signal(SIGINT, abortpt); + if (command("%s %s", cmd, remote) != PRELIM) { + signal(SIGINT, oldintr); + pswitch(1); + return; + } + sleep(2); + pswitch(1); + secndflag++; + if (command("%s %s", cmd2, local) != PRELIM) + goto abort; + ptflag++; + getreply(0); + pswitch(0); + getreply(0); + signal(SIGINT, oldintr); + pswitch(1); + ptflag = 0; + printf("local: %s remote: %s\n", local, remote); + return; +abort: + signal(SIGINT, SIG_IGN); + ptflag = 0; + if (strcmp(cmd, "RETR") && !proxy) + pswitch(1); + else if (!strcmp(cmd, "RETR") && proxy) + pswitch(0); + if (!cpend && !secndflag) { /* only here if cmd = "STOR" (proxy=1) */ + if (command("%s %s", cmd2, local) != PRELIM) { + pswitch(0); + if (cpend) + abort_remote((FILE *) NULL); + } + pswitch(1); + if (ptabflg) + code = -1; + signal(SIGINT, oldintr); + return; + } + if (cpend) + abort_remote((FILE *) NULL); + pswitch(!proxy); + if (!cpend && !secndflag) { /* only if cmd = "RETR" (proxy=1) */ + if (command("%s %s", cmd2, local) != PRELIM) { + pswitch(0); + if (cpend) + abort_remote((FILE *) NULL); + pswitch(1); + if (ptabflg) + code = -1; + signal(SIGINT, oldintr); + return; + } + } + if (cpend) + abort_remote((FILE *) NULL); + pswitch(!proxy); + if (cpend) { + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if ((nfnd = empty(&mask, 10)) <= 0) { + if (nfnd < 0) { + perror("abort"); + } + if (ptabflg) + code = -1; + lostpeer(0,0); + } + getreply(0); + getreply(0); + } + if (proxy) + pswitch(0); + pswitch(1); + if (ptabflg) + code = -1; + signal(SIGINT, oldintr); +} + +char *gunique (char *local) +{ +static char new[MAXPATHLEN]; +char *cp; +int d, count=0; +char ext = '1'; + + cp = rindex(local, (int) '/'); + + if (cp) + *cp = '\0'; + d = access(cp ? local : ".", 2); + if (cp) + *cp = '/'; + if (d < 0) { + fprintf(stderr, "local: %s: %s\n", local, strerror(errno)); + return((char *) 0); + } + strcpy(new, local); + cp = new + strlen(new); + *cp++ = '.'; + while (!d) { + if (++count == 100) { + printf("runique: can't find unique file name.\n"); + return((char *) 0); + } + *cp++ = ext; + *cp = '\0'; + if (ext == '9') + ext = '0'; + else + ext++; + if ((d = access(new, 0)) < 0) + break; + if (ext != '0') + cp--; + else if (*(cp - 2) == '.') + *(cp - 1) = '1'; + else { + *(cp - 2) = *(cp - 2) + 1; + cp--; + } + } + return(new); +} + +void abort_remote (FILE *din) +{ +static char buf[BUFSIZ]; +int nfnd; +struct fd_set mask; + + /* + * send IAC in urgent mode instead of DM because 4.3BSD places oob mark + * after urgent byte rather than before as is protocol now + */ + sprintf(buf, "%c%c%c", IAC, IP, IAC); + if (send(fileno(cout), buf, 3, MSG_OOB) != 3) + perror("abort"); + fprintf(cout,"%cABOR\n", DM); + fflush(cout); + FD_ZERO(&mask); + FD_SET(fileno(cin), &mask); + if (din) { + FD_SET(fileno(din), &mask); + } + if ((nfnd = empty(&mask, 10)) <= 0) { + if (nfnd < 0) { + perror("abort"); + } + if (ptabflg) + code = -1; + lostpeer(0,0); + } + if (din && FD_ISSET(fileno(din), &mask)) { + while (read(fileno(din), buf, BUFSIZ) > 0) + /* LOOP */; + } + if (getreply(0) == ERROR && code == 552) { + /* 552 needed for nic style abort */ + getreply(0); + } + getreply(0); +} diff --git a/bin/ftp/ftp.desc b/bin/ftp/ftp.desc new file mode 100644 index 0000000..b49c25d --- /dev/null +++ b/bin/ftp/ftp.desc @@ -0,0 +1,9 @@ +Name: ftp +Version: 1.0 (October 1997) +Shell: GNO & GS/TCP +Author: Derek Taubert (from BSDi code) +Contact: taubert@geeks.org +Where: /usr/bin +FTP: ground.icaen.uiowa.edu apple2.caltech.edu ftp.gno.org + + File transfer program. diff --git a/bin/ftp/ftp.h b/bin/ftp/ftp.h new file mode 100644 index 0000000..908f143 --- /dev/null +++ b/bin/ftp/ftp.h @@ -0,0 +1,21 @@ +char *hookup (char *host, int port); +char *getlogin (void); +int login (char *host); +void cmdabort (int sig, int code); +int command (char *string, ...); +int getreply (int expecteof); +int empty (struct fd_set *mask, int sec); +void abortsend (int sig, int code); +void sendrequest (char *cmd, char *local, char *remote, int printnames); +void abortrecv (int sig, int code); +void recvrequest (char *cmd, char *local, char *remote, char *lmode, int printnames); +int initconn (void); +FILE *dataconn (char *lmode); +void ptransfer (char *direction, long bytes, struct timeval *t0, struct timeval *t1); +void tvsub (struct timeval *tdiff, struct timeval *t1, struct timeval *t0); +void psabort (int sig, int code); +void pswitch (int flag); +void abortpt (int sig, int code); +void proxtrans (char *cmd, char *local, char *remote); +char *gunique (char *local); +void abort_remote (FILE *din); diff --git a/bin/ftp/ftp.rez b/bin/ftp/ftp.rez new file mode 100644 index 0000000..e46ea0f --- /dev/null +++ b/bin/ftp/ftp.rez @@ -0,0 +1,31 @@ +/* + * Resources for ftp version and comment + * + * $Id: ftp.rez 395 1998-01-24 08:21:33Z taubert $ + */ +#define PROG "ftp" +#define DESC "File transfer program." + +#include "Types.rez" + +/* + * Version + */ +resource rVersion (1, purgeable3) { + { 1, 0, 0, /* Version 1.0.0 */ + release, /* development|alpha|beta|final|release */ + 0 }, /* non-final release number */ + verUS, /* Country */ + PROG, /* Program name */ + DESC " Released with GNO/ME and GS/TCP." +}; + + +/* + * Comment + */ +resource rComment (1, purgeable3) { + PROG " v1.0 (October 1997)\n" + "GNO utility: " DESC "\n" + "Ported from BSDi code by Derek Taubert." +}; diff --git a/bin/ftp/ftp.var.h b/bin/ftp/ftp.var.h new file mode 100644 index 0000000..957a2a9 --- /dev/null +++ b/bin/ftp/ftp.var.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 1985, 1989 Regents of the University of California. + * All rights reserved. + * + * 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. + * + * @(#)ftp_var.h 5.9 (Berkeley) 6/1/90 + */ + +/* + * FTP global variables. + */ + +/* + * Options and other state info. + */ +extern int trace; /* trace packets exchanged */ +extern int hash; /* print # for each buffer transferred */ +extern int sendport; /* use PORT cmd for each data connection */ +extern int verbose; /* print messages coming back from server */ +extern int connected; /* connected to server */ +extern int fromatty; /* input is from a terminal */ +extern int interactive; /* interactively prompt on m* cmds */ +extern int debug; /* debugging level */ +extern int bell; /* ring bell on cmd completion */ +extern int doglob; /* glob local file names */ +extern int autologin; /* establish user account on connection */ +extern int proxy; /* proxy server connection active */ +extern int proxflag; /* proxy connection exists */ +extern int sunique; /* store files on server with unique name */ +extern int runique; /* store local files with unique name */ +extern int mcase; /* map upper to lower case for mget names */ +extern int ntflag; /* use ntin ntout tables for name translation */ +extern int mapflag; /* use mapin mapout templates on file names */ +extern int code; /* return/reply code for ftp command */ +extern int crflag; /* if 1, strip car. rets. on ascii gets */ +extern char pasv[64]; /* passive port for proxy data connection */ +extern char *altarg; /* argv[1] with no shell-like preprocessing */ +extern char ntin[17]; /* input translation table */ +extern char ntout[17]; /* output translation table */ +#include +extern char mapin[MAXPATHLEN]; /* input map template */ +extern char mapout[MAXPATHLEN]; /* output map template */ +extern char typename[32]; /* name of file transfer type */ +extern int type; /* requested file transfer type */ +extern int curtype; /* current file transfer type */ +extern char structname[32]; /* name of file transfer structure */ +extern int stru; /* file transfer structure */ +extern char formname[32]; /* name of file transfer format */ +extern int form; /* file transfer format */ +extern char modename[32]; /* name of file transfer mode */ +extern int mode; /* file transfer mode */ +extern char bytename[32]; /* local byte size in ascii */ +extern int bytesize; /* local byte size in binary */ + +extern char *hostname; /* name of host connected to */ +extern int unix_server; /* server is unix, can use binary for ascii */ +extern int unix_proxy; /* proxy is unix, can use binary for ascii */ + +extern struct servent *sp; /* service spec for tcp/ftp */ + +#include +extern jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ + +extern char line[200]; /* input line buffer */ +extern char *stringbase; /* current scan point in line buffer */ +extern char argbuf[200]; /* argument storage buffer */ +extern char *argbase; /* current storage point in arg buffer */ +extern int margc; /* count of arguments on input line */ +extern char *margv[20]; /* args parsed from input line */ +extern int cpend; /* flag: if != 0, then pending server reply */ +extern int mflag; /* flag: if != 0, then active multi command */ + +extern int options; /* used during socket creation */ + +/* + * Format of command table. + */ +struct cmd { + char *c_name; /* name of command */ + char *c_help; /* help string */ + char c_bell; /* give bell when command completes */ + char c_conn; /* must be connected to use command */ + char c_proxy; /* proxy server may execute */ + void (*c_handler)(int argc, char **argv); /* function to call */ +}; + +struct macel { + char mac_name[9]; /* macro name */ + char *mac_start; /* start of macro in macbuf */ + char *mac_end; /* end of macro in macbuf */ +}; + +extern int macnum; /* number of defined macros */ +extern struct macel macros[16]; +extern char macbuf[4096]; diff --git a/bin/ftp/ftp_var.c b/bin/ftp/ftp_var.c new file mode 100644 index 0000000..2c0002e --- /dev/null +++ b/bin/ftp/ftp_var.c @@ -0,0 +1,91 @@ +#ifdef __ORCAC__ +segment "ftpglobals"; +#endif + +/* + * FTP global variables. + */ + +/* + * Options and other state info. + */ +int trace; /* trace packets exchanged */ +int hash; /* print # for each buffer transferred */ +int sendport; /* use PORT cmd for each data connection */ +int verbose; /* print messages coming back from server */ +int connected; /* connected to server */ +int fromatty; /* input is from a terminal */ +int interactive; /* interactively prompt on m* cmds */ +int debug; /* debugging level */ +int bell; /* ring bell on cmd completion */ +int doglob; /* glob local file names */ +int autologin; /* establish user account on connection */ +int proxy; /* proxy server connection active */ +int proxflag; /* proxy connection exists */ +int sunique; /* store files on server with unique name */ +int runique; /* store local files with unique name */ +int mcase; /* map upper to lower case for mget names */ +int ntflag; /* use ntin ntout tables for name translation */ +int mapflag; /* use mapin mapout templates on file names */ +int code; /* return/reply code for ftp command */ +int crflag; /* if 1, strip car. rets. on ascii gets */ +char pasv[64]; /* passive port for proxy data connection */ +char *altarg; /* argv[1] with no shell-like preprocessing */ +char ntin[17]; /* input translation table */ +char ntout[17]; /* output translation table */ +#include +char mapin[MAXPATHLEN]; /* input map template */ +char mapout[MAXPATHLEN]; /* output map template */ +char typename[32]; /* name of file transfer type */ +int type; /* requested file transfer type */ +int curtype; /* current file transfer type */ +char structname[32]; /* name of file transfer structure */ +int stru; /* file transfer structure */ +char formname[32]; /* name of file transfer format */ +int form; /* file transfer format */ +char modename[32]; /* name of file transfer mode */ +int mode; /* file transfer mode */ +char bytename[32]; /* local byte size in ascii */ +int bytesize; /* local byte size in binary */ + +char *hostname; /* name of host connected to */ +int unix_server; /* server is unix, can use binary for ascii */ +int unix_proxy; /* proxy is unix, can use binary for ascii */ + +struct servent *sp; /* service spec for tcp/ftp */ + +#include +jmp_buf toplevel; /* non-local goto stuff for cmd scanner */ + +char line[200]; /* input line buffer */ +char *stringbase; /* current scan point in line buffer */ +char argbuf[200]; /* argument storage buffer */ +char *argbase; /* current storage point in arg buffer */ +int margc; /* count of arguments on input line */ +char *margv[20]; /* args parsed from input line */ +int cpend; /* flag: if != 0, then pending server reply */ +int mflag; /* flag: if != 0, then active multi command */ + +int options; /* used during socket creation */ + +/* + * Format of command table. + */ +struct cmd { + char *c_name; /* name of command */ + char *c_help; /* help string */ + char c_bell; /* give bell when command completes */ + char c_conn; /* must be connected to use command */ + char c_proxy; /* proxy server may execute */ + void (*c_handler)(int argc, char **argv); /* function to call */ +}; + +struct macel { + char mac_name[9]; /* macro name */ + char *mac_start; /* start of macro in macbuf */ + char *mac_end; /* end of macro in macbuf */ +}; + +int macnum; /* number of defined macros */ +struct macel macros[16]; +char macbuf[4096]; diff --git a/bin/ftp/glob.c b/bin/ftp/glob.c new file mode 100644 index 0000000..d02f71f --- /dev/null +++ b/bin/ftp/glob.c @@ -0,0 +1,609 @@ +#ifdef __ORCAC__ +segment "ftpmain "; +#endif + +static char sccsid[] = "@(#)glob.c 5.9 (Berkeley) 2/25/91"; + +/* + * C-shell glob for random programs. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ftp.var.h" +#include "cmds.h" +#include "main.h" +#include "domacro.h" +#include "ruserpass.h" +#include "ftp.h" +#include "glob.h" + +static void ginit (char **agargv); +static void collect (char *as); +static void acollect (char *as); +static void sort (void); +static void expand (char *as); +static void matchdir (char *pattern); +static int execbrc (char *p, char *s); +static int match (char *s, char *p); +static int amatch (char *s, char *p); +static int Gmatch (char *s, char *p); +static void Gcat (char *s1, char *s2); +static void addpath (char c); +static void rscan (char **t, int (*f)(char)); +static int tglob (char c); +static char *strspl (char *cp, char *dp); +static char *strend (char *cp); + +#define QUOTE 0200 +#define TRIM 0177 +#define eq(a,b) (strcmp(a, b)==0) +#define GAVSIZ (NCARGS/6) +#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR) + +static char **gargv; /* Pointer to the (stack) arglist */ +static int gargc; /* Number args in gargv */ +static int gnleft; +static short gflag; +char *globerr; +char *home; +extern int errno; + +static int globcnt; + +char *globchars = "`{[*?"; + +static char *gpath, *gpathp, *lastgpathp; +static int globbed; +static char *entp; +static char **sortbas; + +char **ftpglob (char *v) +{ +static char agpath[BUFSIZ]; +static char *agargv[GAVSIZ]; +char *vv[2]; + + vv[0] = strspl(v, ""); + vv[1] = 0; + gflag = 0; + rscan (vv, tglob); + if (gflag == 0) + return (copyblk(vv)); + else + blkfree(vv); /* free what strspl() created */ + + globerr = 0; + gpath = agpath; gpathp = gpath; *gpathp = 0; + lastgpathp = &gpath[sizeof agpath - 2]; + ginit(agargv); globcnt = 0; + collect(v); + if (globcnt == 0 && (gflag&1)) { + blkfree(gargv), gargv = 0; + return (0); + } else + return (gargv = copyblk(gargv)); +} + +static void ginit (char **agargv) +{ + agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; + gnleft = NCARGS - 4; +} + +static void collect (char *as) +{ + if (eq(as, "{") || eq(as, "{}")) { + Gcat(as, ""); + sort(); + } else + acollect(as); +} + +static void acollect (char *as) +{ +int ogargc; + + ogargc = gargc; + gpathp = gpath; *gpathp = 0; globbed = 0; + expand(as); + if (gargc != ogargc) + sort(); +} + +static void sort (void) +{ +char **p1, **p2, *c; +char **Gvp; + + Gvp = &gargv[gargc]; + + p1 = sortbas; + while (p1 < Gvp-1) { + p2 = p1; + while (++p2 < Gvp) + if (strcmp(*p1, *p2) > 0) + c = *p1, *p1 = *p2, *p2 = c; + p1++; + } + sortbas = Gvp; +} + +static void expand (char *as) +{ +char *cs; +char *sgpathp, *oldcs; +static struct stat stb; + + sgpathp = gpathp; + cs = as; + if (*cs == '~' && gpathp == gpath) { + addpath('~'); + for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) + addpath(*cs++); + if (!*cs || *cs == '/') { + if (gpathp != gpath + 1) { + *gpathp = 0; + if (gethdir(gpath + 1)) + globerr = "Unknown user name after ~"; + (void) strcpy(gpath, gpath + 1); + } else + (void) strcpy(gpath, home); + gpathp = strend(gpath); + } + } + while (!any(*cs, globchars)) { + if (*cs == 0) { + if (!globbed) + Gcat(gpath, ""); + else if (stat(gpath, &stb) >= 0) { + Gcat(gpath, ""); + globcnt++; + } + goto endit; + } + addpath(*cs++); + } + oldcs = cs; + while (cs > as && *cs != '/') + cs--, gpathp--; + if (*cs == '/') + cs++, gpathp++; + *gpathp = 0; + if (*oldcs == '{') { + (void) execbrc(cs, ((char *)0)); + return; + } + matchdir(cs); +endit: + gpathp = sgpathp; + *gpathp = 0; +} + +static void matchdir (char *pattern) +{ +static struct stat stb; +struct dirent *dp; +DIR *dirp; + + dirp = opendir(gpath); + if (dirp == NULL) { + if (globbed) + return; + goto patherr2; + } + if (fstat(dirp->dd_fd, &stb) < 0) + goto patherr1; + if (!isdir(stb)) { + errno = ENOTDIR; + goto patherr1; + } + while ((dp = readdir(dirp)) != NULL) { + if (dp->d_ino == 0) + continue; + if (match(dp->d_name, pattern)) { + Gcat(gpath, dp->d_name); + globcnt++; + } + } + closedir(dirp); + return; + +patherr1: + closedir(dirp); +patherr2: + globerr = "Bad directory components"; +} + +static int execbrc (char *p, char *s) +{ +static char restbuf[BUFSIZ + 2]; +char *pe, *pm, *pl; +int brclev = 0; +char *lm, savec, *sgpathp; + + for (lm = restbuf; *p != '{'; *lm++ = *p++) + continue; + for (pe = ++p; *pe; pe++) + switch (*pe) { + + case '{': + brclev++; + continue; + + case '}': + if (brclev == 0) + goto pend; + brclev--; + continue; + + case '[': + for (pe++; *pe && *pe != ']'; pe++) + continue; + continue; + } +pend: + brclev = 0; + for (pl = pm = p; pm <= pe; pm++) + switch (*pm & (QUOTE|TRIM)) { + + case '{': + brclev++; + continue; + + case '}': + if (brclev) { + brclev--; + continue; + } + goto doit; + + case ','|QUOTE: + case ',': + if (brclev) + continue; +doit: + savec = *pm; + *pm = 0; + (void) strcpy(lm, pl); + (void) strcat(restbuf, pe + 1); + *pm = savec; + if (s == 0) { + sgpathp = gpathp; + expand(restbuf); + gpathp = sgpathp; + *gpathp = 0; + } else if (amatch(s, restbuf)) + return (1); + sort(); + pl = pm + 1; + if (brclev) + return (0); + continue; + + case '[': + for (pm++; *pm && *pm != ']'; pm++) + continue; + if (!*pm) + pm--; + continue; + } + if (brclev) + goto doit; + return (0); +} + +static int match (char *s, char *p) +{ +int c; +char *sentp; +char sglobbed; + + sglobbed = globbed; + + if (*s == '.' && *p != '.') + return (0); + sentp = entp; + entp = s; + c = amatch(s, p); + entp = sentp; + globbed = sglobbed; + return (c); +} + +static int amatch (char *s, char *p) +{ +int scc; +int ok, lc; +char *sgpathp; +static struct stat stb; +int c, cc; + + globbed = 1; + for (;;) { + scc = *s++ & TRIM; + switch (c = *p++) { + + case '{': + return (execbrc(p - 1, s - 1)); + + case '[': + ok = 0; + lc = 077777; + while (cc = *p++) { + if (cc == ']') { + if (ok) + break; + return (0); + } + if (cc == '-') { + if (lc <= scc && scc <= *p++) + ok++; + } else + if (scc == (lc = cc)) + ok++; + } + if (cc == 0) + if (ok) + p--; + else + return 0; + continue; + + case '*': + if (!*p) + return (1); + if (*p == '/') { + p++; + goto slash; + } + s--; + do { + if (amatch(s, p)) + return (1); + } while (*s++); + return (0); + + case 0: + return (scc == 0); + + default: + if (c != scc) + return (0); + continue; + + case '?': + if (scc == 0) + return (0); + continue; + + case '/': + if (scc) + return (0); +slash: + s = entp; + sgpathp = gpathp; + while (*s) + addpath(*s++); + addpath('/'); + if (stat(gpath, &stb) == 0 && isdir(stb)) + if (*p == 0) { + Gcat(gpath, ""); + globcnt++; + } else + expand(p); + gpathp = sgpathp; + *gpathp = 0; + return (0); + } + } +} + +static int Gmatch (char *s, char *p) +{ +int scc; +int ok, lc; +int c, cc; + + for (;;) { + scc = *s++ & TRIM; + switch (c = *p++) { + + case '[': + ok = 0; + lc = 077777; + while (cc = *p++) { + if (cc == ']') { + if (ok) + break; + return (0); + } + if (cc == '-') { + if (lc <= scc && scc <= *p++) + ok++; + } else + if (scc == (lc = cc)) + ok++; + } + if (cc == 0) + if (ok) + p--; + else + return 0; + continue; + + case '*': + if (!*p) + return (1); + for (s--; *s; s++) + if (Gmatch(s, p)) + return (1); + return (0); + + case 0: + return (scc == 0); + + default: + if ((c & TRIM) != scc) + return (0); + continue; + + case '?': + if (scc == 0) + return (0); + continue; + + } + } +} + +static void Gcat (char *s1, char *s2) +{ +int len; + + len = strlen(s1) + strlen(s2) + 1; + + if (len >= gnleft || gargc >= GAVSIZ - 1) + globerr = "Arguments too long"; + else { + gargc++; + gnleft -= len; + gargv[gargc] = 0; + gargv[gargc - 1] = strspl(s1, s2); + } +} + +static void addpath (char c) +{ + if (gpathp >= lastgpathp) + globerr = "Pathname too long"; + else { + *gpathp++ = c; + *gpathp = 0; + } +} + +static void rscan (char **t, int (*f)(char)) +{ +char *p, c; + + while (p = *t++) { + if (f == tglob) + if (*p == '~') + gflag |= 2; + else if (eq(p, "{") || eq(p, "{}")) + continue; + while (c = *p++) + (*f)(c); + } +} + +static int tglob (char c) +{ + if (any(c, globchars)) + gflag |= c == '{' ? 2 : 1; + return (c); +} + +int letter (char c) +{ + return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); +} + +int digit (char c) +{ + return (c >= '0' && c <= '9'); +} + +int any (int c, char *s) +{ + while (*s) + if (*s++ == c) + return(1); + return(0); +} + +int blklen (char **av) +{ +int i; + + i = 0; + while (*av++) + i++; + return (i); +} + +char **blkcpy (char **oav, char **bv) +{ +char **av; + + av = oav; + while (*av++ = *bv++) + continue; + return (oav); +} + +void blkfree (char **av0) +{ +char **av; + + av = av0; + + while (*av) + free(*av++); +} + +static char *strspl (char *cp, char *dp) +{ +char *ep; + + ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1)); + + if (ep == (char *)0) + fatal("Out of memory"); + (void) strcpy(ep, cp); + (void) strcat(ep, dp); + return (ep); +} + +char **copyblk (char **v) +{ +char **nv; + + nv = (char **)malloc((unsigned)((blklen(v) + 1) * sizeof(char **))); + if (nv == (char **)0) + fatal("Out of memory"); + + return (blkcpy(nv, v)); +} + +static char *strend (char *cp) +{ + while (*cp) + cp++; + return (cp); +} + +/* + * Extract a home directory from the password file + * The argument points to a buffer where the name of the + * user whose home directory is sought is currently. + * We write the home directory of the user back there. + */ +int gethdir (char *home) +{ +struct passwd *pp = getpwnam(home); + + if (!pp || home + strlen(pp->pw_dir) >= lastgpathp) + return (1); + (void) strcpy(home, pp->pw_dir); + return (0); +} diff --git a/bin/ftp/glob.h b/bin/ftp/glob.h new file mode 100644 index 0000000..392c631 --- /dev/null +++ b/bin/ftp/glob.h @@ -0,0 +1,9 @@ +char **ftpglob (char *v); +int letter (char c); +int digit (char c); +int any (int c, char *s); +int blklen (char **av); +char **blkcpy (char **oav, char **bv); +void blkfree (char **av0); +char **copyblk (char **v); +int gethdir (char *home); diff --git a/bin/ftp/main.c b/bin/ftp/main.c new file mode 100644 index 0000000..1a68ebc --- /dev/null +++ b/bin/ftp/main.c @@ -0,0 +1,470 @@ +#ifdef __ORCAC__ +segment "ftpmain "; +#endif + +char copyright[] = +"@(#) Copyright (c) 1985, 1989 Regents of the University of California.\n\ + All rights reserved.\n"; + +static char sccsid[] = "@(#)main.c 5.18 (Berkeley) 3/1/91"; + +/* + * FTP User Program -- Command Interface. + */ +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp.var.h" +#include "ftp.h" +#include "cmds.h" +#include "domacro.h" +#include "main.h" + +extern char *home; + +int +main (int argc, char **argv) +{ +char *cp; +int top; +struct passwd *pw = NULL; +static char homedir[MAXPATHLEN]; + + sp = getservbyname("ftp", "tcp"); + if (sp == 0) { + fprintf(stderr, "ftp: ftp/tcp: unknown service\n"); + exit(1); + } + doglob = 1; + interactive = 1; + autologin = 1; + argc--, argv++; + while (argc > 0 && **argv == '-') { + for (cp = *argv + 1; *cp; cp++) + switch (*cp) { + + case 'd': + options |= SO_DEBUG; + debug++; + break; + + case 'v': + verbose++; + break; + + case 't': + trace++; + break; + + case 'i': + interactive = 0; + break; + + case 'n': + autologin = 0; + break; + + case 'g': + doglob = 0; + break; + + default: + fprintf(stdout, + "ftp: %c: unknown option\n", *cp); + exit(1); + } + argc--, argv++; + } + fromatty = isatty(fileno(stdin)); + if (fromatty) + verbose++; + cpend = 0; /* no pending replies */ + proxy = 0; /* proxy not active */ + crflag = 1; /* strip c.r. on ascii gets */ + sendport = -1; /* not using ports */ + /* + * Set up the home directory in case we're globbing. + */ + cp = getlogin(); + if (cp != NULL) { + pw = getpwnam(cp); + } + if (pw == NULL) + pw = getpwuid(getuid()); + if (pw != NULL) { + home = homedir; + strcpy(home, pw->pw_dir); + } + if (argc > 0) { + if (setjmp(toplevel)) + exit(0); + signal(SIGINT, intr); + signal(SIGPIPE, lostpeer); + setpeer(argc + 1, argv - 1); + } + top = setjmp(toplevel) == 0; + if (top) { + signal(SIGINT, intr); + signal(SIGPIPE, lostpeer); + } + for (;;) { + cmdscanner(top); + top = 1; + } +} + +#pragma databank 1 +void +intr (int sig, int code) +{ + longjmp (toplevel, 1); +} + +void +lostpeer (int sig, int code) +{ +extern FILE *cout; +extern int data; + + if (connected) { + if (cout != NULL) { +#ifdef HAVE_SHUTDOWN + shutdown(fileno(cout), 1+1); +#endif + fclose(cout); + cout = NULL; + } + if (data >= 0) { +#ifdef HAVE_SHUTDOWN + shutdown(data, 1+1); +#endif + close(data); + data = -1; + } + connected = 0; + } + pswitch(1); + if (connected) { + if (cout != NULL) { +#ifdef HAVE_SHUTDOWN + shutdown(fileno(cout), 1+1); +#endif + fclose(cout); + cout = NULL; + } + connected = 0; + } + proxflag = 0; + pswitch(0); +} +#pragma databank 0 + +/* + * Command parser. + */ +int +cmdscanner (int top) +{ +struct cmd *c; +int l; + + if (!top) + putchar('\n'); + for (;;) { + if (fromatty) { + printf("ftp> "); + fflush(stdout); + } + if (fgets(line, 200, stdin) == NULL) + quit(0, NULL); + l = strlen(line); + if (l == 0) + break; + if (line[--l] == '\n') { + if (l == 0) + break; + line[l] = '\0'; + } else if (l == sizeof(line) - 2) { + printf("sorry, input line too long\n"); + while ((l = getchar()) != '\n' && l != EOF) + /* void */; + break; + } /* else it was a line without a newline */ + makeargv(); + if (margc == 0) { + continue; + } + c = getcmd(margv[0]); + if (c == (struct cmd *)-1) { + printf("?Ambiguous command\n"); + continue; + } + if (c == 0) { + printf("?Invalid command\n"); + continue; + } + if (c->c_conn && !connected) { + printf("Not connected.\n"); + continue; + } + (*c->c_handler)(margc, margv); + if (bell && c->c_bell) + putchar('\007'); + if (c->c_handler != help) + break; + } + signal(SIGINT, intr); + signal(SIGPIPE, lostpeer); +} + +struct cmd * +getcmd (char *name) +{ +extern struct cmd cmdtab[]; +char *p, *q; +struct cmd *c, *found; +int nmatches, longest; + + longest = 0; + nmatches = 0; + found = 0; + for (c = cmdtab; p = c->c_name; c++) { + for (q = name; *q == *p++; q++) + if (*q == 0) /* exact match? */ + return (c); + if (!*q) { /* the name was a prefix */ + if (q - name > longest) { + longest = q - name; + nmatches = 1; + found = c; + } else if (q - name == longest) + nmatches++; + } + } + if (nmatches > 1) + return ((struct cmd *)-1); + return (found); +} + +/* + * Slice a string up into argc/argv. + */ + +int slrflag; + +void +makeargv (void) +{ +char **argp; + + margc = 0; + argp = margv; + stringbase = line; /* scan from first of buffer */ + argbase = argbuf; /* store from first of buffer */ + slrflag = 0; + while (*argp++ = slurpstring()) + margc++; +} + +/* + * Parse string into argbuf; + * implemented with FSM to + * handle quoting and strings + */ +char * +slurpstring (void) +{ +int got_one = 0; +char *sb = stringbase; +char *ap = argbase; +char *tmp = argbase; /* will return this if token found */ + + if (*sb == '!' || *sb == '$') { /* recognize ! as a token for shell */ + switch (slrflag) { /* and $ as token for macro invoke */ + case 0: + slrflag++; + stringbase++; + return ((*sb == '!') ? "!" : "$"); + /* NOTREACHED */ + case 1: + slrflag++; + altarg = stringbase; + break; + default: + break; + } + } + +S0: + switch (*sb) { + + case '\0': + goto OUT; + + case ' ': + case '\t': + sb++; goto S0; + + default: + switch (slrflag) { + case 0: + slrflag++; + break; + case 1: + slrflag++; + altarg = sb; + break; + default: + break; + } + goto S1; + } + +S1: + switch (*sb) { + + case ' ': + case '\t': + case '\0': + goto OUT; /* end of token */ + + case '\\': + sb++; goto S2; /* slurp next character */ + + case '"': + sb++; goto S3; /* slurp quoted string */ + + default: + *ap++ = *sb++; /* add character to token */ + got_one = 1; + goto S1; + } + +S2: + switch (*sb) { + + case '\0': + goto OUT; + + default: + *ap++ = *sb++; + got_one = 1; + goto S1; + } + +S3: + switch (*sb) { + + case '\0': + goto OUT; + + case '"': + sb++; goto S1; + + default: + *ap++ = *sb++; + got_one = 1; + goto S3; + } + +OUT: + if (got_one) + *ap++ = '\0'; + argbase = ap; /* update storage pointer */ + stringbase = sb; /* update scan pointer */ + if (got_one) { + return(tmp); + } + switch (slrflag) { + case 0: + slrflag++; + break; + case 1: + slrflag++; + altarg = (char *) 0; + break; + default: + break; + } + return((char *)0); +} + +/* + * Help command. + * Call each command handler with argc == 0 and argv[0] == name. + */ +void +help (int argc, char **argv) +{ +extern struct cmd cmdtab[]; +struct cmd *c; + + if (argc == 1) { + int i, j, w, k; + int columns, width = 0, lines; + extern int NCMDS; + + printf("Commands may be abbreviated. Commands are:\n\n"); + for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { + int len = strlen(c->c_name); + + if (len > width) + width = len; + } + width = (width + 8) &~ 7; + columns = 80 / width; + if (columns == 0) + columns = 1; + lines = (NCMDS + columns - 1) / columns; + for (i = 0; i < lines; i++) { + for (j = 0; j < columns; j++) { + c = cmdtab + j * lines + i; + if (c->c_name && (!proxy || c->c_proxy)) { + printf("%s", c->c_name); + } + else if (c->c_name) { + for (k=0; k < strlen(c->c_name); k++) { + putchar(' '); + } + } + if (c + lines >= &cmdtab[NCMDS]) { + printf("\n"); + break; + } + w = strlen(c->c_name); + while (w < width) { + w = (w + 8) &~ 7; + putchar('\t'); + } + } + } + return; + } + while (--argc > 0) { + char *arg; + arg = *++argv; + c = getcmd(arg); + if (c == (struct cmd *)-1) + printf("?Ambiguous help command %s\n", arg); + else if (c == (struct cmd *)0) + printf("?Invalid help command %s\n", arg); + else + printf("%10s\t%s\n", c->c_name, c->c_help); + } +} + diff --git a/bin/ftp/main.h b/bin/ftp/main.h new file mode 100644 index 0000000..e8f665e --- /dev/null +++ b/bin/ftp/main.h @@ -0,0 +1,7 @@ +void intr (int sig, int code); +void lostpeer (int sig, int code); +int cmdscanner (int top); +struct cmd *getcmd (char *name); +void makeargv (void); +char *slurpstring (void); +void help (int argc, char **argv); diff --git a/bin/ftp/pathnames.h b/bin/ftp/pathnames.h new file mode 100644 index 0000000..ccd9aa6 --- /dev/null +++ b/bin/ftp/pathnames.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * 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. + * + * @(#)pathnames.h 5.2 (Berkeley) 6/1/90 + */ + +#include + +#undef _PATH_TMP +#define _PATH_TMP "/tmp/ftpXXXXXX" diff --git a/bin/ftp/ruserpass.c b/bin/ftp/ruserpass.c new file mode 100644 index 0000000..b664446 --- /dev/null +++ b/bin/ftp/ruserpass.c @@ -0,0 +1,252 @@ +#ifdef __ORCAC__ +segment "ftpmain "; +#endif + +static char sccsid[] = "@(#)ruserpass.c 5.3 (Berkeley) 3/1/91"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ftp.var.h" +#include "cmds.h" +#include "main.h" +#include "domacro.h" +#include "ruserpass.h" + +static FILE *cfile; + +#define DEFAULT 1 +#define LOGIN 2 +#define PASSWD 3 +#define ACCOUNT 4 +#define MACDEF 5 +#define ID 10 +#define MACH 11 + +static char tokval[100]; + +static struct toktab { + char *tokstr; + int tval; +} toktab[]= { + "default", DEFAULT, + "login", LOGIN, + "password", PASSWD, + "passwd", PASSWD, + "account", ACCOUNT, + "machine", MACH, + "macdef", MACDEF, + 0, 0 +}; + +static int token (void) +{ +char *cp; +int c; +struct toktab *t; + + if (feof(cfile)) + return (0); + while ((c = getc(cfile)) != EOF && + (c == '\n' || c == '\t' || c == ' ' || c == ',')) + continue; + if (c == EOF) + return (0); + cp = tokval; + if (c == '"') { + while ((c = getc(cfile)) != EOF && c != '"') { + if (c == '\\') + c = getc(cfile); + *cp++ = c; + } + } else { + *cp++ = c; + while ((c = getc(cfile)) != EOF + && c != '\n' && c != '\t' && c != ' ' && c != ',') { + if (c == '\\') + c = getc(cfile); + *cp++ = c; + } + } + *cp = 0; + if (tokval[0] == 0) + return (0); + for (t = toktab; t->tokstr; t++) + if (!strcmp(t->tokstr, tokval)) + return (t->tval); + return (ID); +} + +int ruserpass (char *host, char **aname, char **apass, char **aacct) +{ +char *hdir, *tmp; +static char buf[BUFSIZ]; +static char myname[MAXHOSTNAMELEN]; +char *mydomain; +int t, i, c, usedefault = 0; +static struct stat stb; + + hdir = getenv("HOME"); + if (hdir == NULL) + hdir = "."; + sprintf(buf, "%s/.netrc", hdir); + cfile = fopen(buf, "r"); + if (cfile == NULL) { + if (errno != ENOENT) + perror(buf); + return(0); + } + if (gethostname(myname, sizeof(myname)) < 0) + myname[0] = '\0'; + if ((mydomain = index(myname, '.')) == NULL) + mydomain = ""; +next: + while ((t = token())) switch(t) { + + case DEFAULT: + usedefault = 1; + /* FALL THROUGH */ + + case MACH: + if (!usedefault) { + if (token() != ID) + continue; + /* + * Allow match either for user's input host name + * or official hostname. Also allow match of + * incompletely-specified host in local domain. + */ + if (strcasecmp(host, tokval) == 0) + goto match; + if (strcasecmp(hostname, tokval) == 0) + goto match; + if ((tmp = index(hostname, '.')) != NULL && + strcasecmp(tmp, mydomain) == 0 && + strncasecmp(hostname, tokval, tmp-hostname) == 0 && + tokval[tmp - hostname] == '\0') + goto match; + if ((tmp = index(host, '.')) != NULL && + strcasecmp(tmp, mydomain) == 0 && + strncasecmp(host, tokval, tmp - host) == 0 && + tokval[tmp - host] == '\0') + goto match; + continue; + } + match: + while ((t = token()) && t != MACH && t != DEFAULT) switch(t) { + + case LOGIN: + if (token()) + if (*aname == 0) { + *aname = malloc((unsigned) strlen(tokval) + 1); + strcpy(*aname, tokval); + } else { + if (strcmp(*aname, tokval)) + goto next; + } + break; + case PASSWD: + if (strcmp(*aname, "anonymous") && + fstat(fileno(cfile), &stb) >= 0 && + (stb.st_mode & 077) != 0) { + fprintf(stderr, "Error - .netrc file not correct mode.\n"); + fprintf(stderr, "Remove password or correct mode.\n"); + goto bad; + } + if (token() && *apass == 0) { + *apass = malloc((unsigned) strlen(tokval) + 1); + strcpy(*apass, tokval); + } + break; + case ACCOUNT: + if (fstat(fileno(cfile), &stb) >= 0 + && (stb.st_mode & 077) != 0) { + fprintf(stderr, "Error - .netrc file not correct mode.\n"); + fprintf(stderr, "Remove account or correct mode.\n"); + goto bad; + } + if (token() && *aacct == 0) { + *aacct = malloc((unsigned) strlen(tokval) + 1); + strcpy(*aacct, tokval); + } + break; + case MACDEF: + if (proxy) { + fclose(cfile); + return(0); + } + while ((c=getc(cfile)) != EOF && c == ' ' || c == '\t'); + if (c == EOF || c == '\n') { + printf("Missing macdef name argument.\n"); + goto bad; + } + if (macnum == 16) { + printf("Limit of 16 macros have already been defined\n"); + goto bad; + } + tmp = macros[macnum].mac_name; + *tmp++ = c; + for (i=0; i < 8 && (c=getc(cfile)) != EOF && + !isspace(c); ++i) { + *tmp++ = c; + } + if (c == EOF) { + printf("Macro definition missing null line terminator.\n"); + goto bad; + } + *tmp = '\0'; + if (c != '\n') { + while ((c=getc(cfile)) != EOF && c != '\n'); + } + if (c == EOF) { + printf("Macro definition missing null line terminator.\n"); + goto bad; + } + if (macnum == 0) { + macros[macnum].mac_start = macbuf; + } + else { + macros[macnum].mac_start = macros[macnum-1].mac_end + 1; + } + tmp = macros[macnum].mac_start; + while (tmp != macbuf + 4096) { + if ((c=getc(cfile)) == EOF) { + printf("Macro definition missing null line terminator.\n"); + goto bad; + } + *tmp = c; + if (*tmp == '\n') { + if (*(tmp-1) == '\0') { + macros[macnum++].mac_end = tmp - 1; + break; + } + *tmp = '\0'; + } + tmp++; + } + if (tmp == macbuf + 4096) { + printf("4K macro buffer exceeded\n"); + goto bad; + } + break; + default: + fprintf(stderr, "Unknown .netrc keyword %s\n", tokval); + break; + } + goto done; + } +done: + fclose(cfile); + return(0); +bad: + fclose(cfile); + return(-1); +} diff --git a/bin/ftp/ruserpass.h b/bin/ftp/ruserpass.h new file mode 100644 index 0000000..8163d8b --- /dev/null +++ b/bin/ftp/ruserpass.h @@ -0,0 +1 @@ +int ruserpass (char *host, char **aname, char **apass, char **aacct); diff --git a/bin/ftp/tags b/bin/ftp/tags new file mode 100644 index 0000000..be74704 --- /dev/null +++ b/bin/ftp/tags @@ -0,0 +1,152 @@ +ACCOUNT ruserpass.c /^#define ACCOUNT 4$/ +DEFAULT ruserpass.c /^#define DEFAULT 1$/ +GAVSIZ glob.c /^#define GAVSIZ (NCARGS\/6)$/ +Gcat glob.c /^static void Gcat (char \*s1, char \*s2)$/ +Gmatch glob.c /^static int Gmatch (char \*s, char \*p)$/ +HASHBYTES ftp.c /^#define HASHBYTES 1024$/ +ID ruserpass.c /^#define ID 10$/ +LOGIN ruserpass.c /^#define LOGIN 2$/ +MACDEF ruserpass.c /^#define MACDEF 5$/ +MACH ruserpass.c /^#define MACH 11$/ +Mmain main.c /^main (int argc, char \*\*argv)$/ +PASSWD ruserpass.c /^#define PASSWD 3$/ +QUOTE glob.c /^#define QUOTE 0200$/ +TRIM glob.c /^#define TRIM 0177$/ +UC ftp.c /^#define UC(b) (((unsigned int)b)&0xff)$/ +_PATH_TMP pathnames.h /^#define _PATH_TMP "\/tmp\/ftpXXXXXX"$/ +abort_remote ftp.c /^void abort_remote (FILE \*din)$/ +abortpt ftp.c /^void abortpt (int sig, int code)$/ +abortrecv ftp.c /^void abortrecv (int sig, int code)$/ +abortsend ftp.c /^void abortsend (int sig, int code)$/ +account cmds.c /^void account (int argc, char \*\*argv)$/ +acollect glob.c /^static void acollect (char \*as)$/ +addpath glob.c /^static void addpath (char c)$/ +amatch glob.c /^static int amatch (char \*s, char \*p)$/ +another cmds.c /^int another (int \*pargc, char \*\*\*pargv, char / +any glob.c /^int any (int c, char \*s)$/ +blkcpy glob.c /^char \*\*blkcpy (char \*\*oav, char \*\*bv)$/ +blkfree glob.c /^void blkfree (char \*\*av0)$/ +blklen glob.c /^int blklen (char \*\*av)$/ +cd cmds.c /^void cd (int argc, char \*\*argv)$/ +cdup cmds.c /^void cdup (int argc, char \*\*argv)$/ +changetype cmds.c /^void changetype (int newtype, int show)$/ +cmd ftp.var.c /^struct cmd {$/ +cmdabort ftp.c /^void cmdabort (int sig, int code)$/ +cmdscanner main.c /^cmdscanner (int top)$/ +collect glob.c /^static void collect (char \*as)$/ +command ftp.c /^int command (char \*string, \.\.\.)$/ +comvars ftp.c /^static struct comvars {$/ +confirm cmds.c /^int confirm (char \*cmd, char \*file)$/ +copyblk glob.c /^char \*\*copyblk (char \*\*v)$/ +dataconn ftp.c /^FILE \*dataconn (char \*lmode)$/ +delete cmds.c /^void delete (int argc, char \*\*argv)$/ +digit glob.c /^int digit (char c)$/ +disconnect cmds.c /^void disconnect (int argc, char \*\*argv)$/ +do_chmod cmds.c /^void do_chmod (int argc, char \*\*argv)$/ +do_umask cmds.c /^void do_umask (int argc, char \*\*argv)$/ +domacro domacro.c /^void domacro (int argc, char \*\*argv)$/ +domap cmds.c /^char \*domap (char \*name)$/ +doproxy cmds.c /^void doproxy (int argc, char \*\*argv)$/ +dotrans cmds.c /^char \*dotrans (char \*name)$/ +empty ftp.c /^int empty (struct fd_set \*mask, int sec)$/ +eq glob.c /^#define eq(a,b) (strcmp(a, b)==0)$/ +execbrc glob.c /^static int execbrc (char \*p, char \*s)$/ +expand glob.c /^static void expand (char \*as)$/ +fatal cmds.c /^void fatal (char \*msg)$/ +ftpglob glob.c /^char \*\*ftpglob (char \*v)$/ +ftpsetdebug cmds.c /^void ftpsetdebug (int argc, char \*\*argv)$/ +get cmds.c /^void get (int argc, char \*\*argv)$/ +getcmd main.c /^getcmd (char \*name)$/ +gethdir glob.c /^int gethdir (char \*home)$/ +getit cmds.c /^int getit (int argc, char \*\*argv, int restartit,/ +getlogin ftp.c /^char \*getlogin (void)$/ +getreply ftp.c /^int getreply (int expecteof)$/ +gettimeofday ftp.c /^int gettimeofday(struct timeval \*tp, struct timez/ +ginit glob.c /^static void ginit (char \*\*agargv)$/ +globulize cmds.c /^int globulize (char \*cpp\[\])$/ +gunique ftp.c /^char \*gunique (char \*local)$/ +help main.c /^help (int argc, char \*\*argv)$/ +hookup ftp.c /^char \*hookup (char \*host, int port)$/ +idle cmds.c /^void idle (int argc, char \*\*argv)$/ +initconn ftp.c /^int initconn (void)$/ +intr main.c /^intr (int sig, int code)$/ +isdir glob.c /^#define isdir(d) ((d\.st_mode & S_IFMT) == S_IFDIR/ +lcd cmds.c /^void lcd (int argc, char \*\*argv)$/ +letter glob.c /^int letter (char c)$/ +login ftp.c /^int login (char \*host)$/ +lostpeer main.c /^lostpeer (int sig, int code)$/ +ls cmds.c /^void ls (int argc, char \*\*argv)$/ +mabort cmds.c /^void mabort (int sig, int code)$/ +macdef cmds.c /^void macdef (int argc, char \*\*argv)$/ +macel ftp.var.c /^struct macel {$/ +makeargv main.c /^makeargv (void)$/ +makedir cmds.c /^void makedir (int argc, char \*\*argv)$/ +match glob.c /^static int match (char \*s, char \*p)$/ +matchdir glob.c /^static void matchdir (char \*pattern)$/ +mdelete cmds.c /^void mdelete (int argc, char \*\*argv)$/ +mget cmds.c /^void mget (int argc, char \*\*argv)$/ +mls cmds.c /^void mls (int argc, char \*\*argv)$/ +modtime cmds.c /^void modtime (int argc, char \*\*argv)$/ +mput cmds.c /^void mput (int argc, char \*\*argv)$/ +newer cmds.c /^void newer (int argc, char \*\*argv)$/ +nz ftp.c /^#define nz(x) ((x) == 0 ? 1 : (x))$/ +onoff cmds.c /^char \*onoff (int bool)$/ +proxabort cmds.c /^void proxabort (int sig, int code)$/ +proxtrans ftp.c /^void proxtrans (char \*cmd, char \*local, char \*r/ +psabort ftp.c /^void psabort (int sig, int code)$/ +pswitch ftp.c /^void pswitch (int flag)$/ +ptransfer ftp.c /^void ptransfer(char \*direction, long bytes, struc/ +put cmds.c /^void put (int argc, char \*\*argv)$/ +pwd cmds.c /^void pwd (int argc, char \*\*argv)$/ +quit cmds.c /^void quit (int argc, char \*\*argv)$/ +quote cmds.c /^void quote (int argc, char \*\*argv)$/ +quote1 cmds.c /^void quote1 (char \*initial, int argc, char \*\*ar/ +recvrequest ftp.c /^void recvrequest (char \*cmd, char \*local, char / +reget cmds.c /^void reget (int argc, char \*\*argv)$/ +remglob cmds.c /^char \*remglob (char \*\*argv, int doswitch)$/ +removedir cmds.c /^void removedir (int argc, char \*\*argv)$/ +renamefile cmds.c /^void renamefile (int argc, char \*\*argv)$/ +reset cmds.c /^void reset (int argc, char \*\*argv)$/ +restart cmds.c /^void restart (int argc, char \*\*argv)$/ +rmthelp cmds.c /^void rmthelp (int argc, char \*\*argv)$/ +rmtstatus cmds.c /^void rmtstatus (int argc, char \*\*argv)$/ +rscan glob.c /^static void rscan (char \*\*t, int (\*f)(char))$/ +ruserpass ruserpass.c /^int ruserpass (char \*host, char \*\*aname, char / +sendrequest ftp.c /^void sendrequest (char \*cmd, char \*local, char / +setascii cmds.c /^void setascii (int argc, char \*\*argv)$/ +setbell cmds.c /^void setbell (int argc, char \*\*argv)$/ +setbinary cmds.c /^void setbinary (int argc, char \*\*argv)$/ +setcase cmds.c /^void setcase (int argc, char \*\*argv)$/ +setcr cmds.c /^void setcr (int argc, char \*\*argv)$/ +setform cmds.c /^void setform (int argc, char \*\*argv)$/ +setglob cmds.c /^void setglob (int argc, char \*\*argv)$/ +sethash cmds.c /^void sethash (int argc, char \*\*argv)$/ +setmode cmds.c /^void setmode (int argc, char \*\*argv)$/ +setnmap cmds.c /^void setnmap (int argc, char \*\*argv)$/ +setntrans cmds.c /^void setntrans (int argc, char \*\*argv)$/ +setpeer cmds.c /^void setpeer (int argc, char \*\*argv)$/ +setport cmds.c /^void setport (int argc, char \*\*argv)$/ +setprompt cmds.c /^void setprompt (int argc, char \*\*argv)$/ +setrunique cmds.c /^void setrunique (int argc, char \*\*argv)$/ +setstruct cmds.c /^void setstruct (int argc, char \*\*argv)$/ +setsunique cmds.c /^void setsunique (int argc, char \*\*argv)$/ +settenex cmds.c /^void settenex (int argc, char \*\*argv)$/ +settrace cmds.c /^void settrace (int argc, char \*\*argv)$/ +settype cmds.c /^void settype (int argc, char \*\*argv)$/ +setverbose cmds.c /^void setverbose (int argc, char \*\*argv)$/ +shell cmds.c /^void shell (int argc, char \*\*argv)$/ +site cmds.c /^void site (int argc, char \*\*argv)$/ +sizecmd cmds.c /^void sizecmd (int argc, char \*\*argv)$/ +slurpstring main.c /^slurpstring (void)$/ +sort glob.c /^static void sort (void)$/ +status cmds.c /^void status (int argc, char \*\*argv)$/ +strend glob.c /^static char \*strend (char \*cp)$/ +strspl glob.c /^static char \*strspl (char \*cp, char \*dp)$/ +syst cmds.c /^void syst (int argc, char \*\*argv)$/ +tglob glob.c /^static int tglob (char c)$/ +token ruserpass.c /^static int token (void)$/ +toktab ruserpass.c /^static struct toktab {$/ +tvadd ftp.c /^void tvadd (struct timeval \*tsum, struct timeval / +tvsub ftp.c /^void tvsub (struct timeval \*tdiff, struct timeval/ +types cmds.c /^struct types {$/ +user cmds.c /^void user (int argc, char \*\*argv)$/