diff --git a/usr.bin/ncftp/cmds.c b/usr.bin/ncftp/cmds.c index c19cf0c61f2d..d576803ea19f 100644 --- a/usr.bin/ncftp/cmds.c +++ b/usr.bin/ncftp/cmds.c @@ -1,2215 +1,2228 @@ /* cmds.c */ /* $RCSfile: cmds.c,v $ - * $Revision: 14020.14 $ - * $Date: 93/07/09 11:31:53 $ + * $Revision: 1.1.1.1 $ + * $Date: 1994/09/22 23:45:33 $ */ #include "sys.h" #include #include #include #include #include #include #include #include #include #include #ifdef SYSLOG # include #endif #include "util.h" #include "cmds.h" #include "main.h" #include "ftp.h" #include "ftprc.h" #include "getpass.h" #include "glob.h" #include "open.h" #include "set.h" #include "defaults.h" #include "copyright.h" /* cmds.c globals */ #ifdef PASSIVEMODE -int passivemode = 1; +int passivemode; /* no reverse FTP connections */ #endif int curtype; /* file transfer type */ char *typeabbrs = "abiet"; str32 curtypename; /* name of file transfer type */ int verbose; /* verbosity level of output */ int mprompt; /* interactively prompt on m* cmds */ int debug; /* debugging level */ int options; /* used during socket creation */ int macnum; /* number of defined macros */ int paging = 0; int creating = 0; struct macel macros[MAXMACROS]; char *macbuf; /* holds ALL macros */ int doingInitMacro = 0; /* TRUE if executing "init" macro. */ jmp_buf jabort; char *mname; /* name of current m* command */ int activemcmd; /* flag: if != 0, then active multi command */ int warnNoLSFlagsWithWildcards = 0; /* Tells whether the user has been * warned about not being able to use * flags with ls when using wildcards. */ longstring cwd; /* current remote directory */ longstring lcwd; /* current local directory */ Hostname lasthostname; /* name of last host w/ lookup(). */ int logged_in = 0; /* TRUE if connected and user/pw OK. */ int is_ls = 0; /* are we doing an ls? if so, then read input into a line buffer for re-use. */ extern int buffer_only; struct lslist *lshead = NULL; /* hold last output from host */ struct lslist *lstail = NULL; /* cmds.c externs */ extern char *globerr, *home, *reply_string; extern int margc, connected, ansi_escapes; extern int code, connected; extern int toatty, fromatty; extern int data, progress_meter, remote_is_unix; extern int parsing_rc, keep_recent; extern char *altarg, *line, *margv[]; extern char *globchars; extern Hostname hostname; extern RemoteSiteInfo gRmtInfo; extern string progname, pager, anon_password; extern string prompt, version, indataline; extern longstring logfname; extern long logsize; extern size_t xferbufsize; extern struct servent serv; extern struct cmd cmdtab[]; extern struct userinfo uinfo; extern FILE *cin, *cout, *logf; extern int Optind; extern char *Optarg; extern int Optind; extern char *Optarg; #ifdef STRICT_PROTOS extern int gethostname(char *, int), getdomainname(char *, int); #endif struct types 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, "8" }, { 0 } }; long GetDateSizeFromLSLine(char *fName, unsigned long *mod_time) { char *cp, *np; string lsline; long size = SIZE_UNKNOWN; int n, v; struct lslist *savedh, *savedt; static int depth = 0; depth++; /* Try to prevent infinite recursion. */ *mod_time = MDTM_UNKNOWN; v = verbose; verbose = V_QUIET; is_ls = 1; buffer_only = 1; savedh = lshead; savedt = lstail; lshead = NULL; (void) recvrequest("LIST", "-", fName, "w"); is_ls = 0; buffer_only = 0; verbose = v; if (lshead == NULL) { PurgeLineBuffer(); lshead = savedh; lstail = savedt; goto aa; } (void) Strncpy(lsline, lshead->string); PurgeLineBuffer(); lshead = savedh; lstail = savedt; if (code >= 400 && code < 500) goto aa; /* See if this line looks like a unix-style ls line. * If so, we can grab the date and size from it. */ if (strpbrk(lsline, "-dlsbcp") == lsline) { /* See if it looks like a typical '-rwxrwxrwx' line. */ cp = lsline + 1; if (*cp != 'r' && *cp != '-') goto aa; ++cp; if (*cp != 'w' && *cp != '-') goto aa; cp += 2; if (*cp != 'r' && *cp != '-') goto aa; /* skip mode, links, owner (and possibly group) */ for (n = 0; n < 4; n++) { np = cp; while (*cp != '\0' && !isspace(*cp)) cp++; while (*cp != '\0' && isspace(*cp)) cp++; } if (!isdigit(*cp)) cp = np; /* back up (no group) */ (void) sscanf(cp, "%ld%n", &size, &n); *mod_time = UnLSDate(cp + n + 1); if (size < 100) { /* May be the size of a link to the file, instead of the file. */ if ((cp = strstr(lsline, " -> ")) != NULL) { /* Yes, it was a link. */ size = (depth>4) ? SIZE_UNKNOWN : GetDateAndSize(cp + 4, mod_time); /* Try the file. */ } } } aa: --depth; return (size); } /* GetDateSizeFromLSLine */ /* The caller wanted to know the modification date and size of the remote * file given to us. We try to get this information by using the SIZE * and MDTM ftp commands, and if that didn't work we try sending the site * a "ls -l " and try to get that information from the line it * sends us back. It is possible that we won't be able to determine * either of these, though. */ long GetDateAndSize(char *fName, unsigned long *mod_time) { unsigned long mdtm, ls_mdtm; long size, ls_size; int have_mdtm, have_size; string cmd; size = SIZE_UNKNOWN; mdtm = MDTM_UNKNOWN; if (fName != NULL) { have_mdtm = have_size = 0; if (gRmtInfo.hasSIZE) { (void) Strncpy(cmd, "SIZE "); (void) Strncat(cmd, fName); if (quiet_command(cmd) == 2) { if (sscanf(reply_string, "%*d %ld", &size) == 1) have_size = 1; } else if (strncmp(reply_string, "550", (size_t)3) != 0) gRmtInfo.hasSIZE = 0; } #ifndef NO_MKTIME /* We'll need mktime() to un-mangle this. */ if (gRmtInfo.hasMDTM) { (void) Strncpy(cmd, "MDTM "); (void) Strncat(cmd, fName); if (quiet_command(cmd) == 2) { /* Result should look like "213 19930602204445\n" */ mdtm = UnMDTMDate(reply_string); if (mdtm != MDTM_UNKNOWN) have_mdtm = 1; } else if (strncmp(reply_string, "550", (size_t)3) != 0) gRmtInfo.hasMDTM = 0; } #endif /* NO_MKTIME */ if (!have_mdtm || !have_size) ls_size = GetDateSizeFromLSLine(fName, &ls_mdtm); /* Try to use the information from the real SIZE/MDTM commands if * we could, since some maverick ftp server may be using a non-standard * ls command, and we could parse it wrong. */ if (!have_mdtm) mdtm = ls_mdtm; if (!have_size) size = ls_size; dbprintf("Used SIZE: %s; Used MDTM: %s\n", have_size ? "yes" : "no", have_mdtm ? "yes" : "no" ); if (debug > 0) { if (size != SIZE_UNKNOWN) dbprintf("Size: %ld\n", size); if (mdtm != MDTM_UNKNOWN) dbprintf("Mdtm: %s\n", ctime((time_t *) &mdtm)); } } *mod_time = mdtm; return size; } /* GetDateAndSize */ int _settype(char *typename) { register struct types *p; int comret, c; string cmd; char *cp; c = isupper(*typename) ? tolower(*typename) : (*typename); if ((cp = index(typeabbrs, c)) != NULL) p = &types[(int) (cp - typeabbrs)]; else { (void) printf("%s: unknown type\n", typename); return USAGE; } if (c == 't') (void) strcpy(cmd, "TYPE L 8"); else (void) sprintf(cmd, "TYPE %s", p->t_mode); comret = command(cmd); if (comret == COMPLETE) { (void) Strncpy(curtypename, p->t_name); curtype = p->t_type; } return NOERR; } /* _settype */ int SetTypeByNumber(int i) { char tstr[4], *tp = tstr, c; tp[1] = c = 0; switch (i) { case TYPE_A: c = 'a'; break; case TYPE_I: c = 'b'; break; case TYPE_E: c = 'e'; break; case TYPE_L: c = 't'; } *tp = c; return (c == 0 ? -1 : _settype(tp)); } /* SetTypeByNumber */ /* * Set transfer type. */ int settype(int argc, char **argv) { int result = NOERR; if (argc > 2) { result = USAGE; } else { if (argc < 2) goto xx; result = _settype(argv[1]); if (IS_VVERBOSE) xx: (void) printf("Using %s mode to transfer files.\n", curtypename); } return result; } /* settype */ /*ARGSUSED*/ int setbinary(int argc, char **argv) { return (_settype("binary")); } /*ARGSUSED*/ int setascii(int argc, char **argv) { return (_settype("ascii")); } /* * Send a single file. */ int put(int argc, char **argv) { char *cmd; if (argc == 2) { argc++; argv[2] = argv[1]; } if (argc < 2) argv = re_makeargv("(local-file) ", &argc); if (argc < 2) { usage: return USAGE; } if (argc < 3) argv = re_makeargv("(remote-file) ", &argc); if (argc < 3) goto usage; cmd = (argv[0][0] == 'a') ? "APPE" : "STOR"; (void) sendrequest(cmd, argv[1], argv[2]); return NOERR; } /* put */ /* * Send multiple files. */ int mput(int argc, char **argv) { register int i; Sig_t oldintr; char *tp; if (argc < 2) argv = re_makeargv("(local-files) ", &argc); if (argc < 2) { return USAGE; } mname = argv[0]; activemcmd = 1; oldintr = Signal(SIGINT, mabort); (void) setjmp(jabort); for (i = 1; i < argc; i++) { register char **cpp, **gargs; char *icopy; /* Make a copy of the argument, because glob() will just copy * the pointer you give it to the glob-arg vector, and blkfree() * will want to free each element of the glob-arg vector * later. */ if ((icopy = NewString(argv[i])) == NULL) break; gargs = glob(icopy); if (globerr != NULL) { (void) printf("%s\n", globerr); if (gargs) { blkfree(gargs); Free(gargs); } continue; } for (cpp = gargs; cpp && *cpp != NULL; cpp++) { if (activemcmd && confirm(argv[0], *cpp)) { tp = *cpp; (void) sendrequest("STOR", *cpp, tp); if (!activemcmd && fromatty) { if (confirm("Continue with","mput")) { activemcmd++; } } } } if (gargs != NULL) { blkfree(gargs); Free(gargs); } } (void) Signal(SIGINT, oldintr); activemcmd = 0; return NOERR; } /* mput */ int rem_glob_one(char *pattern) { int oldverbose, result = 0; char *cp; string str, tname; FILE *ftemp; /* Check for wildcard characters. */ if (*pattern == '|' || strpbrk(pattern, globchars) == NULL) return 0; (void) tmp_name(tname); oldverbose = verbose; verbose = V_QUIET; (void) recvrequest ("NLST", tname, pattern, "w"); verbose = oldverbose; ftemp = fopen(tname, "r"); (void) chmod(tname, 0600); if (ftemp == NULL || FGets(str, ftemp) == NULL) { if (NOT_VQUIET) (void) printf("%s: no match.\n", pattern); result = -1; goto done; } if ((cp = index(str, '\n')) != NULL) *cp = '\0'; (void) strcpy(pattern, str); cp = FGets(str, ftemp); /* It is an error if the pattern matched more than one file. */ if (cp != NULL) { if (NOT_VQUIET) (void) printf("?Ambiguous remote file name.\n"); result = -2; } done: if (ftemp != NULL) (void) fclose(ftemp); (void) unlink(tname); return (result); } /* rem_glob_one */ /* * Receive (and maybe page) one file. */ int get(int argc, char **argv) { string local_file; char remote_file[256]; char *cp; int oldtype = curtype, try_zcat; size_t len; /* paging mode is set if the command name is 'page' or 'more.' */ paging = (**argv != 'g'); if (argc < 2) argv = re_makeargv("(remote-file) ", &argc); if (argc < 2) { return USAGE; } cp = Strncpy(remote_file, argv[1]); argv[1] = cp; if (rem_glob_one(argv[1]) < 0) return CMDERR; if (paging) { try_zcat = 0; len = strlen(remote_file); if (len > (size_t) 2) { if (remote_file[len-2] == '.') { /* Check for .Z files. */ if (remote_file[len-1] == 'Z') try_zcat = 1; #ifdef GZCAT /* Check for .z (gzip) files. */ if (remote_file[len-1] == 'z') try_zcat = 1; #endif /* GZCAT */ } } #ifdef GZCAT if (len > (size_t) 3) { /* Check for ".gz" (gzip) files. */ if (strcmp(remote_file + len - 3, ".gz") == 0) try_zcat = 1; } #endif /* GZCAT */ /* Run compressed remote files through zcat, then the pager. * If GZCAT was defined, we also try paging gzipped files. * Note that ZCAT is defined to be GZCAT if you defined * GZCAT. */ if (try_zcat) { (void) _settype("b"); (void) sprintf(local_file, "|%s ", ZCAT); argv[2] = Strncat(local_file, pager); } else { /* Try to use text mode for paging, so newlines get converted. */ (void) _settype("a"); argv[2] = pager; } } else { /* normal get */ if (argc == 2) { (void) Strncpy(local_file, argv[1]); argv[2] = local_file; } else { if (argc < 3) argv = re_makeargv("(local-file) ", &argc); if (argc < 3) return USAGE; (void) LocalDotPath(argv[2]); } } (void) recvrequest("RETR", argv[2], argv[1], "w"); if (paging) { (void) SetTypeByNumber(oldtype); /* Restore it to what it was. */ paging = 0; } return NOERR; } /* get */ /*ARGSUSED*/ void mabort SIG_PARAMS { (void) printf("\n"); (void) fflush(stdout); if (activemcmd && fromatty) { if (confirm("Continue with", mname)) { longjmp(jabort,0); } } activemcmd = 0; longjmp(jabort,0); } /* mabort */ /* * Get multiple files. */ int mget(int argc, char **argv) { char *cp; longstring local; Sig_t oldintr; + int errs; if (argc < 2) argv = re_makeargv("(remote-files) ", &argc); if (argc < 2) { return USAGE; } mname = argv[0]; activemcmd = 1; oldintr = Signal(SIGINT, mabort); (void) setjmp(jabort); - while ((cp = remglob(argv)) != NULL) { + while ((cp = remglob(argv, &errs)) != NULL) { if (*cp == '\0') { activemcmd = 0; continue; } if (activemcmd && confirm(argv[0], cp)) { (void) Strncpy(local, cp); (void) recvrequest("RETR", local, cp, "w"); if (!activemcmd && fromatty) { if (confirm("Continue with","mget")) { activemcmd++; } } } } (void) Signal(SIGINT,oldintr); activemcmd = 0; + if (!errs) return NOERR; + else + return CMDERR; } /* mget */ -char *remglob(char *argv[]) +char *remglob(char *argv[], int *errs) { static FILE *ftemp = NULL; int oldverbose, i; char *cp, *mode; static string tmpname, str; - int result, errs; + int result; if (!activemcmd) { xx: if (ftemp) { (void) fclose(ftemp); ftemp = NULL; (void) unlink(tmpname); } return(NULL); } if (ftemp == NULL) { (void) tmp_name(tmpname); oldverbose = verbose, verbose = V_QUIET; - errs = 0; + *errs = 0; for (mode = "w", i=1; argv[i] != NULL; i++, mode = "a") { result = recvrequest ("NLST", tmpname, argv[i], mode); if (i == 1) (void) chmod(tmpname, 0600); if (result < 0) { fprintf(stderr, "%s: %s.\n", argv[i], (strpbrk(argv[i], globchars) != NULL) ? "No match" : "No such file" ); - errs++; + ++(*errs); } } verbose = oldverbose; - if (errs == (i - 1)) { + if (*errs == (i - 1)) { /* Every pattern was in error, so we can't try anything. */ (void) unlink(tmpname); /* Shouldn't be there anyway. */ return NULL; } ftemp = fopen(tmpname, "r"); if (ftemp == NULL) { PERROR("remglob", tmpname); return (NULL); } } if (FGets(str, ftemp) == NULL) goto xx; if ((cp = index(str, '\n')) != NULL) *cp = '\0'; return (str); } /* remglob */ /* * Turn on/off printing of server echo's, messages, and statistics. */ int setverbose(int argc, char **argv) { if (argc > 1) set_verbose(argv[1], 0); else set_verbose(argv[1], -1); return NOERR; } /* setverbose */ /* * Toggle interactive prompting * during mget, mput, and mdelete. */ int setprompt(int argc, char **argv) { if (argc > 1) mprompt = StrToBool(argv[1]); else mprompt = !mprompt; if (IS_VVERBOSE) (void) printf("Interactive prompting for m* commmands %s.\n", onoff(mprompt)); return NOERR; } /* setprompt */ void fix_options(void) { if (debug) options |= SO_DEBUG; else options &= ~SO_DEBUG; } /* fix_options */ /* * Set debugging mode on/off and/or * set level of debugging. */ int setdebug(int argc, char **argv) { int val; if (argc > 1) { val = StrToBool(argv[1]); if (val < 0) { (void) printf("%s: bad debugging value.\n", argv[1]); return USAGE; } } else val = !debug; debug = val; fix_options(); if (IS_VVERBOSE) (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug); return NOERR; } /* debug */ /* * Set current working directory * on remote machine. */ int cd(int argc, char **argv) { if (argc < 2) argv = re_makeargv("(remote-directory) ", &argc); if (argc < 2) { return USAGE; } (void) _cd(argv[1]); return NOERR; } /* cd */ int implicit_cd(char *dir) { int i, j = 0; if (connected) { i = verbose; /* Special verbosity level that ignores errors and prints other stuff, * so you will get just the unknown command message and not an error * message from cd. */ verbose = V_IMPLICITCD; j = _cd(dir); verbose = i; } return j; } /* implicit_cd */ int _cd(char *dir) { register char *cp; int result = 0; string str; if (dir == NULL) goto getrwd; /* Won't work because glob really is a ls, so 'cd pu*' will match * pub/README, pub/file2, etc. * if (result = rem_glob_one(dir) < 0) * return result; */ if (strncmp(dir, "CDUP", (size_t) 4) == 0) (void) Strncpy(str, dir); else (void) sprintf(str, "CWD %s", dir); if (command(str) != 5) { getrwd: (void) quiet_command("PWD"); cp = rindex(reply_string, '\"'); if (cp != NULL) { result = 1; *cp = '\0'; cp = index(reply_string, '\"'); if (cp != NULL) (void) Strncpy(cwd, ++cp); } } dbprintf("Current remote directory is \"%s\"\n", cwd); return (result); } /* _cd */ /* * Set current working directory * on local machine. */ int lcd(int argc, char **argv) { longstring ldir; if (argc < 2) argc++, argv[1] = home; if (argc != 2) { return USAGE; } (void) Strncpy(ldir, argv[1]); if (chdir(LocalDotPath(ldir)) < 0) { PERROR("lcd", ldir); return CMDERR; } (void) get_cwd(lcwd, (int) sizeof(lcwd)); if (NOT_VQUIET) (void) printf("Local directory now %s\n", lcwd); return NOERR; } /* lcd */ /* * Delete a single file. */ int do_delete(int argc, char **argv) { string str; if (argc < 2) argv = re_makeargv("(remote file to delete) ", &argc); if (argc < 2) { return USAGE; } if (rem_glob_one(argv[1]) == 0) { (void) sprintf(str, "DELE %s", argv[1]); (void) command(str); } return NOERR; } /* do_delete */ /* * Delete multiple files. */ int mdelete(int argc, char **argv) { char *cp; Sig_t oldintr; string str; + int errs; if (argc < 2) argv = re_makeargv("(remote-files) ", &argc); if (argc < 2) { return USAGE; } mname = argv[0]; activemcmd = 1; oldintr = Signal(SIGINT, mabort); (void) setjmp(jabort); - while ((cp = remglob(argv)) != NULL) { + while ((cp = remglob(argv, &errs)) != NULL) { if (*cp == '\0') { activemcmd = 0; continue; } if (activemcmd && confirm(argv[0], cp)) { (void) sprintf(str, "DELE %s", cp); (void) command(str); if (!activemcmd && fromatty) { if (confirm("Continue with", "mdelete")) { activemcmd++; } } } } (void) Signal(SIGINT, oldintr); activemcmd = 0; + if (errs > 0) + return CMDERR; return NOERR; } /* mdelete */ /* * Rename a remote file. */ int renamefile(int argc, char **argv) { string str; if (argc < 2) argv = re_makeargv("(from-name) ", &argc); if (argc < 2) { usage: return USAGE; } if (argc < 3) argv = re_makeargv("(to-name) ", &argc); if (argc < 3) goto usage; if (rem_glob_one(argv[1]) < 0) return CMDERR; (void) sprintf(str, "RNFR %s", argv[1]); if (command(str) == CONTINUE) { (void) sprintf(str, "RNTO %s", argv[2]); (void) command(str); } return NOERR; } /* renamefile */ /* * Get a directory listing * of remote files. */ int ls(int argc, char **argv) { char *whichcmd, *cp; str32 lsflags; string remote, local, str; int listmode, pagemode, i; PurgeLineBuffer(); pagemode = 0; switch (**argv) { case 'p': /* pls, pdir, pnlist */ pagemode = 1; listmode = argv[0][1] == 'd'; break; case 'd': /* dir */ listmode = 1; break; default: /* ls, nlist */ listmode = 0; } whichcmd = listmode ? "LIST" : "NLST"; (void) strncpy(local, (pagemode ? pager : "-"), sizeof(local)); remote[0] = lsflags[0] = 0; /* Possible scenarios: * 1. ls * 2. ls -flags * 3. ls directory * 4. ls -flags >outfile * 5. ls directory >outfile * 6. ls -flags directory * 7. ls -flags directory >outfile * * Note that using a wildcard will choke with flags. I.e., don't do * "ls -CF *.tar," but instead do "ls *.tar." */ for (i=1; i': /* We don't want the '>'. */ (void) Strncpy(local, argv[i] + 1); LocalDotPath(local); break; default: cp = argv[i]; /* * In case you want to get a remote file called '--README--' * or '>README,' you can use '\--README--' and '\>README.' */ if ((cp[1] != 0) && (*cp == '\\')) ++cp; if (remote[0] != 0) { (void) Strncat(remote, " "); (void) Strncat(remote, cp); } else { (void) Strncpy(remote, cp); } } /* end switch */ } /* end loop */ /* * If we are given an ls with some flags, make sure we use * columnized output (-C) unless one column output (-1) is * specified. */ if (!listmode) { if (lsflags[0] != 0) { (void) Strncpy(str, lsflags); for (cp = str + 1; *cp; cp++) if (*cp == '1') goto aa; (void) sprintf(lsflags, "-FC%s", str + 1); } else { if (remote_is_unix) (void) strcpy(lsflags, "-FC"); } /* As noted above, we can't use -flags if the user gave a * wildcard expr. */ if (remote_is_unix && (strpbrk(remote, globchars) != NULL)) { lsflags[0] = 0; /* Warn the user what's going on. */ if ((warnNoLSFlagsWithWildcards == 0) && NOT_VQUIET) { (void) fprintf(stderr, "Warning: ls flags disabled with wildcard expressions.\n"); warnNoLSFlagsWithWildcards++; } } } aa: is_ls = 1; /* tells getreply() to start saving input to a buffer. */ (void) Strncpy(str, remote); if (lsflags[0] && remote[0]) (void) sprintf(remote, "%s%c%s", lsflags, LS_FLAGS_AND_FILE, str); else (void) strncpy(remote, lsflags[0] ? lsflags : str, sizeof(remote)); (void) recvrequest(whichcmd, local, (remote[0] == 0 ? NULL : remote), "w"); is_ls=0; return NOERR; } /* ls */ /* * Do a shell escape */ /*ARGSUSED*/ int shell(int argc, char **argv) { int pid; Sig_t old1, old2; char *theShell, *namep; #ifndef U_WAIT int Status; #else union wait Status; #endif string str; old1 = signal (SIGINT, SIG_IGN); old2 = signal (SIGQUIT, SIG_IGN); /* This will prevent zombie processes. */ /* (void) signal(SIGCHLD, SIG_IGN); */ if ((pid = fork()) == 0) { for (pid = 3; pid < 20; pid++) (void) close(pid); (void) Signal(SIGINT, SIG_DFL); (void) Signal(SIGQUIT, SIG_DFL); if ((theShell = getenv("SHELL")) == NULL) theShell = uinfo.shell; if (theShell == NULL) theShell = "/bin/sh"; namep = rindex(theShell, '/'); if (namep == NULL) namep = theShell; (void) strcpy(str, "-"); (void) strcat(str, ++namep); if (strcmp(namep, "sh") != 0) str[0] = '+'; dbprintf ("%s\n", theShell); #if defined(BSD) || defined(_POSIX_SOURCE) setreuid(-1,getuid()); setregid(-1,getgid()); #endif if (argc > 1) (void) execl(theShell, str, "-c", altarg, (char *)0); else (void) execl(theShell, str, (char *)0); PERROR("shell", theShell); exit(1); } if (pid > 0) while (wait((void *) &Status) != pid) ; (void) Signal(SIGINT, old1); (void) Signal(SIGQUIT, old2); if (pid == -1) { PERROR("shell", "Try again later"); } return NOERR; } /* shell */ /* * Send new user information (re-login) */ int do_user(int argc, char **argv) { char acct[80]; int n, aflag = 0; string str; if (argc < 2) argv = re_makeargv("(username) ", &argc); if (argc > 4) { return USAGE; } (void) sprintf(str, "USER %s", argv[1]); n = command(str); if (n == CONTINUE) { if (argc < 3 ) argv[2] = Getpass("Password: "), argc++; (void) sprintf(str, "PASS %s", argv[2]); n = command(str); } if (n == CONTINUE) { if (argc < 4) { (void) printf("Account: "); (void) fflush(stdout); (void) FGets(acct, stdin); acct[strlen(acct) - 1] = '\0'; argv[3] = acct; argc++; } (void) sprintf(str, "ACCT %s", argv[3]); n = command(str); aflag++; } if (n != COMPLETE) { (void) fprintf(stdout, "Login failed.\n"); logged_in = 0; return (0); } if (!aflag && argc == 4) { (void) sprintf(str, "ACCT %s", argv[3]); (void) command(str); } logged_in = 1; CheckRemoteSystemType(0); return NOERR; } /* do_user */ /* * Print working directory. */ /*ARGSUSED*/ int pwd(int argc, char **argv) { (void) verbose_command("PWD"); return NOERR; } /* pwd */ /* * Make a directory. */ int makedir(int argc, char **argv) { string str; if (argc < 2) argv = re_makeargv("(directory-name) ", &argc); if (argc < 2) { return USAGE; } (void) sprintf(str, "MKD %s", argv[1]); (void) command(str); return NOERR; } /* makedir */ /* * Remove a directory. */ int removedir(int argc, char **argv) { string str; if (argc < 2) argv = re_makeargv("(directory-name) ", &argc); if (argc < 2) { return USAGE; } if (rem_glob_one(argv[1]) == 0) { (void) sprintf(str, "RMD %s", argv[1]); (void) command(str); } return NOERR; } /* removedir */ /* * Send a line, verbatim, to the remote machine. */ int quote(int argc, char **argv) { int i, tmpverbose; string str; if (argc < 2) argv = re_makeargv("(command line to send) ", &argc); if (argc < 2) { return USAGE; } str[0] = 0; if (*argv[0] == 's') /* Command was 'site' instead of 'quote.' */ (void) Strncpy(str, "site "); (void) Strncat(str, argv[1]); for (i = 2; i < argc; i++) { (void) Strncat(str, " "); (void) Strncat(str, argv[i]); } tmpverbose = verbose; verbose = V_VERBOSE; if (command(str) == PRELIM) { while (getreply(0) == PRELIM); } verbose = tmpverbose; return NOERR; } /* quote */ /* * Ask the other side for help. */ int rmthelp(int argc, char **argv) { string str; if (argc == 1) (void) verbose_command("HELP"); else { (void) sprintf(str, "HELP %s", argv[1]); (void) verbose_command(str); } return NOERR; } /* rmthelp */ /* * Terminate session and exit. */ /*ARGSUSED*/ int quit(int argc, char **argv) { - close_up_shop(); + int rc; + + /* slightly kludge. argc == -1 means failure from some other caller */ + rc = close_up_shop() || argc == -1; trim_log(); - exit(0); + exit(rc); } /* quit */ void close_streams(int wantShutDown) { if (cout != NULL) { if (wantShutDown) (void) shutdown(fileno(cout), 1+1); (void) fclose(cout); cout = NULL; } if (cin != NULL) { if (wantShutDown) (void) shutdown(fileno(cin), 1+1); (void) fclose(cin); cin = NULL; } } /* close_streams */ /* * Terminate session, but don't exit. */ /*ARGSUSED*/ int disconnect(int argc, char **argv) { #ifdef SYSLOG syslog (LOG_INFO, "%s disconnected from %s.", uinfo.username, hostname); #endif (void) command("QUIT"); close_streams(0); if (logged_in) UpdateRecentSitesList(hostname, cwd); hostname[0] = cwd[0] = 0; logged_in = connected = 0; data = -1; macnum = 0; return NOERR; } /* disconnect */ -void +int close_up_shop(void) { static int only_once = 0; + int rcode = 0; + if (only_once++ > 0) - return; + return (0); if (connected) (void) disconnect(0, NULL); - WriteRecentSitesFile(); + rcode = WriteRecentSitesFile(); if (logf != NULL) { (void) fclose(logf); logf = NULL; } + return rcode; } /* close_up_shop */ /* * 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; (void) LocalPath(*cpp); globbed = glob(*cpp); if (globerr != NULL) { (void) printf("%s: %s\n", *cpp, globerr); if (globbed) { blkfree(globbed); Free(globbed); } return (0); } if (globbed) { *cpp = *globbed++; /* don't waste too much memory */ if (*globbed) { blkfree(globbed); Free(globbed); } } return (1); } /* globulize */ /* change directory to perent directory */ /*ARGSUSED*/ int cdup(int argc, char **argv) { (void) _cd("CDUP"); return NOERR; } /* cdup */ /* show remote system type */ /*ARGSUSED*/ int syst(int argc, char **argv) { (void) verbose_command("SYST"); return NOERR; } /* syst */ int make_macro(char *name, FILE *fp) { char *tmp; char *cp; string str; size_t len; int i; if (macnum == MAXMACROS) { (void) fprintf(stderr, "Limit of %d macros have already been defined.\n", MAXMACROS); return -1; } /* Make sure macros have unique names. If 'init' was attempted to be * redefined, just return, since it was probably cmdOpen() in a redial * mode which tried to define it again. */ for (i = 0; i macros[macnum].mac_start) goto endmac; (void) fprintf(stderr, "No text supplied for macro \"%s.\"\n", name); } /* see if we have a 'blank' line: just whitespace. */ while (*cp && isspace(*cp)) ++cp; if (*cp == '\0') { /* Blank line; end this macro. */ endmac: macros[macnum++].mac_end = tmp; return 0; } /* Add the text of this line to the macro. */ len = strlen(cp) + 1; /* we need the \0 too. */ if (tmp + len >= macbuf + MACBUFLEN) { (void) fprintf(stderr, "Macro \"%s\" not defined -- %d byte buffer exceeded.\n", name, MACBUFLEN); return -1; } (void) strcpy(tmp, cp); tmp += len; } } /* make_macro */ int macdef(int argc, char **argv) { if (argc < 2) argv = re_makeargv("(macro name) ", &argc); if (argc != 2) { (void) domacro(0, NULL); return USAGE; } (void) printf("Enter macro line by line, terminating it with a blank line\n"); (void) make_macro(argv[1], stdin); return NOERR; } /* macdef */ int domacro(int argc, char **argv) { register int i, j; register char *cp1, *cp2; int count = 2, loopflg = 0; string str; struct cmd *c; if (argc < 2) { /* print macros. */ if (macnum == 0) (void) printf("No macros defined.\n"); else { (void) printf("Current macro definitions:\n"); for (i = 0; i < macnum; ++i) { (void) printf("%s:\n", macros[i].mac_name); cp1 = macros[i].mac_start; cp2 = macros[i].mac_end; while (cp1 < cp2) { (void) printf(" > "); while (cp1 < cp2 && *cp1) putchar(*cp1++); ++cp1; } } } if (argc == 0) return (NOERR); /* called from macdef(), above. */ argv = re_makeargv("(macro to run) ", &argc); } if (argc < 2) { return USAGE; } for (i = 0; i < macnum; ++i) { if (!strncmp(argv[1], macros[i].mac_name, (size_t) 9)) { break; } } if (i == macnum) { (void) printf("'%s' macro not found.\n", argv[1]); return USAGE; } doingInitMacro = (strcmp(macros[i].mac_name, "init") == 0); (void) Strncpy(str, 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) && !parsing_rc) { (void) printf("?Ambiguous command\n"); } else if (c == NULL && !parsing_rc) { (void) printf("?Invalid command\n"); } else if (c->c_conn && !connected) { (void) printf("Not connected.\n"); } else { if (IS_VVERBOSE) (void) printf("%s\n",line); if ((*c->c_handler)(margc, margv) == USAGE) cmd_usage(c); (void) strcpy(line, str); makeargv(); argc = margc; argv = margv; } if (cp1 != macros[i].mac_end) { cp1++; } } if (loopflg && ++count < argc) { goto TOP; } doingInitMacro = 0; return NOERR; } /* domacro */ /* * get size of file on remote machine */ int sizecmd(int argc, char **argv) { string str; if (argc < 2) argv = re_makeargv("(remote-file) ", &argc); if (argc < 2) { return USAGE; } if (rem_glob_one(argv[1]) == 0) { (void) sprintf(str, "SIZE %s", argv[1]); (void) verbose_command(str); } return NOERR; } /* sizecmd */ /* * get last modification time of file on remote machine */ int modtime(int argc, char **argv) { int overbose; string str; if (argc < 2) argv = re_makeargv("(remote-file) ", &argc); if (argc < 2) { return USAGE; } if (rem_glob_one(argv[1]) == 0) { overbose = verbose; if (debug == 0) verbose = V_QUIET; (void) sprintf(str, "MDTM %s", argv[1]); if (command(str) == COMPLETE) { int yy, mo, day, hour, min, sec; (void) sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo, &day, &hour, &min, &sec); /* might want to print this in local time */ (void) printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1], mo, day, yy, hour, min, sec); } else (void) fputs(reply_string, stdout); verbose = overbose; } return NOERR; } /* modtime */ int lookup(int argc, char **argv) { int i, j, by_name, result = NOERR; struct hostent *host; /* structure returned by gethostbyaddr() */ extern int h_errno; #ifdef BAD_INETADDR struct in_addr addr; /* address in host order */ # define ADDR addr.s_addr #else unsigned long addr; /* address in host order */ # define ADDR addr #endif if (argc < 2) argv = re_makeargv("(sitename) ", &argc); if (argc < 2) { return USAGE; } lasthostname[0] = 0; for (i=1; ih_name) (void) Strncpy(lasthostname, host->h_name); for (j=0; host->h_aliases[j] != NULL; j++) { if (strlen(host->h_aliases[j]) > strlen(host->h_name) && strstr(host->h_aliases[j],host->h_name) != NULL) (void) Strncpy(lasthostname,host->h_aliases[j]); } if (NOT_VQUIET) { (void) printf("%-32s ", *host->h_name ? host->h_name : "???"); if (*host->h_addr_list) { unsigned long horder; horder = ntohl (*(unsigned long *) *(char **)host->h_addr_list); (void) printf ("%lu.%lu.%lu.%lu\n", (horder >> 24), (horder >> 16) & 0xff, (horder >> 8) & 0xff, horder & 0xff); } else (void) printf("???\n"); } } } /* loop thru all sites */ return result; } /* lookup */ int getlocalhostname(char *host, size_t size) { int oldv, r; char *argv[2]; char domain[64]; #ifdef HOSTNAME (void) strncpy(host, HOSTNAME, size); return NOERR; #else host[0] = '\0'; if ((r = gethostname(host, size)) == 0) { if (host[0] == '\0') { (void) fprintf(stderr, "Could not determine the hostname. Re-compile with HOSTNAME defined\n\ to be the full name of your hostname.\n"); exit(1); } oldv = verbose; verbose = V_QUIET; argv[0] = "lookup"; (void) sprintf(line, "lookup %s", host); (void) makeargv(); if (lookup(margc, margv) == 0 && lasthostname[0]) { (void) _Strncpy(host, lasthostname, size); domain[0] = '\0'; #ifdef HAS_DOMAINNAME /* getdomainname() returns just the domain name, without a * preceding period. For example, on "cse.unl.edu", it would * return "unl.edu". * * SunOS note: getdomainname will return an empty string if * this machine isn't on NIS. */ (void) getdomainname(domain, sizeof(domain) - 1); #endif #ifdef DOMAIN_NAME (void) Strncpy(domain, DOMAIN_NAME); #endif if (index(host, '.') == NULL) { /* If the hostname has periods we'll assume that the * it includes the domain name already. Some gethostname()s * return the whole host name, others just the machine name. * If we have just the machine name and we successfully * found out the domain name (from above), we'll append * the domain to the machine to get a full hostname. */ if (domain[0]) { if (domain[0] != '.') (void) _Strncat(host, ".", size); (void) _Strncat(host, domain, size); } else { fprintf(stderr, "WARNING: could not determine full host name (have: '%s').\n\ The program should be re-compiled with DOMAIN_NAME defined to be the\n\ domain name, i.e. -DDOMAIN_NAME=\\\"unl.edu\\\"\n\n", host); } } } verbose = oldv; } return r; #endif } /* getlocalhostname */ /* * show status on remote machine */ int rmtstatus(int argc, char **argv) { string str; if (argc > 1) { (void) sprintf(str, "STAT %s" , argv[1]); (void) verbose_command(str); } else (void) verbose_command("STAT"); return NOERR; } /* rmtstatus */ /* * create an empty file on remote machine. */ int create(int argc, char **argv) { string str; FILE *ftemp; if (argc < 2) argv = re_makeargv("(remote-file) ", &argc); if (argc < 2) { return USAGE; } (void) tmp_name(str); ftemp = fopen(str, "w"); /* (void) fputc('x', ftemp); */ (void) fclose(ftemp); creating = 1; (void) sendrequest("STOR", str, argv[1]); creating = 0; (void) unlink(str); return NOERR; } /* create */ /* show version info */ /*ARGSUSED*/ int show_version(int argc, char **argv) { char *DStrs[80]; int nDStrs = 0, i, j; (void) printf("%-30s %s\n", "NcFTP Version:", version); (void) printf("%-30s %s\n", "Author:", "Mike Gleason, NCEMRSoft (mgleason@cse.unl.edu)."); /* Now entering CPP hell... */ #ifdef __DATE__ (void) printf("%-30s %s\n", "Compile Date:", __DATE__); #endif (void) printf("%-30s %s (%s)\n", "Operating System:", #ifdef System System, #else # ifdef unix "UNIX", # else "??", # endif #endif #ifdef SYSV "SYSV"); #else # ifdef BSD "BSD"); # else "neither BSD nor SYSV?"); # endif #endif /* Show which CPP symbols were used in compilation. */ #ifdef __GNUC__ DStrs[nDStrs++] = "__GNUC__"; #endif #ifdef RINDEX DStrs[nDStrs++] = "RINDEX"; #endif #ifdef CURSES DStrs[nDStrs++] = "CURSES"; #endif #ifdef NO_CURSES_H DStrs[nDStrs++] = "NO_CURSES_H"; #endif #ifdef HERROR DStrs[nDStrs++] = "HERROR"; #endif #ifdef U_WAIT DStrs[nDStrs++] = "U_WAIT"; #endif #if defined(NO_CONST) || defined(const) DStrs[nDStrs++] = "NO_CONST"; #endif #ifdef NO_FORMATTING DStrs[nDStrs++] = "NO_FORMATTING"; #endif #ifdef DONT_TIMESTAMP DStrs[nDStrs++] = "DONT_TIMESTAMP"; #endif #ifdef GETPASS DStrs[nDStrs++] = "GETPASS"; #endif #ifdef HAS_GETCWD DStrs[nDStrs++] = "HAS_GETCWD"; #endif #ifdef GETCWDSIZET DStrs[nDStrs++] = "GETCWDSIZET"; #endif #ifdef HAS_DOMAINNAME DStrs[nDStrs++] = "HAS_DOMAINNAME"; #endif #ifdef DOMAIN_NAME DStrs[nDStrs++] = "DOMAIN_NAME"; #endif #ifdef Solaris DStrs[nDStrs++] = "Solaris"; #endif #ifdef USE_GETPWUID DStrs[nDStrs++] = "USE_GETPWUID"; #endif #ifdef HOSTNAME DStrs[nDStrs++] = "HOSTNAME"; #endif #ifdef SYSDIRH DStrs[nDStrs++] = "SYSDIRH"; #endif #ifdef SYSSELECTH DStrs[nDStrs++] = "SYSSELECTH"; #endif #ifdef TERMH DStrs[nDStrs++] = "TERMH"; #endif #ifdef NO_UNISTDH DStrs[nDStrs++] = "NO_UNISTDH"; #endif #ifdef NO_STDLIBH DStrs[nDStrs++] = "NO_STDLIBH"; #endif #ifdef SYSLOG DStrs[nDStrs++] = "SYSLOG"; #endif #ifdef BAD_INETADDR DStrs[nDStrs++] = "BAD_INETADDR"; #endif #ifdef SGTTYB DStrs[nDStrs++] = "SGTTYB"; #endif #ifdef TERMIOS DStrs[nDStrs++] = "TERMIOS"; #endif #ifdef STRICT_PROTOS DStrs[nDStrs++] = "STRICT_PROTOS"; #endif #ifdef dFTP_PORT DStrs[nDStrs++] = "dFTP_PORT"; #endif #ifdef BROKEN_MEMCPY DStrs[nDStrs++] = "BROKEN_MEMCPY"; #endif #ifdef READLINE DStrs[nDStrs++] = "READLINE"; #endif #ifdef GETLINE DStrs[nDStrs++] = "GETLINE"; #endif #ifdef _POSIX_SOURCE DStrs[nDStrs++] = "_POSIX_SOURCE"; #endif #ifdef _XOPEN_SOURCE DStrs[nDStrs++] = "_XOPEN_SOURCE"; #endif #ifdef NO_TIPS DStrs[nDStrs++] = "NO_TIPS"; #endif #ifdef GZCAT DStrs[nDStrs++] = "GZCAT"; #endif #ifdef LINGER DStrs[nDStrs++] = "LINGER"; #endif #ifdef TRY_NOREPLY DStrs[nDStrs++] = "TRY_NOREPLY"; #endif #ifdef NO_UTIMEH DStrs[nDStrs++] = "NO_UTIMEH"; #endif #ifdef DB_ERRS DStrs[nDStrs++] = "DB_ERRS"; #endif #ifdef NO_VARARGS DStrs[nDStrs++] = "NO_VARARGS"; #endif #ifdef NO_STDARGH DStrs[nDStrs++] = "NO_STDARGH"; #endif #ifdef NO_MKTIME DStrs[nDStrs++] = "NO_MKTIME"; #endif #ifdef NO_STRSTR DStrs[nDStrs++] = "NO_STRSTR"; #endif #ifdef NO_STRFTIME DStrs[nDStrs++] = "NO_STRFTIME"; #endif #ifdef NO_RENAME DStrs[nDStrs++] = "NO_RENAME"; #endif #ifdef TRY_ABOR DStrs[nDStrs++] = "TRY_ABOR"; #endif #ifdef GATEWAY DStrs[nDStrs++] = "GATEWAY"; #endif #ifdef SOCKS DStrs[nDStrs++] = "SOCKS"; #endif #ifdef NET_ERRNO_H DStrs[nDStrs++] = "NET_ERRNO_H"; #endif #ifdef PASSIVEMODE DStrs[nDStrs++] = "PASSIVEMODE"; #endif /* DONE with #ifdefs for now! */ (void) printf ("\nCompile Options:\n"); for (i=j=0; inext; if (a->string) free(a->string); /* free string */ Free(a); /* free node */ a = b; } lshead = lstail = NULL; } /* PurgeLineBuffer */ /*ARGSUSED*/ int ShowLineBuffer(int argc, char **argv) { register struct lslist *a = lshead; int pagemode; FILE *fp; Sig_t oldintp; if (a == NULL) return CMDERR; pagemode= (**argv) == 'p' && pager[0] == '|'; if (pagemode) { fp = popen(pager + 1, "w"); if (!fp) { PERROR("ShowLineBuffer", pager + 1); return CMDERR; } } else fp = stdout; oldintp = Signal(SIGPIPE, SIG_IGN); while (a) { if (a->string) (void) fprintf(fp, "%s\n", a->string); a = a->next; } if (pagemode) (void) pclose(fp); if (oldintp) (void) Signal(SIGPIPE, oldintp); return NOERR; } /* ShowLineBuffer */ #if LIBMALLOC != LIBC_MALLOC /*ARGSUSED*/ int MallocStatusCmd(int argc, char **argv) { #if (LIBMALLOC == FAST_MALLOC) struct mallinfo mi; mi = mallinfo(); printf("\ total space in arena: %d\n\ number of ordinary blocks: %d\n\ number of small blocks: %d\n\ number of holding blocks: %d\n\ space in holding block headers: %d\n\ space in small blocks in use: %d\n\ space in free small blocks: %d\n\ space in ordinary blocks in use: %d\n\ space in free ordinary blocks: %d\n\ cost of enabling keep option: %d\n", mi.arena, mi.ordblks, mi.smblks, mi.hblks, mi.hblkhd, mi.usmblks, mi.fsmblks, mi.uordblks, mi.fordblks, mi.keepcost ); #else #if (LIBMALLOC == DEBUG_MALLOC) printf("malloc_chain_check: %d\n\n", malloc_chain_check(0)); if (argc > 1) malloc_dump(1); printf("malloc_inuse: %lu\n", malloc_inuse(NULL)); #else printf("Nothing to report.\n"); #endif /* (LIBMALLOC == DEBUG_MALLOC) */ #endif /* (LIBMALLOC == FAST_MALLOC) */ return (0); } /* MallocStatusCmd */ #endif /* LIBMALLOC */ /*ARGSUSED*/ int unimpl(int argc, char **argv) { if (!parsing_rc) (void) printf("%s: command not supported. (and probably won't ever be).\n", argv[0]); return (NOERR); } /* unimpl */ #ifdef PASSIVEMODE int setpassive(int argc, char **argv) { passivemode = !passivemode; printf( "Passive mode %s.\n", (passivemode ? "ON" : "OFF") ); return NOERR; } #endif /* eof cmds.c */ diff --git a/usr.bin/ncftp/cmds.h b/usr.bin/ncftp/cmds.h index fe1cacc494b2..11dff6acc06d 100644 --- a/usr.bin/ncftp/cmds.h +++ b/usr.bin/ncftp/cmds.h @@ -1,134 +1,134 @@ /* cmds.h */ #ifndef _cmd_h_ #define _cmd_h_ /* $RCSfile: cmds.h,v $ * $Revision: 14020.11 $ * $Date: 93/07/09 10:58:19 $ */ /* Verbosity levels. */ #define V_QUIET -1 #define V_ERRS 0 #define V_TERSE 1 #define V_VERBOSE 2 #define V_IMPLICITCD 4 #define IS_VQUIET (verbose <= V_QUIET) #define IS_VERRS (verbose == V_ERRS) #define IS_VTERSE (verbose == V_TERSE) #define IS_VVERBOSE (verbose == V_VERBOSE) #define NOT_VQUIET (verbose > V_QUIET) /* Open modes. */ #define OPEN_A 1 #define OPEN_U 0 #define LS_FLAGS_AND_FILE '\1' /* Possible values returned by GetDateAndTime. */ #define SIZE_UNKNOWN (-1L) #define MDTM_UNKNOWN (0L) /* Command result codes. */ #define USAGE (88) #define NOERR (0) #define CMDERR (-1) /* * Format of command table. */ struct cmd { char *c_name; /* name of command */ char c_conn; /* must be connected to use command */ char c_hidden; /* a hidden command or alias (won't show up in help) */ int (*c_handler)(int, char **); /* function to call */ char *c_help; /* help string */ char *c_usage; /* usage string or NULL, to ask the function itself. */ }; #define NCMDS ((int) ((sizeof (cmdtab) / sizeof (struct cmd)) - 1)) struct macel { char mac_name[9]; /* macro name */ char *mac_start; /* start of macro in macbuf */ char *mac_end; /* end of macro in macbuf */ }; struct types { char *t_name; char *t_mode; int t_type; char *t_arg; }; struct lslist { char *string; struct lslist *next; }; int settype(int argc, char **argv); int _settype(char *typename); int setbinary(int argc, char **argv); int setascii(int argc, char **argv); int put(int argc, char **argv); int mput(int argc, char **argv); int rem_glob_one(char *pattern); int get(int argc, char **argv); void mabort SIG_PARAMS; int mget(int argc, char **argv); -char *remglob(char *argv[]); +char *remglob(char *argv[], int *); int setverbose(int argc, char **argv); int setprompt(int argc, char **argv); int setdebug(int argc, char **argv); void fix_options(void); int cd(int argc, char **argv); int implicit_cd(char *dir); int _cd(char *dir); int lcd(int argc, char **argv); int do_delete(int argc, char **argv); int mdelete(int argc, char **argv); int renamefile(int argc, char **argv); int ls(int argc, char **argv); int shell(int argc, char **argv); int do_user(int argc, char **argv); int pwd(int argc, char **argv); int makedir(int argc, char **argv); int removedir(int argc, char **argv); int quote(int argc, char **argv); int rmthelp(int argc, char **argv); int quit(int argc, char **argv); void close_streams(int wantShutDown); int disconnect(int argc, char **argv); -void close_up_shop(void); +int close_up_shop(void); int globulize(char **cpp); int cdup(int argc, char **argv); int syst(int argc, char **argv); int make_macro(char *name, FILE *fp); int macdef(int argc, char **argv); int domacro(int argc, char **argv); int sizecmd(int argc, char **argv); int modtime(int argc, char **argv); int lookup(int argc, char **argv); int rmtstatus(int argc, char **argv); int create(int argc, char **argv); int getlocalhostname(char *host, size_t size); int show_version(int argc, char **argv); void PurgeLineBuffer(void); int ShowLineBuffer(int argc, char **argv); int MallocStatusCmd(int argc, char **argv); int unimpl(int argc, char **argv); long GetDateSizeFromLSLine(char *fName, unsigned long *mod_time); long GetDateAndSize(char *fName, unsigned long *mod_time); int SetTypeByNumber(int i); #ifdef PASSIVEMODE int setpassive(int argc, char **argv); #endif /* In util.c: */ void cmd_help(struct cmd *c); void cmd_usage(struct cmd *c); struct cmd *getcmd(char *name); #endif /* _cmd_h_ */ diff --git a/usr.bin/ncftp/defaults.h b/usr.bin/ncftp/defaults.h index 24521959c3cc..f3fbb0814cda 100644 --- a/usr.bin/ncftp/defaults.h +++ b/usr.bin/ncftp/defaults.h @@ -1,130 +1,142 @@ /* Defaults.h: default values for ftp's common variables */ /* These are all surrounded by #ifndef blocks so you can just use * the -D flag with your compiler (i.e. -DZCAT=\"/usr/local/bin/zcat\"). */ #ifndef _DEFAULTS_H_ #define _DEFAULTS_H_ /* $RCSfile: defaults.h,v $ * $Revision: 14020.13 $ * $Date: 93/07/09 10:58:27 $ */ #ifndef NEWMAILMESSAGE /* For english speakers, "You have new mail." */ #define NEWMAILMESSAGE "You have new mail." #endif #ifndef ZCAT /* Usually "zcat," but use the full pathname */ /* if possible. */ # ifdef GZCAT /* If you said you had gnu's zcat, use it * since it can do .Z files too. */ # define ZCAT GZCAT # else /* !GZCAT */ # define ZCAT "zcat" # endif /* ifdef GZCAT */ #endif /* ifndef ZCAT */ #ifndef MAX_XFER_BUFSIZE #define MAX_XFER_BUFSIZE 32768 #endif #ifndef dANONOPEN /* 1 or 0, usually 1 */ #define dANONOPEN 1 #endif #ifndef dDEBUG /* 1 or 0, usually 0 */ #define dDEBUG 0 #endif #ifndef dMPROMPT /* Usually 1, I prefer 0... */ #define dMPROMPT 0 #endif +#ifndef PASSIVEMODE +#define PASSIVEMODE 1 +#endif + +/* If passive FTP can be used, this specifies whether it is turned on + * by default. If not, we have passive mode available, but are using + * Port ftp by default. + */ +#ifndef dPASSIVE +#define dPASSIVE 1 /* Works for most folks... */ +#endif + #ifndef dVERBOSE /* V_QUIET, V_ERRS, V_TERSE, V_VERBOSE */ #define dVERBOSE V_TERSE #endif #ifndef dPROMPT /* short: "@Bftp@P>" */ /* long: "@B@E @UNcFTP@P @B@M@D@P ->" */ #define dPROMPT "@B@c@Mncftp@P>" /* new two line prompt */ #endif #ifndef dPAGER /* if set to empty string, act like 'cat' */ #define dPAGER "more" #endif #ifndef dLOGNAME /* usu. put in the user's home directory. */ #define dLOGNAME "~/.ftplog" #endif #ifndef dRECENTF /* usu. put in the user's home directory. */ #define dRECENTF "~/.ncrecent" #endif #ifndef dMAXRECENTS /* limit to how many recent sites to save. */ #define dMAXRECENTS 50 #endif #ifndef dRECENT_ON /* Do you want the recent log on? */ /* usually 1. */ #define dRECENT_ON 1 #endif /* Do you want logging on by default? */ #ifndef dLOGGING /* usually 0 */ #define dLOGGING 0 #endif #ifndef dTYPE /* usually TYPE_A */ #define dTYPE TYPE_A #endif #ifndef dTYPESTR /* usually "ascii" */ #define dTYPESTR "ascii" #endif #ifndef dREDIALDELAY /* usu. 60 (seconds). */ #define dREDIALDELAY 60 #endif #ifndef CMDLINELEN #define CMDLINELEN 256 #endif #ifndef RECEIVEDLINELEN #define RECEIVEDLINELEN 256 #endif #ifndef MAXMACROS #define MAXMACROS 16 #endif #ifndef MACBUFLEN /* usually 4096. */ #define MACBUFLEN 4096 #endif /* Do you want binary transfers by default? */ #ifndef dAUTOBINARY /* usually 1 */ #define dAUTOBINARY 1 #endif #ifndef dPROGRESS #define dPROGRESS pr_philbar /* can be: pr_none, pr_percent, pr_philbar, * or pr_kbytes */ #endif /* Default login name at gateway */ #ifdef GATEWAY # ifndef dGATEWAY_LOGIN # define dGATEWAY_LOGIN "ftp" # endif #endif #endif /* _DEFAULTS_H_ */ /* eof */ diff --git a/usr.bin/ncftp/ftprc.c b/usr.bin/ncftp/ftprc.c index e8380cef6e0e..c048852f16fd 100644 --- a/usr.bin/ncftp/ftprc.c +++ b/usr.bin/ncftp/ftprc.c @@ -1,612 +1,615 @@ /* ftprc.c */ /* $RCSfile: ftprc.c,v $ * $Revision: 14020.11 $ * $Date: 93/07/09 10:58:37 $ */ #include "sys.h" #include #include #include #include "util.h" #include "ftprc.h" #include "main.h" #include "cmds.h" #include "set.h" #include "defaults.h" #include "copyright.h" /* ftprc.c global variables */ siteptr firstsite = NULL, lastsite = NULL; recentsite recents[dMAXRECENTS]; int nRecents = 0; int nSites = 0; int keep_recent = dRECENT_ON; longstring rcname; longstring recent_file; int parsing_rc = 0; extern char *line, *margv[]; extern int margc, fromatty; extern string anon_password; /* most likely your email address */ extern string pager; extern struct userinfo uinfo; int thrash_rc(void) { struct stat st; string word, str; longstring cwd; char *cp, *dp, *rc; FILE *fp; int i; (void) get_cwd(cwd, sizeof(cwd)); if (cwd[strlen(cwd) - 1] != '/') (void) Strncat(cwd, "/"); /* Because some versions of regular ftp complain about ncftp's * #set commands, FTPRC takes precedence over NETRC. */ cp = getenv("DOTDIR"); for (i=0; i<2; i++) { rc = (i == 0) ? FTPRC : NETRC; (void) sprintf(rcname, "%s%s", cwd, rc); if (stat(rcname, &st) == 0) goto foundrc; (void) sprintf(rcname, "%s.%s", cwd, rc); if (stat(rcname, &st) == 0) goto foundrc; if (cp != NULL) { (void) sprintf(rcname, "%s/.%s", cp, rc); if (stat(rcname, &st) == 0) goto foundrc; } (void) sprintf(rcname, "%s/.%s", uinfo.homedir, rc); if (stat(rcname, &st) == 0) goto foundrc; } return (0); /* it's OK not to have an rc. */ foundrc: if ((st.st_mode & 077) != 0) /* rc must be unreadable by others. */ (void) chmod(rcname, 0600); if ((fp = fopen(rcname, "r")) == NULL) { PERROR("thrash_rc", rcname); return -1; } parsing_rc = 1; while ((cp = FGets(str, fp)) != 0) { while (isspace(*cp)) ++cp; /* skip leading space. */ if (*cp == '#') { if ((strncmp("set", ++cp, (size_t)3) == 0) || (strncmp("unset", cp, (size_t)5) == 0)) { (void) strcpy(line, cp); makeargv(); (void) set(margc, margv); /* setting or unsetting a variable. */ } /* else a comment. */ } else { if (strncmp(cp, "machine", (size_t) 7) == 0) { /* We have a new machine record. */ cp += 7; while (isspace(*cp)) ++cp; /* skip delimiting space. */ dp = word; while (*cp && !isspace(*cp)) *dp++ = *cp++; /* copy the name. */ *dp = 0; AddNewSitePtr(word); } } } (void) fclose(fp); parsing_rc = 0; return 1; } /* thrash_rc */ void AddNewSitePtr(char *word) { siteptr s; if ((s = (siteptr) malloc(sizeof(site))) != 0) { s->next = NULL; if ((s->name = malloc(strlen(word) + 1)) != 0) { (void) strcpy(s->name, word); if (firstsite == NULL) firstsite = lastsite = s; else { lastsite->next = s; lastsite = s; } ++nSites; } else { Free(s); } } } /* AddNewSitePtr */ static int RecentCmp(recentsite *a, recentsite *b) { int i = 1; if (a->lastcall > b->lastcall) i = -1; else if (a->lastcall == b->lastcall) i = 0; return i; } /* RecentCmp */ static siteptr FindNetrcSite(char *host, int exact) { register siteptr s, s2; string str, host2; (void) Strncpy(host2, host); StrLCase(host2); /* see if 'host' is in our list of favorite sites (in NETRC). */ for (s = firstsite; s != NULL; s2=s->next, s=s2) { (void) Strncpy(str, s->name); StrLCase(str); if (exact) { if (strcmp(str, host2) == 0) return s; } else { if (strstr(str, host2) != NULL) return s; } } return NULL; } /* FindNetrcSite */ static recentsite *FindRecentSite(char *host, int exact) { register recentsite *r; register int i; string str, host2; (void) Strncpy(host2, host); StrLCase(host2); /* see if 'host' is in our list of favorite sites (in recent-log). */ for (i=0; iname); StrLCase(str); if (exact) { if (strcmp(str, host2) == 0) return r; } else { if (strstr(str, host2) != NULL) return r; } } return NULL; } /* FindRecentSite */ void ReadRecentSitesFile(void) { FILE *rfp; recentsite *r; char name[64]; int offset; longstring str; nRecents = 0; if (recent_file[0] != 0 && keep_recent) { rfp = fopen(recent_file, "r"); if (rfp != NULL) { for (; nRecents < dMAXRECENTS; ) { r = &recents[nRecents]; if (FGets(str, rfp) == NULL) break; (void) RemoveTrailingNewline(str, NULL); name[0] = 0; offset = 45; if (sscanf(str, "%s %lu %n", name, (unsigned long *) &r->lastcall, &offset) >= 2) { if ((r->name = NewString(name)) != NULL) { r->dir = NewString(str + offset); if (r->dir != NULL) nRecents++; else { free(r->name); r->name = r->dir = NULL; } } } } (void) fclose(rfp); } } } /* ReadRecentSitesFile */ static void SortRecentList(void) { QSort(recents, nRecents, sizeof(recentsite), RecentCmp); } /* SortRecentList */ -void WriteRecentSitesFile(void) +int WriteRecentSitesFile(void) { FILE *rfp; recentsite *r; int i; + int retcode = 0; if ((recent_file[0] != 0) && (nRecents > 0) && (keep_recent)) { dbprintf("Attempting to write %s...\n", recent_file); rfp = fopen(recent_file, "w"); if (rfp != NULL) { SortRecentList(); for (i=0; iname, (unsigned long) r->lastcall, r->dir); } (void) fclose(rfp); dbprintf("%s written successfully.\n", recent_file); (void) chmod(recent_file, 0600); } else { perror(recent_file); + ++retcode; } } + return retcode; } /* WriteRecentSitesFile */ void AddRecentSite(char *host, char *lastdir) { char *nhost, *ndir; recentsite *r; if (keep_recent) { nhost = NewString(host); /* Use '/' to denote that the current directory wasn't known, * because we won't try to cd to the root directory. */ ndir = NewString(*lastdir ? lastdir : "/"); /* Don't bother if we don't have the memory, or if it is already * in our NETRC. */ if ((ndir != NULL) && (nhost != NULL) && (FindNetrcSite(host, 1) == NULL)) { if (nRecents == dMAXRECENTS) { SortRecentList(); r = &recents[dMAXRECENTS - 1]; if (r->name != NULL) free(r->name); if (r->dir != NULL) free(r->dir); } else { r = &recents[nRecents]; nRecents++; } r->name = nhost; r->dir = ndir; (void) time(&r->lastcall); SortRecentList(); } } } /* AddRecentSite */ /* * After you are done with a site (by closing it or quitting), we * need to update the list of recent sites called. */ void UpdateRecentSitesList(char *host, char *lastdir) { recentsite *r; char *ndir; if (keep_recent) { r = FindRecentSite(host, 1); if (r == NULL) AddRecentSite(host, lastdir); else { /* Update the last time connected, and the directory we left in. */ if ((ndir = NewString(*lastdir ? lastdir : "/")) != NULL) { free(r->dir); r->dir = ndir; } (void) time(&r->lastcall); } } } /* UpdateRecentSitesList */ /* * Prints out the number of sites we know about, so the user can figure out * an abbreviation or type it's number to open (setpeer). */ void PrintSiteList(void) { int i, j; siteptr s, s2; FILE *pagerfp; Sig_t sigpipe; if (fromatty) { j = 0; i = 1; sigpipe = Signal(SIGPIPE, SIG_IGN); if ((pagerfp = popen(pager + 1, "w")) == NULL) pagerfp = stdout; if (nRecents > 0) { j++; (void) fprintf(pagerfp, "\nRecently called sites:\n"); for (; i<=nRecents; i++) { (void) fprintf(pagerfp, "%4d. %-32s", i, recents[i-1].name); i++; if (i <= nRecents) { (void) fprintf(pagerfp, "%5d. %-32s", i, recents[i-1].name); } else { (void) fprintf(pagerfp, "\n"); break; } (void) fprintf(pagerfp, "\n"); } } if (nSites > 0) { j++; (void) fprintf(pagerfp, "Sites in your netrc (%s):\n", rcname); for (s = firstsite; s != NULL; s2=s->next, s=s2, ++i) { (void) fprintf(pagerfp, "%4d. %-32s", i, s->name); s2=s->next; s=s2; i++; if (s != NULL) { (void) fprintf(pagerfp, "%5d. %-32s", i, s->name); } else { (void) fprintf(pagerfp, "\n"); break; } (void) fprintf(pagerfp, "\n"); } } if (j > 0) { (void) fprintf(pagerfp, "\ Note that you can specify an abbreviation of any name, or #x, where x is the\n\ number of the site you want to connect to.\n\n"); } if (pagerfp != stdout) (void) pclose(pagerfp); Signal(SIGPIPE, sigpipe); } } /* PrintRecentSiteList */ /* * Given a sitename, check to see if the name was really an abbreviation * of a site in the NETRC, or a site in our list of recently connected * sites. Also check if the name was in the format #x, where x which * would mean to use recents[x].name as the site; if x was greater than * the number of sites in the recent list, then index into the netrc * site list. */ #include void GetFullSiteName(char *host, char *lastdir) { register siteptr s, s2; register recentsite *r; char *ndir, *nhost, *cp; int x, i, isAllDigits, exact; struct hostent *hostentp; ndir = nhost = NULL; x = exact = 0; /* First, see if the "abbreviation" is really just the name of * a machine in the local domain, or if it was a full hostname * already. That way we can avoid problems associated with * short names, such as having "ce" as a machine in the local * domain, but having "faces.unl.edu", where we would most likely * want to use ce instead of faces if the user said "open ce". * This will also prevent problems when you have a host named * xx.yy.unl.edu, and another host named yy.unl.edu. If the user * said "open yy.unl.edu" we should use yy.unl.edu, and not look * for matches containing yy.unl.edu. */ if ((hostentp = gethostbyname(host)) != NULL) { strcpy(host, hostentp->h_name); exact = 1; } /* Don't allow just numbers as abbreviations; "open 2" could be * confused between site numbers in the open 'menu,' like * "2. unlinfo.unl.edu" and IP numbers "128.93.2.1" or even numbers * in the site name like "simtel20.army.mil." */ for (isAllDigits = 1, cp = host; *cp != 0; cp++) { if (!isdigit(*cp)) { isAllDigits = 0; break; } } if (!isAllDigits) { if (host[0] == '#') (void) sscanf(host + 1, "%d", &x); /* Try matching the abbreviation, since it isn't just a number. */ /* see if 'host' is in our list of favorite sites (in NETRC). */ if (x == 0) { if ((s = FindNetrcSite(host, exact)) != NULL) { nhost = s->name; } else if ((r = FindRecentSite(host, exact)) != NULL) { nhost = r->name; ndir = r->dir; } } } else if (sscanf(host, "%d", &x) != 1) { x = 0; } if (--x >= 0) { if (x < nRecents) { nhost = recents[x].name; ndir = recents[x].dir; } else { x -= nRecents; if (x < nSites) { for (i = 0, s = firstsite; i < x; s2=s->next, s=s2) ++i; nhost = s->name; } } } if (nhost != NULL) { (void) strcpy(host, nhost); if (lastdir != NULL) { *lastdir = 0; /* Don't cd if the dir is the root directory. */ if (ndir != NULL && (strcmp("/", ndir) != 0)) (void) strcpy(lastdir, ndir); } } } /* GetFullSiteName */ int ruserpass2(char *host, char **username, char **pass, char **acct) { FILE *fp; char *cp, *dp, *dst, *ep; str32 macname; char *varname; int site_found; string str; static string auser; static str32 apass, aacct; site_found = 0; if ((fp = fopen(rcname, "r")) != NULL) { parsing_rc = 1; while (FGets(str, fp)) { if ((cp = strstr(str, "machine")) != 0) { /* Look for the machine token. */ cp += 7; while (isspace(*cp)) cp++; } else continue; if (strncmp(host, cp, strlen(host)) == 0) { site_found = 1; while (!isspace(*cp)) ++cp; /* skip the site name. */ do { /* Skip any comments ahead of time. */ for (dp=cp; *dp; dp++) { if (*dp == '#') { *dp = 0; break; } } ep = cp; while (1) { varname = strtok(ep, RC_DELIM); if (!varname) break; dst = ep = NULL; switch (*varname) { case 'u': /* user */ *username = dst = auser; break; case 'l': /* login */ *username = dst = auser; break; case 'p': /* password */ *pass = dst = apass; break; case 'a': /* account */ *acct = dst = aacct; break; /* case 'd': /o default */ /* unused -- use 'set anon_password.' */ case 'm': /* macdef or machine */ if (strcmp(varname, "macdef")) goto done; /* new machine record... */ dst = macname; break; default: (void) fprintf(stderr, "Unknown .netrc keyword \"%s\"\n", varname ); } if (dst) { dp = strtok(ep, RC_DELIM); if (dp) (void) strcpy(dst, dp); if (dst == macname) { /* * Read in the lines of the macro. * The macro's end is denoted by * a blank line. */ (void) make_macro(macname, fp); goto nextline; } } } nextline: ; } while ((cp = FGets(str, fp)) != 0); break; } /* end if we found the machine record. */ } done: parsing_rc = 0; (void) fclose(fp); } if (!site_found) { /* didn't find it in the rc. */ return (0); } return (1); /* found */ } /* ruserpass2 */ /* eof ftprc.c */ diff --git a/usr.bin/ncftp/ftprc.h b/usr.bin/ncftp/ftprc.h index 14eec88ad860..eed0217ea721 100644 --- a/usr.bin/ncftp/ftprc.h +++ b/usr.bin/ncftp/ftprc.h @@ -1,39 +1,39 @@ /* ftprc.h */ #ifndef _ftprc_h_ #define _ftprc_h_ /* $RCSfile: ftprc.h,v $ * $Revision: 14020.11 $ * $Date: 93/05/21 05:45:31 $ */ #define NETRC "netrc" #define FTPRC "ncftprc" #define RC_DELIM " \n\t," typedef struct site *siteptr; typedef struct site { char *name; /* name (or IP address) of site */ siteptr next; } site; typedef struct recentsite { char *name; /* name (or IP address) of site */ char *dir; /* directory we were in last time we called. */ time_t lastcall; /* when this site was called last. */ } recentsite; int thrash_rc(void); void AddNewSitePtr(char *word); int ruserpass2(char *host, char **user, char **pass, char **acct); void GetFullSiteName(char *host, char *lastdir); void ReadRecentSitesFile(void); -void WriteRecentSitesFile(void); +int WriteRecentSitesFile(void); void AddRecentSite(char *host, char *lastdir); void UpdateRecentSitesList(char *host, char *lastdir); void PrintSiteList(void); #endif /* eof */ diff --git a/usr.bin/ncftp/main.c b/usr.bin/ncftp/main.c index d51d384e8cf2..9fdfc06ec0a5 100644 --- a/usr.bin/ncftp/main.c +++ b/usr.bin/ncftp/main.c @@ -1,1128 +1,1135 @@ -/* main.c - * - * $RCSfile: main.c,v $ - * $Revision: 14020.15 $ - * $Date: 93/07/09 11:50:12 $ - */ +/* main.c */ #define _main_c_ -#define FTP_VERSION "1.8.6 (Octboer 30, 1994)" +#define FTP_VERSION "1.8.7 (December 11, 1994)" /* #define BETA 1 */ /* If defined, it prints a little warning message. */ #include "sys.h" #include #include #include #include #include #include #include #include #ifdef SYSLOG # include #endif #if defined(CURSES) && !defined(NO_CURSES_H) # undef HZ /* Collides with HaZeltine ! */ # include # ifdef TERMH # include # endif #endif /* CURSES */ #include "util.h" #include "cmds.h" #include "main.h" #include "ftp.h" #include "ftprc.h" #include "open.h" #include "set.h" #include "defaults.h" #include "copyright.h" /* main.c globals */ int slrflag; int fromatty; /* input is from a terminal */ int toatty; /* output is to a terminal */ int doing_script; /* is a file being = 0) { + while ((opt = Getopt(argc, argv, "D:V:INPRHaicmup:rd:g:")) >= 0) { switch(opt) { case 'a': case 'c': case 'i': case 'm': case 'u': case 'r': (void) sprintf(tmp, "-%c ", opt); goto cattmp; case 'p': case 'd': case 'g': (void) sprintf(tmp, "-%c %s ", opt, Optarg); cattmp: (void) strcat(oline, tmp); openopts++; break; case 'D': debug = atoi(Optarg); break; case 'V': set_verbose(Optarg, 0); break; case 'I': mprompt = !mprompt; break; case 'N': ++ignore_rc; break; + case 'P': + passivemode = !passivemode; + break; + case 'H': (void) show_version(0, NULL); exit (0); default: usage: (void) fprintf(stderr, "Usage: %s [program options] [[open options] site.to.open[:path]]\n\ Program Options:\n\ -D x : Set debugging level to x (a number).\n\ -H : Show version and compilation information.\n\ -I : Toggle interactive (mprompt) mode.\n\ -N : Toggle reading of the .netrc/.ncftprc.\n\ + -P : Toggle passive mode ftp (for use behind firewalls).\n\ -V x : Set verbosity to level x (-1,0,1,2).\n\ Open Options:\n\ -a : Open anonymously (this is the default).\n\ -u : Open, specify user/password.\n\ -i : Ignore machine entry in your .netrc.\n\ -p N : Use port #N for connection.\n\ -r : \"Redial\" until connected.\n\ -d N : Redial, pausing N seconds between tries.\n\ -g N : Redial, giving up after N tries.\n\ :path : ``Colon-mode:'' If \"path\" is a file, it opens site, retrieves\n\ file \"path,\" then exits; if \"path\" is a remote directory,\n\ it opens site then starts you in that directory..\n\ -c : If you're using colon-mode with a file path, this will cat the\n\ file to stdout instead of storing on disk.\n\ -m : Just like -c, only it pipes the file to your $PAGER.\n\ Examples:\n\ ncftp ftp.unl.edu:/pub/README (just fetches README then quits)\n\ ncftp (just enters ncftp command shell)\n\ ncftp -V -u ftp.unl.edu\n\ ncftp -c ftp.unl.edu:/pub/README (cats README to stdout then quits)\n\ ncftp -D -r -d 120 -g 10 ftp.unl.edu\n", progname); exit(1); } } cp = argv[Optind]; /* the site to open. */ if (cp == NULL) { if (openopts) goto usage; } else (void) strcat(oline, cp); if (ignore_rc <= 0) (void) thrash_rc(); if (ignore_rc <= 1) ReadRecentSitesFile(); (void) fix_options(); /* adjust "options" according to "debug" */ fromatty = doing_script = isatty(0); toatty = isatty(1); (void) UserLoggedIn(); /* Init parent-death detection. */ cpend = 0; /* no pending replies */ if (*logfname) logf = fopen (logfname, "a"); /* The user specified a host, maybe in 'colon-mode', on the command * line. Open it now... */ if (argc > 1 && cp) { if (setjmp(toplevel)) exit(0); (void) Signal(SIGINT, intr); (void) Signal(SIGPIPE, lostpeer); (void) strcpy(line, oline); makeargv(); /* setpeer uses this to tell if it was called from the cmd-line. */ eventnumber = 0L; (void) cmdOpen(margc, margv); } eventnumber = 1L; (void) init_prompt(); if (startup_msg) { /* TAR */ if (ansi_escapes) { #ifdef BETA # define BETA_MSG "\n\ For testing purposes only. Do not re-distribute or subject to novice users." #else # define BETA_MSG "" #endif #ifndef CURSES (void) printf("%sNcFTP %s by Mike Gleason, NCEMRSoft.%s%s%s%s\n", tcap_boldface, FTP_VERSION, tcap_normal, tcap_reverse, BETA_MSG, tcap_normal ); #else char vis[256]; (void) sprintf(vis, "%sNcFTP %s by Mike Gleason, NCEMRSoft.%s%s%s%s\n", tcap_boldface, FTP_VERSION, tcap_normal, tcap_reverse, BETA_MSG, tcap_normal ); tcap_put(vis); #endif /* !CURSES */ } else (void) printf("%s%s\n", FTP_VERSION, BETA_MSG); } /* TAR */ if (NOT_VQUIET) PrintTip(); top = setjmp(toplevel) == 0; if (top) { (void) Signal(SIGINT, intr); (void) Signal(SIGPIPE, lostpeer); } for (;;) { - (void) cmdscanner(top); + if (cmdscanner(top)) + exit(1); top = 1; } } /* main */ /*ARGSUSED*/ void intr SIG_PARAMS { dbprintf("intr()\n"); (void) Signal(SIGINT, intr); (void) longjmp(toplevel, 1); } /* intr */ int getuserinfo(void) { register char *cp; struct passwd *pw; string str; extern char *home; /* for glob.c */ home = uinfo.homedir; /* for glob.c */ pw = NULL; #ifdef USE_GETPWUID /* Try to use getpwuid(), but if we have to, fall back to getpwnam(). */ pw = getpwuid(getuid()); if (pw == NULL) { /* Oh well, try getpwnam() then. */ cp = getlogin(); if (cp == NULL) { cp = getenv("LOGNAME"); if (cp == NULL) cp = getenv("USER"); } if (cp != NULL) pw = getpwnam(cp); } #else /* Try to use getpwnam(), but if we have to, fall back to getpwuid(). */ cp = getlogin(); if (cp == NULL) { cp = getenv("LOGNAME"); if (cp == NULL) cp = getenv("USER"); } if (cp != NULL) pw = getpwnam(cp); if (pw == NULL) { /* Oh well, try getpwuid() then. */ pw = getpwuid(getuid()); } #endif if (pw != NULL) { uinfo.uid = pw->pw_uid; (void) Strncpy(uinfo.username, pw->pw_name); (void) Strncpy(uinfo.shell, pw->pw_shell); if ((cp = getenv("HOME")) != NULL) (void) Strncpy(uinfo.homedir, cp); else (void) Strncpy(uinfo.homedir, pw->pw_dir); cp = getenv("MAIL"); if (cp == NULL) cp = getenv("mail"); if (cp == NULL) (void) sprintf(str, "/usr/spool/mail/%s", uinfo.username); else (void) Strncpy(str, cp); cp = str; /* * mbox variable may be like MAIL=(28 /usr/mail/me /usr/mail/you), * so try to find the first mail path. */ while ((*cp != '/') && (*cp != 0)) cp++; (void) Strncpy(mail_path, cp); if ((cp = index(mail_path, ' ')) != NULL) *cp = '\0'; return (0); } else { PERROR("getuserinfo", "Could not get your passwd entry!"); (void) Strncpy(uinfo.shell, "/bin/sh"); (void) Strncpy(uinfo.homedir, "."); /* current directory */ uinfo.uid = 999; if ((cp = getenv("HOME")) != NULL) (void) Strncpy(uinfo.homedir, cp); mail_path[0] = 0; return (-1); } } /* getuserinfo */ int init_arrays(void) { if ((macbuf = (char *) malloc((size_t)(MACBUFLEN))) == NULL) goto barf; if ((line = (char *) malloc((size_t)(CMDLINELEN))) == NULL) goto barf; if ((argbuf = (char *) malloc((size_t)(CMDLINELEN))) == NULL) goto barf; if ((reply_string = (char *) malloc((size_t)(RECEIVEDLINELEN))) == NULL) goto barf; *macbuf = '\0'; init_transfer_buffer(); return (0); barf: return (-1); } /* init_arrays */ #ifndef BUFSIZ #define BUFSIZ 512 #endif void init_transfer_buffer(void) { extern char *xferbuf; extern size_t xferbufsize; /* Make sure we use a multiple of BUFSIZ for efficiency. */ xferbufsize = (MAX_XFER_BUFSIZE / BUFSIZ) * BUFSIZ; while (1) { xferbuf = (char *) malloc (xferbufsize); if (xferbuf != NULL || xferbufsize < 1024) break; xferbufsize >>= 2; } if (xferbuf != NULL) return; fatal("out of memory for transfer buffer."); } /* init_transfer_buffer */ void init_prompt(void) { register char *cp; percent_flags = at_flags = 0; for (cp = prompt; *cp; cp++) { if (*cp == '%') percent_flags = 1; else if (*cp == '@') at_flags = 1; } } /* init_prompt */ /*ARGSUSED*/ void lostpeer SIG_PARAMS { if (connected) { close_streams(1); if (data >= 0) { (void) shutdown(data, 1+1); (void) close(data); data = -1; } connected = 0; } if (connected) { close_streams(1); connected = 0; } hostname[0] = cwd[0] = 0; logged_in = macnum = 0; } /* lostpeer */ /* * Command parser. */ -void cmdscanner(int top) +int cmdscanner(int top) { register struct cmd *c; + int cmd_status, rcode = 0; if (!top) (void) putchar('\n'); for (;;) { if (!doing_script && !UserLoggedIn()) (void) quit(0, NULL); if (Gets(strprompt(), line, (size_t)CMDLINELEN) == NULL) { (void) quit(0, NULL); /* control-d */ } eventnumber++; dbprintf("\"%s\"\n", line); (void) makeargv(); if (margc == 0) { continue; /* blank line... */ } c = getcmd(margv[0]); if (c == (struct cmd *) -1) { (void) printf("?Ambiguous command\n"); continue; } if (c == 0) { if (!implicit_cd(margv[0])) (void) printf("?Invalid command\n"); continue; } if (c->c_conn && !connected) { (void) printf ("Not connected.\n"); continue; } - if ((*c->c_handler)(margc, margv) == USAGE) + cmd_status = (*c->c_handler)(margc, margv); + if (cmd_status == USAGE) cmd_usage(c); + else if (cmd_status == CMDERR) + rcode = 1; if (c->c_handler != help) break; } (void) Signal(SIGINT, intr); (void) Signal(SIGPIPE, lostpeer); + return rcode; } /* cmdscanner */ char *strprompt(void) { time_t tyme; char eventstr[8]; char *dname, *lastlinestart; register char *p, *q; string str; int flag; if (at_flags == 0 && percent_flags == 0) { epromptlen = strlen(prompt); return (prompt); /* But don't overwrite it! */ } epromptlen = 0; lastlinestart = prompt2; if (at_flags) { for (p = prompt, q = prompt2, *q = 0; (*p); p++) { if (*p == '@') switch (flag = *++p) { case '\0': --p; break; case 'M': if (CheckNewMail() > 0) q = Strpcpy(q, "(Mail) "); break; case 'N': q = Strpcpy(q, "\n"); lastlinestart = q; epromptlen = 0; break; case 'P': /* reset to no bold, no uline, no inverse, etc. */ if (ansi_escapes) { q = Strpcpy(q, tcap_normal); epromptlen += tcl_normal; } break; case 'B': /* toggle boldface */ if (ansi_escapes) { q = Strpcpy(q, tcap_boldface); epromptlen += tcl_bold; } break; case 'U': /* toggle underline */ if (ansi_escapes) { q = Strpcpy(q, tcap_underline); epromptlen += tcl_uline; } break; case 'R': case 'I': /* toggle inverse (reverse) video */ if (ansi_escapes) { q = Strpcpy(q, tcap_reverse); epromptlen += tcl_rev; } break; case 'D': /* insert current directory */ case 'J': if ((flag == 'J') && (remote_is_unix)) { /* Not the whole path, just the dir name. */ dname = rindex(cwd, '/'); if (dname == NULL) dname = cwd; else if ((dname != cwd) && (dname[1])) ++dname; } else dname = cwd; if (dname[0]) { q = Strpcpy(q, dname); q = Strpcpy(q, " "); } break; case 'H': /* insert name of connected host */ if (logged_in) { (void) sprintf(str, "%s ", hostname); q = Strpcpy(q, str); } break; case 'C': /* Insert host:path (colon-mode format. */ if (logged_in) { (void) sprintf(str, "%s:%s ", hostname, cwd); q = Strpcpy(q, str); } else q = Strpcpy(q, "(not connected)"); break; case 'c': if (logged_in) { (void) sprintf(str, "%s:%s\n", hostname, cwd); q = Strpcpy(q, str); lastlinestart = q; /* there is a \n at the end. */ epromptlen = 0; } break; case '!': case 'E': /* insert event number */ (void) sprintf(eventstr, "%ld", eventnumber); q = Strpcpy(q, eventstr); break; default: *q++ = *p; /* just copy it; unknown switch */ } else *q++ = *p; } *q = '\0'; } else (void) strcpy(prompt2, prompt); #ifndef NO_STRFTIME if (percent_flags) { /* only strftime if the user requested it (with a %something), otherwise don't waste time doing nothing. */ (void) time(&tyme); (void) Strncpy(str, prompt2); (void) strftime(prompt2, sizeof(str), str, localtime(&tyme)); } #endif epromptlen = (size_t) ((long) strlen(lastlinestart) - (long) epromptlen); return (prompt2); } /* strprompt */ /* * Slice a string up into argc/argv. */ 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()) != 0) margc++; } /* makeargv */ /* * Parse string into argbuf; * implemented with FSM to * handle quoting and strings */ char *slurpstring(void) { int got_one = 0; register char *sb = stringbase; register 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': case '\n': case '=': 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 '\n': case '=': 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); } /* slurpstring */ /* * Help command. * Call each command handler with argc == 0 and argv[0] == name. */ int help(int argc, char **argv) { register struct cmd *c; int showall = 0, helpall = 0; char *arg; int i, j, k; int nRows, nCols; int nCmds2Print; int screenColumns; int len, widestName; char *cp, **cmdnames, spec[16]; if (argc == 2) { showall = (strcmp(argv[1], "showall") == 0); helpall = (strcmp(argv[1], "helpall") == 0); } if (argc == 1 || showall) { (void) printf("\ Commands may be abbreviated. 'help showall' shows aliases, invisible and\n\ unsupported commands. 'help ' gives a brief description of .\n\n"); for (c = cmdtab, nCmds2Print=0; c->c_name != NULL; c++) if (!c->c_hidden || showall) nCmds2Print++; if ((cmdnames = (char **) malloc(sizeof(char *) * nCmds2Print)) == NULL) fatal("out of memory!"); for (c = cmdtab, i=0, widestName=0; c->c_name != NULL; c++) { if (!c->c_hidden || showall) { cmdnames[i++] = c->c_name; len = (int) strlen(c->c_name); if (len > widestName) widestName = len; } } if ((cp = getenv("COLUMNS")) == NULL) screenColumns = 80; else screenColumns = atoi(cp); widestName += 2; /* leave room for white-space in between cols. */ nCols = screenColumns / widestName; /* if ((screenColumns % widestName) > 0) nCols++; */ nRows = nCmds2Print / nCols; if ((nCmds2Print % nCols) > 0) nRows++; (void) sprintf(spec, "%%-%ds", widestName); for (i=0; ic_name != NULL; c++) { cmd_help(c); cmd_usage(c); } } else while (--argc > 0) { arg = *++argv; c = getcmd(arg); if (c == (struct cmd *)-1) (void) printf("?Ambiguous help command %s\n", arg); else if (c == (struct cmd *)0) (void) printf("?Invalid help command %s\n", arg); else { cmd_help(c); cmd_usage(c); } } return NOERR; } /* help */ /* * If the user wants to, s/he can specify the maximum size of the log * file, so it doesn't waste too much disk space. If the log is too * fat, trim the older lines (at the top) until we're under the limit. */ void trim_log(void) { FILE *new, *old; struct stat st; long fat; string tmplogname, str; if (logsize <= 0 || *logfname == 0 || stat(logfname, &st) || (old = fopen(logfname, "r")) == NULL) return; /* never trim, or no log */ fat = st.st_size - logsize; if (fat <= 0L) return; /* log too small yet */ while (fat > 0L) { if (FGets(str, old) == NULL) return; fat -= (long) strlen(str); } /* skip lines until a new site was opened */ while (1) { if (FGets(str, old) == NULL) { (void) fclose(old); (void) unlink(logfname); return; /* nothing left, start anew */ } if (*str != '\t') break; } /* copy the remaining lines in "old" to "new" */ (void) Strncpy(tmplogname, logfname); tmplogname[strlen(tmplogname) - 1] = 'T'; if ((new = fopen(tmplogname, "w")) == NULL) { (void) PERROR("trim_log", tmplogname); return; } (void) fputs(str, new); while (FGets(str, old)) (void) fputs(str, new); (void) fclose(old); (void) fclose(new); if (unlink(logfname) < 0) PERROR("trim_log", logfname); if (rename(tmplogname, logfname) < 0) PERROR("trim_log", tmplogname); } /* trim_log */ int CheckNewMail(void) { struct stat stbuf; if (*mail_path == '\0') return 0; if (stat(mail_path, &stbuf) < 0) { /* cant find mail_path so we'll */ *mail_path = '\0'; /* never check it again */ return 0; } /* * Check if the size is non-zero and the access time is less than * the modify time -- this indicates unread mail. */ if ((stbuf.st_size != 0) && (stbuf.st_atime <= stbuf.st_mtime)) { if (stbuf.st_mtime > mbox_time) { (void) printf("%s\n", NEWMAILMESSAGE); mbox_time = stbuf.st_mtime; } return 1; } return 0; } /* CheckNewMail */ #ifdef CURSES int termcap_get(char **dest, char *attr) { static char area[1024]; static char *s = area; char *buf, *cp; int i, result = -1; int len = 0; *dest = NULL; while (*attr != '\0') { buf = tgetstr(attr, &s); if (buf != NULL && buf[0] != '\0') { for (i = 0; (buf[i] <= '9') && (buf[i] >= '0'); ) i++; /* Get rid of the terminal delays, like "$<2>". */ if ((cp = strstr(&(buf[i]), "$<")) != NULL) *cp = 0; if (*dest == NULL) *dest = (char *)malloc(strlen(&(buf[i])) + 1); else *dest = (char *)realloc(*dest, len + strlen(&(buf[i])) + 1); if (*dest == NULL) break; (void) strcpy(*dest + len, &(buf[i])); len += strlen (&(buf[i])); } attr += 2; } if (*dest == NULL) *dest = ""; else result = 0; return (result); } /* termcap_get */ void termcap_init(void) { char *term; if ((term = getenv("TERM")) == NULL) { term = "dumb"; /* TAR */ ansi_escapes = 0; } if (tgetent(tcbuf,term) != 1) { (void) fprintf(stderr,"Can't get termcap entry for terminal [%s]\n", term); } else { (void) termcap_get(&tcap_normal, "meuese"); if (termcap_get(&tcap_boldface, "md") < 0) { /* Dim-mode is better than nothing... */ (void) termcap_get(&tcap_boldface, "mh"); } (void) termcap_get(&tcap_underline, "us"); (void) termcap_get(&tcap_reverse, "so"); tcl_normal = strlen(tcap_normal); tcl_bold = strlen(tcap_boldface); tcl_uline = strlen(tcap_underline); tcl_rev = strlen(tcap_reverse); } } /* termcap_init */ static int c_output(int c) { return (putchar(c)); } /* c_output */ void tcap_put(char *cap) { tputs(cap, 0, c_output); } /* tcap_put */ #endif /* CURSES */ /* eof main.c */ diff --git a/usr.bin/ncftp/main.h b/usr.bin/ncftp/main.h index 1891b61d77c6..fd6438c38549 100644 --- a/usr.bin/ncftp/main.h +++ b/usr.bin/ncftp/main.h @@ -1,50 +1,50 @@ /* main.h */ #ifndef _main_h_ #define _main_h_ /* $RCSfile: main.h,v $ * $Revision: 14020.12 $ * $Date: 93/05/21 05:45:33 $ */ struct userinfo { str32 username; string homedir; string shell; string hostname; int uid; }; void intr SIG_PARAMS; int getuserinfo(void); int init_arrays(void); void init_transfer_buffer(void); void init_prompt(void); void lostpeer SIG_PARAMS; -void cmdscanner(int top); +int cmdscanner(int top); char *strprompt(void); void makeargv(void); char *slurpstring(void); int help(int argc, char **argv); void trim_log(void); int CheckNewMail(void); #ifdef CURSES void tcap_put(char *cap); void termcap_init(void); int termcap_get(char **dest, char *attr); # ifndef TERMH /* would take care of this. */ # ifdef NO_CONST extern char *tgetstr(char *, char **); # else extern char *tgetstr(const char *, char **); # endif # endif /* TERMH */ #endif /* CURSES */ /* Should be in a 'tips.h,' but... */ void PrintTip(void); #endif /* _main_h_ */ diff --git a/usr.bin/ncftp/ncftp.1 b/usr.bin/ncftp/ncftp.1 index 37cf474748e2..8eaf7584a409 100644 --- a/usr.bin/ncftp/ncftp.1 +++ b/usr.bin/ncftp/ncftp.1 @@ -1,1393 +1,1396 @@ .\"------- .\" Man page portability notes .\" .\" These are some notes on conventions to maintain for greatest .\" portability of this man page to various other versions of .\" nroff. .\" .\" When you want a \ to appear in the output, use \e in the man page. .\" (NOTE this comes up in the rc grammar, where to print out '\n' the .\" man page must contain '\en'.) .\" .\" Evidently not all versions of nroff allow the omission of the .\" terminal " on a macro argument. Thus what could be written .\" .\" .Cr "exec >[2] err.out .\" .\" in true nroffs must be written .\" .\" .Cr "exec >[2] err.out" .\" .\" instead. .\" .\" Use symbolic font names (e.g. R, I, B) instead of the standard .\" font positions 1, 2, 3. Note that for Xf to work the standard .\" font names must be single characters. .\" .\" Note that sentences should end at the end of a line. nroff and .\" troff will supply the correct intersentence spacing, but only if .\" the sentences end at the end of a line. Explicit spaces, if given, .\" are apparently honored and the normal intersentence spacing is .\" supressed. .\" .\" DaviD W. Sanderson .\"------- .\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Sp space down the interparagraph distance .\"------- .de Sp .sp \\n(Ddu .. .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .Sp .in +0.5i .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .in .. .TH NcFTP 1 "" NCEMRSoft .\"------- .SH "NAME" .\"------- NcFTP \(em Internet file transfer program .\"------- .SH "SYNOPSIS" .\"------- .B ncftp .RI [ "program options" ] .RI [[ "open options" ] .IR hostname [\c .B :\c .IR pathname ]] .\"------- .SH "DESCRIPTION" .\"------- .I NcFTP is a user interface to the Internet standard .IR "File Transfer Protocol" . This program allows a user to transfer files to and from a remote network site, and offers additional features that are not found in the standard interface, .IR ftp . .\"------- .SH "FEATURES" .\"------- Program options will be explained later in this document. Let's get down to business and go over the features that make this program worthwhile. .PP Here is the list of section headers; I have my $MANPAGER environment variable set to use .RB `` "less \-i" '' so that I can skip to the section I want (otherwise, .BI / regex commands to the pager won't match the section headers because of the formatting codes; the .RB `` \-i '' can search through the formatting codes) .Ds Establishing the remote connection Format of the RC file The Recent-sites file Redialing a busy remote site Supplying a sitename from your shell's command line Using Colon-mode Using FTP-cat and FTP-more mode Supplying a port number with the open command Displaying and changing program variables Program variables Listing a remote directory Viewing a remote directory with your pager Redisplaying the last directory listing Fetching files from the remote host Viewing a remote file with your pager Creating a message file on the remote host Looking up site names and addresses Checking the configuration of the program Using the command shell Customizing the prompt Keeping a log of your file transfers Program options A sample RC file .De .\"------- .SH "Establishing the remote connection" .\"------- Just opening a connection to a remote server was inconvenient enough in the stock .I ftp program to justify writing this program. Here at .IR NCEMRSoft , we want to do our business as quickly and painlessly as possible. We'd rather save time and wear and tear on our metacarpals than bother typing entire site names, usernames, and email addresses masquerading as passwords, and setting binary mode. .PP We made all connections anonymous by default, and we automatically send our email address for the password on those connections. We allowed for site names to be abbreviated. .PP For each commonly accessed site, you can put an entry in your program preferences file (let's call it the ``ncftprc file'' or ``RC file'' for short). To open the site, from the command shell all you do is type: .Ds open wuarchive.wustl.edu .De .PP or .Ds o wuarchive.wustl.edu .De .PP As promised, you can abbreviate that further. Just use any abbreviation that would match only the site you had in mind. For the previous example, you could try: .Ds o wuarc o wustl o stl o wu .De .PP Any of those abbreviations would open wuarchive.wustl.edu anonymously, sending your anon-password (usually set to your email address) as the password. Keep in mind that the program tries opening the first site that matches the abbreviation you supplied. So: .Ds o w .De .PP might match a site named bowser.nintendo.co.jp if that site appeared before your entry for wuarchive.wustl.edu. .PP Most of the time we open remote sites anonymously, but there are times where you need to specifically open a site with an actual username and password. Let's say my partner, Phil Dietz, wants to FTP something out of my account. Perhaps he wants to fetch the latest version of the source code to .I NcFTP so he can optimize something or add a new feature behind my back. Since the program opens remote sites anonymously by default (actually, you can change this behavior; more on that later), he would have to specify a flag to the .I open command so he can supply my username and password. He would try: .Ds o \-u sphygmomanometer.unl.edu .De .PP or, more likely: .Ds o \-u sph .De .PP Then the program would prompt him for a username (login, whatever) and a password: .Ds Login Name (pdietz): mgleason Password: ******** .De .PP If he got it right, he could raid my stuff. If not, he'd probably drop me an email asking me to quit changing my password so often. .PP There are even times where you want to FTP from your own account, like if you are debugging an FTP client you wrote. At this prompt: .Ds Login Name (mgleason): .De .PP I could just hit return to tell the program that I want ``mgleason'' as my username, then I would enter my password. .\"------- .SH "Format of the RC file" .\"------- This release of the program is somewhat compatible with the stock .I ftp program's .B ".netrc" file. However, I can promise you that in the near future the program will use a new format, so don't invest too much time in it. .PP The RC file can be named .RB `` ncftprc '', .RB `` netrc '', or .RB `` .ncftprc '', but it is usually named .RB `` .netrc '' so it can be used with the stock .I ftp program. .I NcFTP looks in the current working directory for any of those files, and then in your home directory, and after that it gives up (which is OK, because RC files aren't mandatory). .PP The file usually starts with .I #set and .I #unset commands that do things to the programs variables. The reason for the ``#'' is so the stock .I ftp program will think they are comments. You might have this appearing as the first few lines in your RC file (I'll explain later): .Ds #set debug 1 #set pager "less \-EMi" #unset startup\-msg .De .PP After those, you put in machine entries for each of your favorite sites. Let's put in an entry for wuarchive.wustl.edu. First you would put: .Ds machine wuarchive.wustl.edu .De .PP Then you could put in your username, password, and account if you like: .Ds user anonymous password \-mgleason@cse.unl.edu account wuarc.does.not.use.accounts .De .PP Following that, you would add the startup macro that is run each time you connect to wuarchive. You must start it with this line: .Ds macdef init .De .PP Then put in the commands you want to do: .Ds cd /graphics/gif ls \-lt .De .PP After that, you end the macro with a blank line (important!). The finished machine entry would look like the following. To make the transition to the impending new format less painful, I recommend you adhere to this format: .ta 6m +6m .Ds machine wuarchive.wustl.edu user anonymous password \-mgleason@cse.unl.edu account wuarc.does.not.use.accounts macdef init cd /graphics/gif ls \-lt .RI \t( "mandatory blank line to end the macro" ) .De .PP Of course, if all you want to do is open wuarchive anonymously, you needn't bother with the ``user'', ``password'', and ``account'' lines. You may want to put them in if you plan on using the stock .I ftp program, though. Try something like this: .ta 6m +6m .Ds machine wuarchive.wustl.edu macdef init cd /graphics/gif ls \-lt .RI \t( "mandatory blank line to end the macro" ) .De .PP You can tell the program to not run the startup macro if you supply .B "\-i" to the .I open command. .PP Really, you should only bother adding entries for sites that you want to run startup macros upon connection. The next section explains why. .\"------- .SH "The Recent-sites file" .\"------- Each time you open a site, the program saves the name of the site and the last directory you were in to the .I recent-sites file which is named .B ".ncrecent" and placed in your home directory. The program saves a predetermined number of these sites in the file, and when it reaches the limit, it discards the oldest entry so it can add a new one. .PP You can just go ahead and use the name of the site you want with the .I open command if you know it is in the .I recent\-file (and you can abbreviate the name, just like those in the RC file). But if you cannot remember what the name of the site you want, all you do is run the .I open command with no site parameter: .Ds open .De .PP This will pop up a list of the sites in the .IR "recent-file" , and sites in your RC file. At the open prompt, just type the name (or an abbreviation of that name) or the number preceding the site name to open that site. After opening the site you wanted, the program sets the remote working directory to the same one you left in the last time you called. .PP If you don't like the idea of having the sites you called stored on disk, you can turn this feature off using an .I unset command, explained later. .\"------- .SH "Redialing a busy remote site" .\"------- Some remote sites limit the number of leeches, er, anonymous connections at a time to reduce the load on the host computer. You can use the .I open command's redial feature to keep attempting connections until you get on, although that is not a very polite thing to do. The simplest way to do this would be to just supply the .B \-r option: .Ds open \-r wuarc .De .PP There are also options you can use to tweak redial. The .B \-d flag sets the delay between dials, and the .B \-g flag sets a limit on how many dials should be attempting before giving up. If you don't supply .B \-g the program will dial a day and forever (which my Number Theory professor, Dr. Mientka, says is longer than forever and a day) until it connects successfully, or until you get sick of waiting and hit the interrupt key (usually ^C). .PP This example dials wuarchive every ten minutes, giving up after twenty attempts. Note that the redial delay is specified in seconds: .Ds open \-r \-d 600 \-g 20 wuarc .De .PP Please be considerate when you use redialing, so you won't tax the network. Site administrators can and do get angry when they get flooded with connections. .\"------- .SH "Supplying a sitename from your shell's command line" .\"------- When you run the program: .Ds ncftp .De .PP by itself does nothing and waits for you to type commands to the program's own shell. Just like the stock .I ftp program, you can supply a site name on the command line: .Ds ncftp wuarchive.wustl.edu .De .PP You can also use abbreviations as usual: .Ds ncftp wuarc .De .PP This is equivalent to running the program, then issuing an .I open command to open wuarchive. .\"------- .SH "Using Colon-mode" .\"------- The .I open command is not a one-trick pony. Another option is what I call .IR "colon-mode" . This feature is used (most of the time) from your shell's command line. .PP In ancient times, way back during the Disco era, you could use a program called .I tftp to fetch a file using the Internet standard .I Trivial File Transfer Protocol. You could use that program to do something like this from within its shell: .Ds get wuarchive.wustl.edu:/graphics/gif/README .De .PP and that would call wuarchive and fetch the .B README file. .PP You can use this program to do the same thing from your shell's command line: .Ds csh> ncftp wuarchive.wustl.edu:/graphics/gif/README csh> head README .De .PP This tells your shell, in this case the ``c-shell'' to run .IR NcFTP , which would open wuarchive, fetch .B /graphics/gif/README and write the file .B ./README in the current working directory, and then exits. This is nice if you don't want to browse around the remote site, and you know exactly want you want. It would also come in handy in shell scripts, where you don't want to enter the command shell, and might not want the program to spew output. .PP You can use .I colon-mode to set the starting remote working directory also: .Ds csh> ncftp wuarchive.wustl.edu:/graphics/gif .De .PP This would run the program, open wuarchive, and .I cd to the gif directory, then run the program's command shell so you can browse. .PP .I Colon-mode is also available from within the program's command shell. At a prompt you can do stuff like this: .Ds ncftp> open wuarchive.wustl.edu:/graphics/gif/README ncftp> o wuarc:/graphics/gif .De .\"------- .SH "Using FTP-cat and FTP-more mode" .\"------- There are times where you might not want the program to write a .I colon-mode file in the current working directory, or perhaps you want to pipe the output of a remote file into something else. .I Colon-mode has options to do this. It was inspired by the guy who wrote the .I ftpcat perl script. The .B \-c option tells the program to write on the standard output stream. The .B \-m option pipes the file into your pager (like .IR more ")" Of course this won't work if the thing you give .I colon-mode is a directory! This example just dumps a remote file to stdout: .Ds csh> ncftp \-c wuarc:/graphics/gif/README \&... csh> .De .PP This example redirects a remote file into a different location: .Ds csh> ncftp \-c wu:/README > ~pdietz/thesis.tex .De .PP This one shows how to use a pipeline: .Ds csh> ncftp \-c wuarc:/README | tail | wc \-l 10 csh> .De .PP This shows how to page a remote file: .Ds csh> ncftp \-m wuarc:/graphics/gif/README \&... csh> .De .\"------- .SH "Supplying a port number with the open command" .\"------- This option just didn't fit anywhere else, so to finish out the open command, .B \-p lets you supply a port number if you have to .I ftp to a site using an nonstandard port number. Personally, I have yet to use this feature, but it is there for compatibility with the stock .I ftp program. .\"------- .SH "Displaying and changing program variables" .\"------- Now I'll explain the commands unique to .IR NcFTP . The others should perform the same as they would in the stock .I ftp program; consult the man page for it if you want those explained, or use the .I help command for a brief blurb. .PP The .I show command is used to display program variables and their values. .Ds show all .De .PP or .Ds show .De .PP would display all the variables with their values. .Ds .RI show " var1 var2 ... varN" .De .PP would display each specified variable and its value. .PP The .I set command changes the value of a program variable. Its syntax is: .Ds .RI set " varname value" .De .PP For Boolean or Integer variables, .Ds .RI set " varname" .De .PP would set the value of the variable .I varname to .B 1 .RB ( true ). .PP The .I unset command can be used to set the variable to its default value, or for Boolean and Integer variables, set the value of the variable to .B 0 .RB ( false ). For String variables, you can use this to set the value to an empty string. .PP You can use any of those three commands in both the command shell, or in the RC file with a ``#'' prepended. .\"------- .SH "Program variables" .\"------- Each variable can be one of the following types: .TP Boolean: Can be .RB `` on '' or .RB `` off '' (you can also use .RB `` 1 '' or .RB `` 0 ''). .TP Integer: Can be any positive or negative number, or .BR 0 . .TP String: Is a string of characters. If the string needs to have a space in it, make sure you surround the whole string with double quotes in a .I set command. .PP Variables follow. Some variables are explained later in the relevant sections. .TP .IR anon\-open " (Boolean)" Tells whether the default login mode is anonymous if on, or if off, will prompt for a username/password. You can always override this by using either .B \-a or .B \-u with the .I open command. .TP .IR anon\-password " (String)" Sends this as the password when you login anonymously. By default this is your email address. .TP .IR ansi\-escapes " (Boolean)" If on, the program can use boldface, underline, and inverse text. .TP .IR auto\-binary " (Boolean)" If on, sets the transfer type to binary mode immediately after connection. .TP .IR debug " (Integer)" Sets the debugging level. .TP .IR gateway\-login " (String)" Tells which username to use when logging in to your firewall gateway host. .TP .IR gateway\-host " (String)" The site which is acting as your firewall gateway, or empty if you aren't using one. .TP .IR local\-dir " (String)" The current local working directory. I like to set this from my RC file, so all my files go into my download directory. .TP .IR logfile " (String)" The name of your personal transfer log, or empty if you aren't using a transfer log. .TP .IR logsize " (Integer)" The maximum ceiling of your log file, before the program removes old entries. .TP .IR mprompt " (Boolean)" If on, prompts for each remote file expanded from a wildcard globbing expression. .TP .IR netrc " (String, Read-only)" Tells you the name of the RC file in use. .TP .IR pager " (String)" The pathname and flags of the program used to display output one screenful at a time. The default is the value of your $PAGER environment variable. .TP .IR prompt " (String)" The prompt specification that expands into the prompt. .TP .IR progress\-reports " (Integer)" Which progress meter to use, or .B 0 if you don't want progress reports during file transfers. Set it to .B 1 for a simple percentage meter; .B 2 for a fancy bar graph indicator; .B 3 to print just the number of kilobytes transferred; or .B 4 to print one dot for each 10% transferred, if you want to avoid the use of backspaces. Note that the program may use a different meter depending on how cooperative the remote host is, and what you have the .I ansi\-escapes variable set to. .TP .IR recent\-list " (Boolean)" If on, uses and updates the .I recent\-file. .TP .IR remote\-is\-unix " (Boolean)" Set automatically by the program upon connection, you may need to use this in a startup macro if the program guessed that a remote site was UNIX when it really is not. .TP .IR startup\-msg " (Boolean)" If on, prints the opening message and tip. .TP .IR tips " (Boolean)" If on, prints a tip on how to use the program better each time you run the program. .TP .IR type " (String)" The name of the file transfer mode in use, such as .RB `` binary '' or .RB `` ascii ''. .TP .IR verbose " (String/Integer)" Controls the amount of output spewed by the program. You can supply either the first character of the name of the verbosity level, or its number: .RS .TP .IR "Q" "uiet (\-1)" Won't print any output at all, even if an error occurs. .TP .IR "E" "rrors Only (0)" No output, except when errors occur. .TP .IR "T" "erse (1)" Prints errors, and useful output from the remote host. .TP .IR "V" "erbose (2)" Prints everything, even junk output from the remote end. .RE .\"------- .SH "Listing a remote directory" .\"------- The .I ls and .I dir commands perform in a similar manner to those of the stock .I ftp program. .PP The .I ls command sends the FTP command ``NLST'' for you. This command has been set so that it defaults to always listing files in columns (this is the .B \-C option given to the UNIX .I ls command) and appending metacharacters to each item name (this is the .B \-F option), so you can see which items are directories, files, links, etcetera. If you don't want your items columnized, you can try using the .B \-1 option with .I ls to print one item per line. .PP The .I dir command sends the FTP command ``LIST'' for you, which instead of printing just item names, it prints item sizes, owners, dates, and permissions as well. This command is equivalent to .RB `` "ls \-l" '' on most remote systems. .PP The usage for both commands is the same. Here is the one for .IR ls : .PP .RS .B ls .RI [ \-flags ] .RI [ "directory and file names" ] .RI [ redirection ] .RE .PP Note that in this program, you can supply both flags and items to list in the same command. The stock version of .I ftp doesn't let you do this: .Ds ls \-lrt /info\-mac/help .De .PP Another thing that the program does which the others should have done is let you supply more than one item: .Ds ls \-lrt /info\-mac/help /pub /info\-mac/README .De .PP You can also redirect the output into a file, or pipe it into something. This example shows how to list the contents of the current remote directory, and save the output into a file in the current local directory: .Ds ls \-t >ls.out .De .PP Note that for this to work, there must be no whitespace between the ``>'' and the filename, unlike your shell command line which allows for extra whitespace. This will be (actually, is) fixed in a future version of the program. .PP These examples show how to use a pipe: .Ds ls \-t |tail dir \-t "|less \-CM" ls \-t "|tail | wc" .De .PP Like the redirection example, there must be no whitespace between the first pipe character and the rest of the stuff. The trick is that it has to appear as one argument to the commands. The second and third examples illustrate the use of double quotes to squeeze extra parameters in. The second example can be done without all that typing. See the descriptions of the .I pdir and .I pls commands below. .\"------- .SH "Viewing a remote directory with your pager" .\"------- Didn't you hate it when you listed a remote directory, only to have most of the stuff scrolled off your terminal before you could read it? The .I pls and .I pdir commands take care of this for you. As you might have guessed, they perform exactly like their regular counterparts, only you view them with your pager. The pager to use is controlled by the .I pager program variable. .\"------- .SH "Redisplaying the last directory listing" .\"------- The program saves the listing into a local buffer, so if you need to see it again (probably forgot about .IR pdir ) you can use the .I redir and .I predir commands for this. .\"------- .SH "Fetching files from the remote host" .\"------- The .I get and .I mget retrieve remote files for you. The usage for .I get is: .Ds get remote\-file [local\-file or redirection] .De .PP To fetch .B /pub/README and write it as a file named .BR ./junk/readme , try: .Ds get /pub/README ./junk/readme .De .PP To fetch .B /pub/README and write it as .BR ./README , just do: .Ds get /pub/README .De .PP This lets you fetch a file using its whole pathname, and write a copy of it in the current directory, without having to bother with typing a local filename. In the unlikely event that you have write permission to a directory called .B /pub on your local machine, it would write .RB `` README '' in that directory. .PP Most of the time the file you want will be in the current remote directory, so you can just do these: .Ds get README get README ./junk/readme .De .PP You can also use a redirection for .IR get , just like you can with the .IR ls ", " dir ", and " redir commands. As described earlier, you have to conform to the format below for this release of the program: .Ds get README >/dev/null get README |head get README "|head \-8" get README "|less \-EMi" .De .PP The last example is facilitated by the .I page command described later. .PP The .I get command can also use a wildcard expression in an attempt to match exactly one remote file. I call it ``Poor Man's File Completion.'' If you've done a remote listing, and you decide you want to download a file by the name of .RB `` obnoxiouslylongpackagename.tar.Z '', you can use ``PMFC'' to save some keystrokes. Choose an expression that will only match that one file, then use it with .IR get : .Ds get obn*.Z a.tar.Z .De .PP If your pattern was unique, .I get will fetch that file only. If the pattern matched more than one file, the program will bitch and moan. .PP The .I mget command is used to fetch many files at a time. The difference between .I get and .I mget is that .I get lets you write only one file, but you can put it in a different directory, while .I mget fetches many files, always writing them in the current local directory. This example fetches several remote files at once: .Ds mget a.file.Z b.file.Z c.tar d.tar.Z .De .PP The .I mget command, and its ugly sisters, .I mput and .I mdelete let you use wildcard expressions. I could have done the previous example as: .Ds mget *.Z c.tar .De .PP instead. The ``m'' commands will verify each file, if you have the program variable .I mprompt set. .\"------- .SH "Viewing a remote file with your pager" .\"------- If you would like to read a file on the remote host without saving a copy of it on your machine, you can use the .I page (or .I more if you wish) command: .Ds page README page obn*README page README.Z .De .PP The second example show that you can use ``PMFC'' like you can for .IR get. The third example will work also, because if the program knows how to decompress the file, it will do so before feeding it to your pager. As stated earlier, you can change the program to use to page by setting the program variable .IR pager. .\"------- .SH "Creating a message file on the remote host" .\"------- Use the .I create an empty file on the remote site. Sometimes it is necessary to leave a note if you can't get in touch with the remote site's administrator. For example if a file is corrupted, you could try: .Ds create Foo.tar_is_corrupt .De .PP in hopes that the original uploader will replace it. .\"------- .SH "Looking up site names and addresses" .\"------- You can use the program's builtin .RI mini- nslookup facility. If you wanted to know the site's IP number, but only knew the name you could do: .Ds lookup cse.unl.edu .De .PP This would spit out IP number for that site, in this case ``129.93.1.12''. If you needed to know what a site's name was, but only knew the IP number, try: .Ds lookup 129.93.1.12 .De .PP This would spit out the name for that site, in this case ``cse.unl.edu''. .\"------- .SH "Checking the configuration of the program" .\"------- Use the .I version command to print version and compilation information about the program. This will also tell you which optional features are compiled into the program, such as logging to the system log and which command line editor (if any) has been installed. .PP The author's email address is listed, and if you need to report something, send the output of this command along with your message. .\"------- .SH "Using the command shell" .\"------- Just like the stock .I ftp program, you type commands to it until you get bored and hit either ^D or type the .I quit command. .PP The program supports links to popular command line editing libraries. If the person who compiled it went to the effort, you will be able to edit the command line with arrow keys and other editing commands, and also scroll up and down in the command line history, usually with the up and down arrows. You can check the .I version command to see if either ``GETLINE'' or ``READLINE'' are installed. .\"------- .SH "Customizing the prompt" .\"------- You can set the shell's prompt string to whatever you like. You can use several metacharacters that expand into something each prompt. The .RB `` % '' flags are passed to .IR strftime (3), so you can put the date or time in the prompt formatted as you like it: .Ds set prompt "%I:%M ncftp>" .De .PP That would insert the current time in the prompt. .PP The .RB `` @ '' flags are expanded by the program itself. Here's the list of them. .PP If you have an ANSI-compatible terminal, or you have the program variable .I ansi\-escapes set, you can use .BR @B , .BR @I , and .B @U to turn on boldface, inverse, and underline text respectively (otherwise they won't insert anything). You can also use .B @R to turn on inverse (reverse) text. .B @P sets the text back to plain text. .PP .B @D Inserts the full path of the current remote directory. The .B @J flag is similar except it inserts only the directory name. .PP .B @H Inserts the name of the remote host. .B @C inserts the host and current directory path in .I "colon-mode" format, such as ``cse.unl.edu:/pub/mgleason'', or ``(not connected)''. The .B @c flag is similar, only it will insert ``cse.unl.edu:/pub/mgleason'' and a newline if connected, otherwise it prints nothing. The default prompt uses this flag to print a two line prompt when connected and a one line prompt when not connected. .PP .BR @E " or " @! inserts the event number (how many commands you've typed). .PP .B @M inserts ``(Mail)\0'' if mail has arrived since running the program. .PP .B @N inserts a newline character. .\"------- .SH "Keeping a log of your file transfers" .\"------- You can have the program keep a personal log file. I find it is useful so I can see where I got a certain file, or what the name of that site was I called two weeks ago. .PP To use a log, add: .Ds #set logfile ~/.ftplog .De .PP (or whatever you want to name the log) to your RC file. I don't want my log growing too large and using up all my disk space, so I also have: .Ds #set logsize 10240 .De .PP in my RC file. If you set the limit on the maximum log size, the program will keep the log file at or below that size, discarding old entries. .PP Note that this is different from having SYSLOG appear in the .I version command's output. When this is on, your actions are recorded to the system log, so your system administrator can make sure you aren't doing anything ``bad.'' .\"------- .SH "Program options" .\"------- Remember that you can treat the command line like an .I open command, so all lowercase options are passed to the .I open command, and the uppercase options are handled by the main program. The uppercase options are described below; refer to the .I open command for descriptions of its options. .TP .BI \-D " x" sets the debugging level to .IR x . .TP .B \-H runs the .I version command and exits, so you can save the output of it to use when you need to mail me something. .TP .B \-I toggles the mprompt variable; this is provided for compatibility with .RB `` "ftp \-i" ''. .TP .B \-N disables reading of the RC file; this is provided for compatibility with .RB `` "ftp \-n" ''. .TP +.B \-P +toggle passive mode (defaults to on). Useful for work behind firewalls. +.TP .BI \-V " x" sets verbosity to level .I x .RB ( \-1 , .BR 0 , .BR 1 , .BR 2 ) or .RB ( quiet , .BR errs , .BR terse , .BR verbose ). See the description of the .I verbose program variable for more information. .PP Here are some example command lines. Again, see the description of the .I open command (especially .IR "colon-mode" " and " "FTP\-cat mode" ")" and all its functions for more information. .PP This just enters the .I NcFTP command shell: .Ds csh> ncftp .De .PP This fetches .B CONTENTS and then quits: .Ds csh> ncftp cse.unl.edu:/pub/mgleason/CONTENTS .De .PP Some others examples, with open options and main program options mixed in: .Ds csh> ncftp \-V quiet \-u ftp.unl.edu csh> ncftp \-c cse.unl.edu:/pub/mgleason/CONTENTS csh> ncftp \-D 2 \-r \-d 120 \-g 10 \-N ftp.unl.edu .De .\"------- .SH "A sample RC file" .\"------- Here is a sample RC file: .ta 6m +6m .Ds #set logfile ~/.ftplog #set progress\-reports 2 #set local\-dir /usr/tmp/zz #set prompt "@B@E @UNcFTP@P @B@M@D@P \->" .sp machine sumex\-aim.stanford.edu macdef init cd /info\-mac get ./help/recent\-files.txt "|grep \-v '.abs' > sumex" !less sumex pwd .sp # This site is in here just so I can use ``apple'' # as an abbreviation. machine ftp.apple.com .sp # NcFTP will only ask for your password: machine cse.unl.edu login mgleason .sp # You can supply a login and a password: machine fake.machine.unl.edu login mgleason password mypass macdef init cd ./foo/bar .sp # If an antiquated non-UNIX machine doesn't use # the "SYST" command, you may need to unset # remote\-is\-unix, if the remote host complains # about ``ls \-CF''. machine some.vms.unl.edu macdef init unset remote\-is\-unix .sp .De .\"------- .SH "AUTHORS" .\"------- .I NcFTP was written by Mike Gleason, .I NCEMRSoft (mgleason@cse.unl.edu), and based on code by the authors of the .I ftp from the BSD 4.3 distribution. .I NcFTP is copyrighted 1992, 1993 by NCEMRSoft and 1985, 1989 by the Regents of California. .PP Ideas and some code contributed by Phil Dietz, .I NCEMRSoft (pdietz@cse.unl.edu). Testing and debugging done by Phil and Kok Hon Yin (hkok@cse.unl.edu). .PP Extensive man page formatting work by DaviD W. Sanderson (dws@ssec.wisc.edu). .\"------- .SH "BUGS" .\"------- Correct execution of many commands depends upon proper behavior by the remote server. .PP The remote server may drop the connection if you take a long time to page remote files. .PP Termcap padding is not correctly displayed. .PP There are no such sites named .I bowser.nintendo.co.jp or .IR sphygmomanometer.unl.edu . .\"------- .SH "SEE ALSO" .\"------- .IR strftime (3), .IR ftpd (8), .IR ftp (1), .IR nslookup (1), .IR compress (1), .IR gzip (1), .IR zcat (1), .IR fsp (1), .IR archie (1), .IR tftp (1). diff --git a/usr.bin/ncftp/open.c b/usr.bin/ncftp/open.c index 66733a88ec9c..fbbe7945f7dd 100644 --- a/usr.bin/ncftp/open.c +++ b/usr.bin/ncftp/open.c @@ -1,638 +1,639 @@ /* open.c */ /* $RCSfile: open.c,v $ * $Revision: 1.1 $ * $Date: 93/07/09 11:27:07 $ */ #include "sys.h" #include #include #include #include #include "util.h" #include "open.h" #include "cmds.h" #include "ftp.h" #include "ftprc.h" #include "main.h" #include "defaults.h" #include "copyright.h" /* open.c globals */ int remote_is_unix; /* TRUE if remote host is unix. */ int auto_binary = dAUTOBINARY; int anon_open = dANONOPEN; /* Anonymous logins by default? */ int connected = 0; /* TRUE if connected to server */ /* If TRUE, set binary each connection. */ Hostname hostname; /* Name of current host */ RemoteSiteInfo gRmtInfo; #ifdef GATEWAY string gateway; /* node name of firewall gateway */ string gate_login; /* login at firewall gateway */ #endif /* open.c externs */ extern char *reply_string, *line, *Optarg, *margv[]; extern int Optind, margc, verbose, macnum; extern long eventnumber; extern struct servent serv; extern FILE *cout; extern string anon_password; /* Given a pointer to an OpenOptions (structure containing all variables * that can be set from the command line), this routine makes sure all * the variables have valid values by setting them to their defaults. */ void InitOpenOptions(OpenOptions *openopt) { /* How do you want to open a site if neither -a or -u are given? * anon_open is true (default to anonymous login), unless * defaults.h was edited to set dANONOPEN to 0 instead. */ openopt->openmode = anon_open ? openImplicitAnon : openImplicitUser; /* Normally you don't want to ignore the entry in your netrc. */ openopt->ignore_rc = 0; /* Set the default delay if the user specifies redial mode without * specifying the redial delay. */ openopt->redial_delay = dREDIALDELAY; /* Normally, you only want to try once. If you specify redial mode, * this is changed. */ openopt->max_dials = 1; /* You don't want to cat the file to stdout by default. */ openopt->ftpcat = NO_FTPCAT; /* Setup the port number to try. */ #ifdef dFTP_PORT /* If dFTP_PORT is defined, we use a different port number by default * than the one supplied in the servent structure. */ openopt->port = dFTP_PORT; /* Make sure the correct byte order is supplied! */ openopt->port = htons(openopt->port); #else /* Use the port number supplied by the operating system's servent * structure. */ openopt->port = serv.s_port; #endif /* We are not in colon-mode (yet). */ openopt->colonmodepath[0] = 0; /* Set the hostname to a null string, since there is no default host. */ openopt->hostname[0] = 0; /* Set the opening directory path to a null string. */ openopt->cdpath[0] = 0; } /* InitOpenOptions */ /* This is responsible for parsing the command line and setting variables * in the OpenOptions structure according to the user's flags. */ int GetOpenOptions(int argc, char **argv, OpenOptions *openopt) { int opt, www; char *cp, *hostp, *cpath; /* First setup the openopt variables. */ InitOpenOptions(openopt); /* Tell Getopt() that we want to start over with a new command. */ Getopt_Reset(); while ((opt = Getopt(argc, argv, "aiup:rd:g:cm")) >= 0) { switch (opt) { case 'a': /* User wants to open anonymously. */ openopt->openmode = openExplicitAnon; break; case 'u': /* User wants to open with a login and password. */ openopt->openmode = openExplicitUser; break; case 'i': /* User wants to ignore the entry in the netrc. */ openopt->ignore_rc = 1; break; case 'p': /* User supplied a port number different from the default * ftp port. */ openopt->port = atoi(Optarg); if (openopt->port <= 0) { /* Probably never happen, but just in case. */ (void) printf("%s: bad port number (%s).\n", argv[0], Optarg); goto usage; } /* Must ensure that the port is in the correct byte order! */ openopt->port = htons(openopt->port); break; case 'd': /* User supplied a delay (in seconds) that differs from * the default. */ openopt->redial_delay = atoi(Optarg); break; case 'g': /* User supplied an upper-bound on the number of redials * to try. */ openopt->max_dials = atoi(Optarg); break; case 'r': openopt->max_dials = -1; break; case 'm': /* ftpcat mode is only available from your shell command-line, * not from the ncftp shell. Do that yourself with 'more zz'. */ if (eventnumber == 0L) { /* If eventnumber is zero, then we were called directly * from main(), and before the ftp shell has started. */ openopt->ftpcat = FTPMORE; /* ftpcat mode is really ftpmore mode. */ break; } else { fprintf(stderr, "You can only use this form of colon-mode (-m) from your shell command line.\n\ Try 'ncftp -m wuarchive.wustl.edu:/README'\n"); goto usage; } /* break; */ case 'c': /* ftpcat mode is only available from your shell command-line, * not from the ncftp shell. Do that yourself with 'get zz -'. */ if (eventnumber == 0L) { /* If eventnumber is zero, then we were called directly * from main(), and before the ftp shell has started. */ openopt->ftpcat = FTPCAT; break; } else { fprintf(stderr, "You can only use ftpcat/colon-mode from your shell command line.\n\ Try 'ncftp -c wuarchive.wustl.edu:/README > file.'\n"); goto usage; } /* break; */ default: usage: return USAGE; } } if (argv[Optind] == NULL) { /* No host was supplied. Print out the list of sites we know * about and ask the user for one. */ PrintSiteList(); (void) Gets("(site to open) ", openopt->hostname, sizeof(openopt->hostname)); /* Make sure the user just didn't hit return, in which case we * just give up and go home. */ if (openopt->hostname[0] == 0) goto usage; } else { /* The user gave us a host to open. * * First, check to see if they gave us a colon-mode path * along with the hostname. We also understand a WWW path, * like "ftp://bang.nta.no/pub/fm2html.v.0.8.4.tar.Z". */ hostp = argv[Optind]; cpath = NULL; if ((cp = index(hostp, ':')) != NULL) { *cp++ = '\0'; cpath = cp; www = 0; /* Is 0 or 1, depending on the type of path. */ if ((*cp == '/') && (cp[1] == '/')) { /* First make sure the path was intended to be used * with ftp and not one of the other URLs. */ if (strcmp(argv[Optind], "ftp")) { fprintf( stderr, "Bad URL '%s' -- WWW paths must be prefixed by 'ftp://'.\n", argv[Optind] ); goto usage; } cp += 2; hostp = cp; cpath = NULL; /* It could have been ftp://hostname only. */ if ((cp = index(hostp, '/')) != NULL) { *cp++ = '\0'; cpath = cp; } www = 1; } if (cpath != NULL) { (void) Strncpy(openopt->colonmodepath, www ? "/" : ""); (void) Strncat(openopt->colonmodepath, cpath); dbprintf("Colon-Mode Path = '%s'\n", openopt->colonmodepath); } } (void) Strncpy(openopt->hostname, hostp); dbprintf("Host = '%s'\n", hostp); } return NOERR; } /* GetOpenOptions */ /* This examines the format of the string stored in the hostname * field of the OpenOptions, and sees if has to strip out a colon-mode * pathname (to store in the colonmodepath field). Since colon-mode * is run quietly (without any output being generated), we init the * login_verbosity variable here to quiet if we are running colon-mode. */ int CheckForColonMode(OpenOptions *openopt, int *login_verbosity) { /* Usually the user doesn't supply hostname in colon-mode format, * and wants to interactively browse the remote host, so set the * login_verbosity to whatever it is set to now. */ *login_verbosity = verbose; if (openopt->colonmodepath[0] != 0) { /* But if the user does use colon-mode, we want to do our business * and leave, without all the login messages, etc., so set * login_verbosity to quiet so we won't print anything until * we finish. Colon-mode can be specified from the shell command * line, so we would like to be able to execute ncftp as a one * line command from the shell without spewing gobs of output. */ *login_verbosity = V_QUIET; } else if (openopt->ftpcat != 0) { /* User specified ftpcat mode, but didn't supply the host:file. */ (void) fprintf(stderr, "You didn't use colon mode correctly.\n\ If you use -c or -m, you need to do something like this:\n\ ncftp -c wuarchive.wustl.edu:/pub/README (to cat this file to stdout).\n"); return USAGE; } return NOERR; } /* CheckForColonMode */ /* All this short routine does is to hookup a socket to either the * remote host or the firewall gateway host. */ int HookupToRemote(OpenOptions *openopt) { int hErr; #ifdef GATEWAY /* Try connecting to the gateway host. */ if (*gateway) { hErr = hookup(gateway, openopt->port); (void) Strncpy(hostname, openopt->hostname); } else #endif hErr = hookup(openopt->hostname, openopt->port); return hErr; } /* HookupToRemote */ void CheckRemoteSystemType(int force_binary) { int tmpverbose; char *cp, c; /* As of this writing, UNIX is pretty much standard. */ remote_is_unix = 1; /* Do a SYSTem command quietly. */ tmpverbose = verbose; verbose = V_QUIET; if (command("SYST") == COMPLETE) { if (tmpverbose == V_VERBOSE) { /* Find the system type embedded in the reply_string, * and separate it from the rest of the junk. */ cp = index(reply_string+4, ' '); if (cp == NULL) cp = index(reply_string+4, '\r'); if (cp) { if (cp[-1] == '.') cp--; c = *cp; *cp = '\0'; } (void) printf("Remote system type is %s.\n", reply_string+4); if (cp) *cp = c; } remote_is_unix = !strncmp(reply_string + 4, "UNIX", (size_t) 4); } /* Set to binary mode if any of the following are true: * (a) The user has auto-binary set; * (b) The user is using colon-mode (force_binary); * (c) The reply-string from SYST said it was UNIX with 8-bit chars. */ if (auto_binary || force_binary || !strncmp(reply_string, "215 UNIX Type: L8", (size_t) 17)) { (void) _settype("binary"); if (tmpverbose > V_TERSE) (void) printf("Using binary mode to transfer files.\n"); } /* Print a warning for that (extremely) rare Tenex machine. */ if (tmpverbose >= V_ERRS && !strncmp(reply_string, "215 TOPS20", (size_t) 10)) { (void) _settype("tenex"); (void) printf("Using tenex mode to transfer files.\n"); } verbose = tmpverbose; } /* CheckRemoteSystemType */ /* This is called if the user opened the host with a file appended to * the host's name, like "wuarchive.wustl.edu:/pub/readme," or * "wuarchive.wustl.edu:/pub." In the former case, we open wuarchive, * and fetch "readme." In the latter case, we open wuarchive, then set * the current remote directory to "/pub." If we are fetching a file, * we can do some other tricks if "ftpcat mode" is enabled. This mode * must be selected from your shell's command line, and this allows you * to use the program as a one-liner to pipe a remote file into something, * like "ncftp -c wu:/pub/README | wc." If the user uses ftpcat mode, * the program immediately quits instead of going into it's own command * shell. */ void ColonMode(OpenOptions *openopt) { int tmpverbose; + int cmdstatus; /* How do we tell if colonmodepath is a file or a directory? * We first try cd'ing to the path first. If we can, then it * was a directory. If we could not, we'll assume it was a file. */ /* Shut up, so cd won't print 'foobar: Not a directory.' */ tmpverbose = verbose; verbose = V_QUIET; /* If we are using ftpcat|more mode, or we couldn't cd to the * colon-mode path (then it must be a file to fetch), then * we need to fetch a file. */ if (openopt->ftpcat || ! _cd(openopt->colonmodepath)) { /* We call the appropriate fetching routine, so we have to * have the argc and argv set up correctly. To do this, * we just make an entire command line, then let makeargv() * convert it to argv/argc. */ if (openopt->ftpcat == FTPCAT) (void) sprintf(line, "get %s -", openopt->colonmodepath); else if (openopt->ftpcat == FTPMORE) (void) sprintf(line, "more %s", openopt->colonmodepath); else { /* Regular colon-mode, where we fetch the file, putting the * copy in the current local directory. */ (void) sprintf(line, "mget %s", openopt->colonmodepath); } makeargv(); /* Turn on messaging if we aren't catting. */ if (openopt->ftpcat == 0) verbose = tmpverbose; /* get() also handles 'more'. */ if (openopt->ftpcat) - (void) get(margc, margv); + cmdstatus = get(margc, margv); else - (void) mget(margc, margv); + cmdstatus = mget(margc, margv); /* If we were invoked from the command line, quit * after we got this file. */ if (eventnumber == 0L) { - (void) quit(0, NULL); + (void) quit(cmdstatus == CMDERR ? -1 : 0, NULL); } } verbose = tmpverbose; } /* ColonMode */ /* Given a properly set up OpenOptions, we try connecting to the site, * redialing if necessary, and do some initialization steps so the user * can send commands. */ int Open(OpenOptions *openopt) { int hErr; int dials; char *ruser, *rpass, *racct; int siteInRC; char *user, *pass, *acct; int login_verbosity, oldv; macnum = 0; /* Reset macros. */ /* If the hostname supplied is in the form host.name.str:/path/file, * then colon mode was used, and we need to fix the hostname to be * just the hostname, copy the /path/file to colonmode path, and init * the login_verbosity variable. */ if (CheckForColonMode(openopt, &login_verbosity) == USAGE) return USAGE; /* If the hostname supplied was an abbreviation, such as just * "wu" (wuarchive.wustl.edu), look through the list of sites * we know about and get the whole name. We also would like * the path we want to start out in, if it is available. */ GetFullSiteName(openopt->hostname, openopt->cdpath); #ifdef GATEWAY /* Make sure the gateway host name is a full name and not an * abbreviation. */ if (*gateway) GetFullSiteName(gateway, NULL); #endif ruser = rpass = racct = NULL; /* This also loads the init macro. */ siteInRC = ruserpass2(openopt->hostname, &ruser, &rpass, &racct); if (ISANONOPEN(openopt->openmode)) { user = "anonymous"; pass = anon_password; } else { user = NULL; pass = NULL; } acct = NULL; if (siteInRC && !openopt->ignore_rc) { acct = racct; if (ruser != NULL) { /* We were given a username. If we were given explicit * instructions from the command line, follow those and * ignore what the RC had. Otherwise if no -a or -u * was specified, we use whatever was in the RC. */ if (ISIMPLICITOPEN(openopt->openmode)) { user = ruser; pass = rpass; } } } for ( dials = 0; openopt->max_dials < 0 || dials < openopt->max_dials; dials++) { if (dials > 0) { /* If this is the second dial or higher, sleep a bit. */ (void) sleep(openopt->redial_delay); (void) fprintf(stderr, "Retry Number: %d\n", dials + 1); } if ((hErr = HookupToRemote(openopt)) == -2) /* Recoverable, so we can try re-dialing. */ continue; else if (hErr == NOERR) { /* We were hookup'd successfully. */ connected = 1; oldv = verbose; verbose = login_verbosity; #ifdef GATEWAY if (*gateway) { if ((Login( user, pass, acct, (!openopt->ignore_rc && !openopt->colonmodepath[0]) ) != NOERR) || cout == NULL) goto nextdial; /* error! */ } #endif #ifdef GATEWAY if (!*gateway) { #endif /* We don't want to run the init macro for colon-mode. */ if ((Login( user, pass, acct, (!openopt->ignore_rc && !openopt->colonmodepath[0]) ) != NOERR) || cout == NULL) { goto nextdial; /* error! */ } #ifdef GATEWAY } #endif verbose = oldv; /* We need to check for unix and see if we should set binary * mode automatically. */ CheckRemoteSystemType(openopt->colonmodepath[0] != (char)0); if (openopt->colonmodepath[0]) { ColonMode(openopt); } else if (openopt->cdpath[0]) { /* If we didn't have a colon-mode path, we try setting * the current remote directory to cdpath. cdpath is * usually the last directory we were in the previous * time we called this site. */ (void) _cd(openopt->cdpath); } else { /* Freshen 'cwd' variable for the prompt. * We have to do atleast one 'cd' so our variable * cwd (which is saved by _cd()) is set to something * valid. */ (void) _cd(NULL); } break; /* we are connected, so break the redial loop. */ /* end if we are connected */ } else { /* Irrecoverable error, so don't bother redialing. */ /* The error message should have already been printed * from Hookup(). */ break; } nextdial: disconnect(0, NULL); continue; /* Try re-dialing. */ } return (NOERR); } /* Open */ /* This stub is called by our command parser. */ int cmdOpen(int argc, char **argv) { OpenOptions openopt; /* If there is already a site open, close that one so we can * open a new one. */ if (connected && NOT_VQUIET && hostname[0]) { (void) printf("Closing %s...\n", hostname); (void) disconnect(0, NULL); } /* Reset the remote info structure for the new site we want to open. * Assume we have these properties until we discover otherwise. */ gRmtInfo.hasSIZE = 1; gRmtInfo.hasMDTM = 1; if ((GetOpenOptions(argc, argv, &openopt) == USAGE) || (Open(&openopt) == USAGE)) return USAGE; return NOERR; } /* cmdOpen */ /* eof open.c */ diff --git a/usr.bin/ncftp/patchlevel.h b/usr.bin/ncftp/patchlevel.h index 60d128ae47c2..3b2259fd606f 100644 --- a/usr.bin/ncftp/patchlevel.h +++ b/usr.bin/ncftp/patchlevel.h @@ -1,129 +1,133 @@ +v1.8.7 - December 11, 1994. Tweaks for FreeBSD. Passive mode enabled and + turned on by default. This should be the last version of ncftp before + version 2. + v1.8.6 - October 30, 1994. Tweaks for Solaris in sys.h. v1.8.5 - September 20, 1994. Better(?) support for term. v1.8.4 - September 19, 1994. Bug in Makefile fixed. Bug involving getwd fixed. v1.8.3 - August 27, 1994. Bug fixed where failed connection attempts when using a numeric IP address would fail. v1.8.2 - August 4, 1994. Can compile with DONT_TIMESTAMP to turn off syncing timestamps of fetched files with their remote counterparts. IP_TOS now utilized. v1.8.1 - July 4, 1994. Forgot in ftprc.c. v1.8.0 - July 4, 1994. Tweak for DEC OSF/1. NO_FORMATTING added. Support for QNX added. Reporting an error if the recent file could not be written. Bumped up the max recents to 50; the open menu will now be fed through your pager to avoid the problem of scrolling off screen. Fixed problem with redialing and running out of descriptors. v1.7.8 - June 30, 1994. No longer defining TERMH for linux. v1.7.7 - June 21, 1994. Deleted a space in front of an " #endif". No functionality change whatsoever... v1.7.6 - June 18, 1994. Added commands and code to support the PASV command for passive negotiation of the data connection from the host server to the client. This facilitates operation of the client software from within a firewall. (J. B. Harrell) v1.7.5 - May 28, 1994. Fixed a rare problem with dimmed text. Fixed compilation problem with Dynix. Defining the domain name now takes precedence over the getdomainname() function. v1.7.4 - May 16, 1994. Tweaked hookup() a bit, to (try to) handle hosts with multiple addresses better. Fixed error with GMT offsets. Fixed 'addr_t' typo in SVR4 section. Moved SVR4 block down in sys.h. v1.7.3 - April 13, 1994. Fixed minor error in syslog reporting. Trying both getpwnam() and getpwuid(), instead of just one of them, increasing the probability the program can get your passwd entry. Better compatibility with other types of password input devices. v1.7.2 - April 5, 1994. Bytes/sec is now correct. Fixed error when NO_VARARGS was defined. Added support for . v1.7.1 - March 27, 1994. Defining HAS_DOMAINNAME for NeXT. Term hack can share sockets, plus some term stuff added to the Makefile. Trimmed some old stuff from the patchlevel.h file, and putting new versions first now. Smarter about determining abbreviations from local hostnames. Fixed bug where progress meter would go beserk after trying to get a non-existant file. v1.7.0 - March 14, 1994. More verbose when logging to the system log, and making sure that syslog() itself is called with a total of 5 or less parameters. Official patch posted which incorporates all the fixes to 1.6.0 (i.e. 1.6.1, 1.6.2, ... 1.6.9). v1.6.9 - March 11, 1994. Added DOMAIN_NAME and Solaris CPP symbols. Better handling of getting the domain name, specifically with SunOS. BSDi support added. v1.6.8 - March 4, 1994. Ensuring that tmp files are not public. Trying harder to get the real hostname, and fixed problem with disappearing progress meters (both due to T. Lindgren). v1.6.7 - February 20, 1994. Using getpwnam() instead of getpwuid(). Supporting WWW paths (i.e. ftp://host.name/path/name). v1.6.6 - February 15, 1994. Prevented scenario of fclosing a NULL FILE *. Edited term ftp's hookup() a little. More defs for linux in sys.h. Not updating a recent entry unless you were fully logged in. v1.6.5 - January 6, 1994. Fixed error with an #ifndef/#endif block having whitespace before the #. No longer confirming "ls >file" actions. Changed echo() to Echo(). AIX 3 uses TERMIOS. v1.6.4 - December 30, 1993. Fixed rare problem with GetDateAndTime. confirm() will return true if you're running the init macro. v1.6.3 - December 28, 1993. Added a new diagnostic command, memchk, to print stats from a special malloc library if you used one. Using SIZE and MDTM when the remote site supports it. Using a new set of routines for term (again). v1.6.2 - December 10, 1993. Term hack no longer depends on the PASV command (!). The BROKEN_MEMCPY problem worked-around. More wary of symbolic-link recursion. Fixed local path expander. Fixed inadvertant flushing of the typeahead buffer. Debug mode won't print your password. Progress meters no longer goof up when the file is huge. Added time-remaining to the Philbar. v1.6.1 - November 5, 1993. Checking if we have permission to write over a file to fetch. A few very minor changes. BSD no longer trying to use strchr :-) v1.6.0 - October 31, 1993. Added "term" support for Linux users. Better SCO Xenix support. Added -DLINGER, if you have a connection requiring it (so 'puts' to the remote system complete). Added -DNET_ERRNO_H if you need to include . Including more headers in sys.h. Fixed another globulize bug. Fixed a bug in confirm() where prompt was overwriting a str32. Added -DNO_CURSES_H if you do not want to try and include . Added -DHAS_GETCWD (usually automatic) and HAS_DOMAINNAME. Logins as "ftp" act like "anonymous." Fixed bug with "open #x". Making sure you defined GZCAT as a string. Turning off termcap attributes one by one, instead of using the turn-off-all-attributes. A few fixes for the man page, including documentation of the progress-meter types. AIX 2.x, AIX 3.x, ISC Unix, Dynix/PTX, and Besta support added to sys.h. Safer use of getwd(). Colon-mode is quieter. Getuserinfo function tweaked. Eliminated unnecessary GetHomeDir function in util.c. Reworked Gets(), since it wasn't always stripping \n's. Recent file can now read dir names with whitespace. Opening msg uses a larger buffer, because of escape codes. Philbar now prints K/sec stats. v1.5.6 - September 20, 1993... v1.5.5 - September 16, 1993... v1.5.4 - September 14, 1993... v1.5.3 - September 2, 1993... v1.5.2 - August 30, 1993... v1.5.1 - August 29, 1993... v1.5.0 - August 22, 1993... v1.0.2 - Jan 17, 1993... v1.0.1 - December 8, 1992... v1.0.0 - December 6, 1992. Initial release. diff --git a/usr.bin/ncftp/sys.h b/usr.bin/ncftp/sys.h index 372640cdcd19..e4b6d55f8f0d 100644 --- a/usr.bin/ncftp/sys.h +++ b/usr.bin/ncftp/sys.h @@ -1,610 +1,608 @@ /* Sys.h * See the README for details. */ /* $RCSfile: sys.h,v $ * $Revision: 14020.13 $ * $Date: 93/06/21 06:42:11 $ */ #ifdef __sun # ifndef sun # define sun 1 # endif #endif #ifdef sun # if !defined(__GNUC__) && !defined(__STDC__) && !defined(SunOverride) /* If you choke here, but you know what you're doing, just * define SunOverride. */ ^^^ "You need to use an ANSI C compiler. Try using gcc or acc." ^^^ # endif # ifdef Solaris /* not predefined. */ # ifndef SYSV # define SYSV 1 # endif # define System "Solaris" # else # define System "SunOS" # ifndef RINDEX # define RINDEX 1 # endif # endif /* not Solaris */ # ifndef TERMIOS # define TERMIOS 1 # endif # ifndef HAS_DOMAINNAME # define HAS_DOMAINNAME 1 # endif #endif /* sun */ #ifdef __sgi # ifndef sgi # define sgi 1 # endif #endif #ifdef sgi # define System "IRIX" # ifndef SYSV # define SYSV 1 # endif # ifndef HERROR # define HERROR 1 # endif # ifndef U_WAIT # define U_WAIT 1 # endif # ifndef STRICT_PROTOS # define STRICT_PROTOS 1 # endif # ifndef TERMIOS # define TERMIOS 1 # endif #endif /* sgi */ #ifdef AIX # define System "AIX 2.2.1" # define BSD_INCLUDES # define SYSV # define NO_STDLIB # define NO_UTIME_H # define NO_STRFTIME # define NO_STRSTR # define NO_MKTIME #endif /* AIX */ #ifdef _AIX # define System "AIX 3.x" # define SYSSELECTH 1 # define TERMIOS 1 #endif /* _AIX */ #ifdef __QNX__ # define QNX # define System "QNX 4.21 (POSIX)" # define SYSSELECTH # define TERMIOS # define _POSIX_SOURCE # define GETCWDSIZET # define STRICT_PROTOS # define RINDEX # define NO_CURSES_H # define unlink remove # define bcopy(s,d,l) memcpy((d),(s),(l)) # define bzero(cp,l) memset((cp),0,(l)) # define NO_SYSPARAM # include # define NCARGS _POSIX_ARG_MAX #endif #ifdef SCOXNX # define System "SCO Xenix" # define LAI_TCP # define NO_UTIMEH # define NO_MKTIME # define NO_STRFTIME # define NO_STRSTR # define NO_RENAME # define LINGER /* else SCO bug causes incomplete transfers */ # define SYSV 1 #endif /* SCOXNX */ #ifdef SCO322 # define System "SCO Unix 3.2v2" # define BOTCHED_FOPEN_RW # define NO_RENAME /* it exists, but it corrupts filesystems */ # define BROKEN_MEMCPY 1 # define SYSV 1 #endif /* SCO322 */ #ifdef SCO324 # define System "SCO Unix 3.2v4" # ifndef SYSV # define SYSV 1 # endif # ifndef BROKEN_MEMCPY # define BROKEN_MEMCPY 1 # endif #endif /* SCO324 */ #ifdef linux # define System "Linux" # ifndef HAS_DOMAINNAME # define HAS_DOMAINNAME 1 # endif # ifndef TERMIOS # define TERMIOS 1 # endif # ifndef SYSV # define SYSV 1 # endif #endif #ifdef ISC # define System "Interactive Unix" # ifndef SYSV # define SYSV 1 # endif # ifndef BROKEN_MEMCPY # define BROKEN_MEMCPY 1 # endif # ifndef NET_ERRNO_H # define NET_ERRNO_H 1 # endif #endif /* ISC */ #ifdef aux # define System "A/UX" # ifndef BROKEN_MEMCPY # define BROKEN_MEMCPY 1 # endif # ifndef SYSV # define SYSV 1 # endif #endif #ifdef NeXT # define System "NeXTStep" # ifndef RINDEX # define RINDEX 1 # endif # ifndef BSD # define BSD 1 # endif # ifndef NO_UNISTDH # define NO_UNISTDH 1 # endif # ifndef NO_UTIMEH # define NO_UTIMEH # endif # ifndef HAS_DOMAINNAME # define HAS_DOMAINNAME 1 # endif #endif #ifdef pyr # define System "OSx" # ifndef BSD # define BSD 1 # endif # ifndef SGTTYB # define SGTTYB 1 # endif # ifndef NO_STDLIBH # define NO_STDLIBH 1 # endif extern int errno; #endif /* pyr */ #ifdef _SEQUENT_ # if !defined(DYNIXPTX) && !defined(DYNIX) # define DYNIXPTX 1 # endif #endif #if DYNIXPTX # define System "Dynix/PTX" # ifndef SYSV # define SYSV 1 # endif # ifndef TRY_NOREPLY # define TRY_NOREPLY 1 # endif # define gettimeofday(a, b) get_process_stats(a, getpid(), 0, 0) #endif /* DYNIXPTX */ #ifdef DYNIX # define System "Dynix" # ifndef BSD # define BSD 1 # endif # ifndef SGTTYB # define SGTTYB 1 # endif # ifndef NO_UTIMEH # define NO_UTIMEH 1 # endif # ifndef NO_STDLIBH # define NO_STDLIBH 1 # endif # ifndef NO_VARARGS # define NO_VARARGS 1 # endif #endif /* DYNIX */ #ifdef ultrix # define System "Ultrix" # ifndef BSD # define BSD 1 # endif # ifndef USE_GETPWUID # define USE_GETPWUID 1 # endif # ifndef __GNUC__ # ifndef NO_CONST # define NO_CONST 1 # endif # endif #endif /* ultrix */ #ifdef __hpux # ifndef HPUX # define HPUX 1 # endif # define Select(a,b,c,d,e) select((a), (int *)(b), (c), (d), (e)) #endif #ifdef HPUX # define System "HP-UX" # ifndef _HPUX_SOURCE # define _HPUX_SOURCE 1 # endif # ifndef GETCWDSIZET # define GETCWDSIZET 1 # endif # define SYSV 1 #endif /* HPUX */ #ifdef SINIX # define System "SINIX" # ifndef SYSV # define SYSV 1 # endif /* You may need to add -lresolv, -lport, -lcurses to MORELIBS in Makefile. */ #endif #ifdef BULL /* added 23nov92 for Bull DPX/2 */ # define _POSIX_SOURCE # define _XOPEN_SOURCE # define _BULL_SOURCE # ifndef SYSV # define SYSV 1 # endif # define bull # define System "Bull DPX/2 BOS" # define SYSSELECTH #endif /* BULL */ /* added 23nov92 for Bull DPX/2 */ #ifdef __dgux # ifndef DGUX # define DGUX 1 # endif #endif #ifdef DGUX # ifndef _DGUX_SOURCE # define _DGUX_SOURCE # endif # define GETCWDSIZET 1 # define BAD_INETADDR 1 # define SYSV 1 # define System "DG/UX" #endif /* DGUX */ #ifdef apollo # ifndef BSD # define BSD 43 # endif # define NO_UTIMEH 1 # define System "Apollo" #endif #ifdef __Besta__ # define SYSV 1 # define SYSSELECTH 1 # define NO_UNISTDH 1 # define NO_STDLIBH 1 # define NO_UTIMEH 1 # ifndef BROKEN_MEMCPY # define BROKEN_MEMCPY 1 # endif # include #endif #ifdef __osf__ # ifdef __alpha /* DEC OSF/1 */ # define GETCWDSIZET 1 # endif #endif /* -------------------------------------------------------------------- */ #ifdef _SYSV # ifndef SYSV # define SYSV 1 # endif #endif #ifdef USG # ifndef SYSV # define SYSV 1 # endif #endif #ifdef _BSD # ifndef BSD # define BSD 1 # endif #endif #ifdef SVR4 # ifndef System # define System "System V.4" # endif # ifndef SYSV # define SYSV 1 # endif # ifndef VOID # define VOID void # endif # ifndef HERROR # define HERROR 1 # endif # ifdef TERMH # define TERMH 1 # endif # ifndef Gettimeofday # define Gettimeofday gettimeofday # endif #endif /* SVR4 */ #ifdef SYSV # ifndef RINDEX # define RINDEX 1 # endif # define bcopy(s,d,l) memcpy((d),(s),(l)) # define bzero(cp,l) memset((cp),0,(l)) # ifndef HAS_GETCWD # define HAS_GETCWD 1 # endif #endif #ifdef __bsdi__ # define System "BSDi" # ifndef BSD # define BSD 1 # endif # ifndef SYSSELECTH # define SYSSELECTH 1 # endif # ifndef GETCWDSIZET # define GETCWDSIZET 1 # endif # ifndef HERROR # define HERROR 1 # endif #endif /* BSDi */ -#ifdef __386BSD__ -# ifdef __FreeBSD__ +#ifdef __FreeBSD__ # define System "FreeBSD" # define GZCAT "/usr/bin/gzcat" # define HAS_DOMAINNAME 1 -# endif # include # include /* this two for BSD definition */ /* to avoid redefinition of it to 1 */ # define HERROR 1 # define TERMIOS 1 # define HAS_GETCWD 1 # define U_WAIT 1 # define NO_CONST 1 /* avoid prototype conflict */ #endif #ifdef BSD -# ifndef __386BSD__ +# ifndef __FreeBSD__ # ifndef SYSDIRH # define SYSDIRH 1 # endif # ifndef SGTTYB # define SGTTYB # endif # endif #endif /* * Generic pointer type, e.g. as returned by malloc(). */ #ifndef PTRTYPE # define PTRTYPE void #endif #ifndef Free # define Free(a) free((PTRTYPE *)(a)) #endif /* * Some systems besides System V don't use rindex/index (like SunOS). * Add -DRINDEX to your SDEFS line if you need to. */ #ifdef RINDEX /* or #include if you have it. */ # define rindex strrchr # define index strchr #endif /* RINDEX */ #ifdef SOCKS #define Getsockname(d,a,l) Rgetsockname((d), (struct sockaddr *)(a), (l)) #else #ifdef SYSV # define Getsockname(d,a,l) getsockname((d), (void *)(a), (l)) #else # define Getsockname(d,a,l) getsockname((d), (struct sockaddr *)(a), (l)) #endif #endif #ifndef Select # define Select(a,b,c,d,e) select((a), (b), (c), (d), (e)) #endif #ifndef Connect #ifndef SVR4 # define Connect(a,b,c) (connect((a), (struct sockaddr *)(b), (int)(c))) # define Bind(a,b,c) (bind((a), (struct sockaddr *)(b), (int)(c))) # define Accept(a,b,c) (accept((a), (struct sockaddr *)(b), (int *)(c))) #else /* SVR4 */ # define Connect(a,b,c) (connect((a), (caddr_t)(b), (int)(c))) # define Bind(a,b,c) (bind((a), (caddr_t)(b), (int)(c))) # define Accept(a,b,c) (accept((a), (caddr_t)(b), (int *)(c))) #endif /* SVR4 */ #endif /* Connect */ #ifndef Gettimeofday # define Gettimeofday(a) gettimeofday(a, (struct timezone *)0) #endif /* Gettimeofday */ #ifdef GETPASS # define Getpass getpass #endif /* Enable connections through firewall gateways */ #ifndef GATEWAY # define GATEWAY 1 #endif #ifdef _POSIX_SOURCE # define TERMIOS #endif /* Include frequently used headers: */ #include #ifndef NO_SYSPARAM #include #endif #include #include #include #include #include #ifndef NO_STDLIBH # include #else extern PTRTYPE *malloc(size_t); extern PTRTYPE *calloc(size_t, size_t); extern PTRTYPE *malloc(size_t); extern void free(PTRTYPE *); extern PTRTYPE *realloc(PTRTYPE *, size_t); extern void exit(int); #ifdef NO_CONST extern char *getenv(char *); extern int atoi(char *); #else extern char *getenv(const char *); extern int atoi(const char *); #endif #endif /* NO_STDLIBH */ #ifndef NO_UNISTDH # include #else char *getlogin (void); # ifdef NO_CONST extern char *getenv(char *); # else extern char *getenv(const char *); # endif #endif /* NO_UNISTDH */ #ifdef NO_STD_PROTOS extern int _filbuf(FILE *); extern int _flsbuf(int, FILE *); extern int fflush(FILE *); extern int fgetc(FILE *); extern int fprintf(FILE *, char *, ...); extern int fputc(int, FILE *); extern int fputs(char *, FILE *); extern int fclose(FILE *); extern int pclose(FILE *); extern void perror(char *); extern int printf(char *, ...); extern int rewind(FILE *); extern int sscanf(char *, char *, ...); extern int vfprintf(FILE *, char *, char *); extern char * mktemp(char *); extern int rename(char *, char *); extern int gettimeofday(struct timeval *, struct timezone *); extern time_t mktime(struct tm *); extern int strftime(char *, int, char *, struct tm *); extern time_t time(time_t *); extern int tolower(int); extern int toupper(int); #ifndef bcopy extern void bcopy(char *, char *, size_t); #endif #ifndef bzero extern void bzero(char *, size_t); #endif #ifdef SOCKS extern int Raccept(int, struct sockaddr *, int *); extern int Rbind(int, struct sockaddr *, int, unsigned long); extern int Rconnect(int, struct sockaddr *, int); extern int Rlisten(int, int); extern int Rgetsockname(int, struct sockaddr *, int *); #else extern int accept(int, struct sockaddr *, int *); extern int bind(int, struct sockaddr *, int); extern int connect(int, struct sockaddr *, int); extern int listen(int, int); extern int getsockname(int, struct sockaddr *, int *); #endif extern int gethostname(char *, int), getdomainname(char *, int); #ifndef Select extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); #endif extern int send(int, char *, int, int); extern int setsockopt(int, int, int, char *, int); extern int shutdown(int, int); extern int socket(int, int, int); #endif /* NO_STD_PROTOS */ /* This malloc stuff is mostly for our own use. */ #define LIBC_MALLOC 0 #define FAST_MALLOC 1 #define DEBUG_MALLOC 2 #ifdef LIBMALLOC # if LIBMALLOC != LIBC_MALLOC /* Make sure you use -I to use the malloc.h of choice. */ # include # endif #else # define LIBMALLOC LIBC_MALLOC #endif /* End of personal malloc junk. */ /* eof sys.h */