home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-01-24 | 54.9 KB | 2,497 lines |
- Newsgroups: comp.sources.misc
- From: mgleason@cse.unl.edu (Michael Gleason)
- Subject: v35i004: ncftp - Alternative User Interface for FTP, Part01/04
- Message-ID: <csm-v35i004=ncftp.095334@sparky.IMD.Sterling.COM>
- X-Md4-Signature: e3a2b18b99720bdd10123e1feb0d6783
- Date: Mon, 25 Jan 1993 15:54:08 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: mgleason@cse.unl.edu (Michael Gleason)
- Posting-number: Volume 35, Issue 4
- Archive-name: ncftp/part01
- Environment: UNIX, ANSI-C, getopt
- Supersedes: ncftp: Volume 34, Issue 14-16
-
- ncftp - Alternative user interface for FTP
- version 1.0 PL 2 by Mike Gleason, NCEMRSoft.
-
- Changes from 1.0 PL 1:
-
- * ls is more flexible, so now you can do things like "ls -flags directory."
- Previous versions of ncftp (and ftp) only allowed "ls -flags" or
- "ls directory."
-
- * Some new progress meters, a fancy bargraph and another similar to the
- original % meter that shows how many kilobytes have been transferred.
- This meter is also used when the remote site doesn't support the SIZE
- command, so you can always have a progress meter.
-
- * If you don't want ftp and ncftp to share an rc, you can use a '.ncftprc'
- for ncftp and a '.netrc' for ftp.
-
- * Better portability; in addition to support for DG/UX, NeXT, and DYNIX,
- the getpass2() function which was causing problems has been replaced
- by a more portable version. Also using a private getopt which can be
- called more than once.
-
- * Syslog'ging capability added for system administrators.
-
- * So many small enhancements and bug fixes that the patch is almost as
- large as the shar-chive. See patchlevel.h for the gory details.
-
-
- ncftp was created out of disgust with using the regular 'ftp'
- command found on many brands of Unix. People who spend a lot
- of time in ftp will want to install ncftp.
-
- Features:
-
- * No more typing 'anonymous' and your email address every time
- you want to ftp anonymously. You don't need to have the
- site in your .netrc.
-
- * No more typing complete site names. Sites in your .netrc
- can be abbreviated. Type 'o wuar' to call wuarchive.wustl.edu.
-
- * Use your pager (like 'more') to read remote files (and also
- compressed files).
-
- * Use your pager to view remote directory listings.
-
- * Transfers feature a progress meter.
-
- * Implicit cd.
-
- * Fancy prompts.
-
- * You can keep a log of your actions. See what the path was of
- that file you downloaded yesterday so you don't have to
- look for it today.
-
- * Built-in mini-nslookup.
-
- * The 'ls' command is ls -CF. Some ftp's ls was identical to 'dir.'
-
- * You can 'redial' a remote host until you connect.
-
- * Don't need to 'close' a site, just open a new one.
-
- * Don't feel like typing a long filename? Use a wildcard in single
- file commands like get and page.
-
- * You can create empty remote files.
-
- * Supports 'colon mode', so you can type 'ncftp cse.unl.edu:/pub/foo',
- to copy foo into your current directory.
-
- * You can re-display the last directory listing without getting it
- across the network.
-
- * Detects when new mail arrives.
-
- * ncftp is quieter by default -- who cares if the PORT command was
- successful (if you do, turn verbose on :-).
-
- * It can be compiled to log transfers, etc., to the system log.
- -------------
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: cmds.c ftp.h
- # Wrapped by kent@sparky on Mon Jan 25 09:48:02 1993
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 1 (of 4)."'
- if test -f 'cmds.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'cmds.c'\"
- else
- echo shar: Extracting \"'cmds.c'\" \(48279 characters\)
- sed "s/^X//" >'cmds.c' <<'END_OF_FILE'
- X/* cmds.c */
- X
- X#include "sys.h"
- X#include <sys/types.h>
- X#include <sys/param.h>
- X
- X#include <sys/wait.h>
- X
- X#include <sys/stat.h>
- X#include <sys/socket.h>
- X#include <arpa/ftp.h>
- X#include <setjmp.h>
- X#include <signal.h>
- X#include <string.h>
- X#include <errno.h>
- X#include <netdb.h>
- X#include <netinet/in.h>
- X#include <arpa/inet.h>
- X#include <ctype.h>
- X#include <sys/time.h>
- X#include <time.h>
- X
- X#ifdef SYSLOG
- X# include <syslog.h>
- X#endif
- X
- X#ifndef NO_UNISTDH
- X# include <unistd.h>
- X#endif
- X
- X#include "ftpdefs.h"
- X#include "defaults.h"
- X#include "cmds.h"
- X#include "main.h"
- X#include "ftp.h"
- X#include "ftprc.h"
- X#include "getpass.h"
- X#include "glob.h"
- X#include "copyright.h"
- X
- X/* cmds.c globals */
- Xint curtype; /* file transfer type */
- Xstr32 curtypename; /* name of file transfer type */
- Xint verbose; /* print messages coming back from server */
- Xint mprompt; /* interactively prompt on m* cmds */
- Xint debug; /* debugging level */
- Xint options; /* used during socket creation */
- Xint macnum; /* number of defined macros */
- Xint paging = 0;
- Xint creating = 0;
- Xstruct macel macros[16];
- Xchar *macbuf; /* holds ALL macros */
- Xjmp_buf jabort;
- Xchar *mname; /* name of current m* command */
- Xint activemcmd; /* flag: if != 0, then active multi command */
- Xstring cwd; /* current remote directory */
- Xstring lcwd; /* current local directory */
- Xchar lasthostname[64]; /* name of last host w/ lookup(). */
- Xint remote_is_unix; /* TRUE if remote host is unix. */
- Xint auto_binary = dAUTOBINARY; /* If TRUE, set binary each connection. */
- Xint Opterr = 1; /* if error message should be printed */
- Xint Optind = 1; /* index into parent argv vector */
- Xint Optopt; /* character checked for validity */
- Xchar *Optarg; /* argument associated with option */
- Xchar *Optplace = EMSG; /* saved position in an arg */
- X
- X#ifdef REDIR
- Xint is_ls = 0; /* are we doing an ls? if so, then buffer */
- Xstruct lslist *lshead = NULL; /* hold last output from host */
- Xstruct lslist *lstail = NULL;
- X#endif
- X
- X/* cmds.c externs */
- Xextern char *globerr, *home, *reply_string;
- Xextern int code, margc, connected, ansi_escapes;
- Xextern int connected, fromatty, data, progress_meter;
- Xextern int parsing_rc;
- Xextern char *altarg, *line, *margv[];
- Xextern char *globchars;
- Xextern string hostname, progname, pager, anon_password;
- Xextern string prompt, logfname, version;
- Xextern long logsize, eventnumber;
- Xextern size_t xferbufsize;
- Xextern struct servent *sp;
- Xextern struct cmd cmdtab[];
- Xextern struct userinfo uinfo;
- Xextern FILE *cin, *cout, *logf;
- Xextern int Optind;
- Xextern char *Optarg;
- Xextern int gethostname (char *, int);
- Xextern int ioctl (int, int, ...);
- X
- Xstruct var vars[] = {
- X { "anon-password", STR, 0, anon_password, (setvarproc) 0 },
- X { "ansi-escapes", INT, 0, &ansi_escapes, (setvarproc) 0 },
- X { "auto-binary", INT, 0, &auto_binary, (setvarproc) 0 },
- X { "debug", INT, 0, &debug, (setvarproc) 0 },
- X { "local-dir", STR, 0, lcwd, set_ldir },
- X { "logfile", STR, 0, logfname, set_log },
- X { "logsize", LONG, 0, &logsize, (setvarproc) 0 },
- X { "mprompt", INT, 0, &mprompt, (setvarproc) 0 },
- X { "pager", STR, 0, pager + 1, set_pager },
- X { "prompt", STR, 0, prompt, set_prompt },
- X { "progress-reports", INT, 0, &progress_meter,(setvarproc) 0 },
- X { "remote-is-unix", INT, 1, &remote_is_unix,(setvarproc) 0 },
- X { "type", STR, 1, curtypename, set_type },
- X { "verbose", INT, 0, &verbose, set_verbose }
- X};
- X
- Xstruct types types[] = {
- X { "ascii", "A", TYPE_A, 0 },
- X { "binary", "I", TYPE_I, 0 },
- X { "image", "I", TYPE_I, 0 },
- X { "ebcdic", "E", TYPE_E, 0 },
- X { "tenex", "L", TYPE_L, "8" },
- X 0
- X};
- X
- X
- X
- Xvoid Getopt_Reset(void)
- X{
- X Optind = 1;
- X Optplace = "";
- X} /* Getopt_Reset */
- X
- X
- X
- Xint Getopt(int nargc, char **nargv, char *ostr)
- X{
- X register char *oli; /* Option letter list index */
- X
- X if (!*Optplace) { /* update scanning pointer */
- X if (Optind >= nargc || *(Optplace = nargv[Optind]) != '-')
- X return (EOF);
- X if (Optplace[1] && *++Optplace == '-') { /* found "--" */
- X ++Optind;
- X return (EOF);
- X }
- X } /* Option letter okay? */
- X if ((Optopt = (int) *Optplace++) == (int) ':' ||
- X !(oli = index(ostr, Optopt))) {
- X if (!*Optplace)
- X ++Optind;
- X if (Opterr) {
- X fprintf(stderr, "%s%s%c\n", *nargv, ": illegal option -- ", Optopt);
- X return(BADCH);
- X }
- X }
- X if (*++oli != ':') { /* don't need argument */
- X Optarg = NULL;
- X if (!*Optplace)
- X ++Optind;
- X } else { /* need an argument */
- X if (*Optplace) /* no white space */
- X Optarg = Optplace;
- X else if (nargc <= ++Optind) { /* no arg */
- X Optplace = EMSG;
- X if (Opterr) {
- X fprintf(stderr, "%s%s%c\n", *nargv, ": option requires an argument -- ", Optopt);
- X return(BADCH);
- X }
- X } else /* white space */
- X Optarg = nargv[Optind];
- X Optplace = EMSG;
- X ++Optind;
- X }
- X return (Optopt); /* dump back Option letter */
- X} /* Getopt */
- X
- X
- X
- X
- Xchar *Gets(char *sline, size_t size)
- X{
- X char *cp = fgets(sline, (int) (size - 1), stdin);
- X if (cp != NULL) {
- X cp += strlen(cp) - 1;
- X if (*cp == '\n')
- X *cp = 0; /* get rid of the newline. */
- X }
- X return cp;
- X} /* Gets */
- X
- X
- X
- X
- Xchar **re_makeargv(char *promptstr, int *argc)
- X{
- X size_t sz;
- X
- X (void) strcat(line, " ");
- X (void) printf(promptstr);
- X sz = strlen(line);
- X (void) Gets(&line[sz], (size_t) (CMDLINELEN - sz)) ;
- X (void) makeargv();
- X *argc = margc;
- X return (margv);
- X} /* re_makeargv */
- X
- X
- X
- X
- Xchar *get_cwd(char *buf, int size)
- X{
- X#ifdef SYSV
- X# ifdef NO_UNISTDH
- X# ifdef GETCWDSIZET
- X extern char *getcwd(char *, size_t);
- X# else
- X extern char *getcwd(char *, int);
- X# endif
- X# endif
- X return (getcwd(buf, size - 1));
- X#else
- X extern char *getwd(char *);
- X return (getwd(buf));
- X#endif
- X} /* get_cwd */
- X
- X/*
- X * Connect to peer server and
- X * auto-login, if possible.
- X */
- X
- Xint setpeer(int argc, char **argv)
- X{
- X char *path;
- X unsigned int port;
- X time_t now;
- X int openmode = 1, tmpverbose, opt, hErr;
- X int redial_delay = dREDIALDELAY;
- X int ignore_rc = 0, dials, max_dials = 1;
- X string pathname, newhost;
- X char *cmdname = argv[0];
- X
- X port = sp->s_port;
- X Getopt_Reset();
- X while ((opt = Getopt(argc, argv, "aiup:rd:g:")) >= 0) {
- X switch (opt) {
- X case 'a': openmode = OPEN_A; break;
- X case 'u': openmode = OPEN_U; break;
- X case 'i': ignore_rc = 1; break;
- X case 'p':
- X port = atoi(Optarg);
- X if (port <= 0) {
- X (void) printf("%s: bad port number (%s).\n", cmdname, Optarg);
- X goto usage;
- X }
- X port = htons(port);
- X break;
- X case 'd': redial_delay = atoi(Optarg); break;
- X case 'g': max_dials = atoi(Optarg); break;
- X case 'r': max_dials = -1; break;
- X default:
- X usage:
- X (void) printf("usage: %s [-a | -u] [-i] [-p N] [-r [-d N] [-g N]] hostname[:pathname]\n\
- X -a : Open anonymously (this is the default).\n\
- X -u : Open, specify user/password.\n\
- X -i : Ignore machine entry in your .netrc.\n\
- X -p N : Use port #N for connection.\n\
- X -r : \"Redial\" until connected.\n\
- X -d N : Redial, pausing N seconds between tries.\n\
- X -g N : Redial, giving up after N tries.\n\
- X :path : Open site, then retrieve file \"path.\"\n", cmdname);
- X code = -1;
- X return;
- X }
- X }
- X
- X if (argv[Optind] == NULL)
- X goto usage;
- X (void) Strncpy(newhost, argv[Optind]);
- X if (connected) {
- X if (NOT_VQUIET && hostname != NULL)
- X (void) printf("Closing %s...\n", hostname);
- X (void) disconnect(0, NULL);
- X }
- X
- X /*
- X * If we are given something like wuarchive.wustl.edu:/pub/foo,
- X * try to connect to the site then first try to cd to /pub/foo,
- X * or if that fails, assume it is a file then try to fetch
- X * /pub/foo and write foo in the current local directory.
- X */
- X if ((path = index(newhost, ':')) != NULL) {
- X *path++ = 0;
- X (void) Strncpy(pathname, path);
- X }
- X
- X GetFullSiteName(newhost);
- X for (dials = 0; max_dials < 0 || dials < max_dials; dials++) {
- X if (dials > 0) {
- X (void) sleep(redial_delay);
- X (void) fprintf(stderr, "Retry Number: %d\n", dials + 1);
- X }
- X hErr = hookup(newhost, port);
- X if (hErr == -2) /* Recoverable, so we can try again. */
- X continue;
- X else if (hErr == 0) {
- X connected = 1;
- X tmpverbose = verbose;
- X if (debug == 0)
- X verbose = V_QUIET;
- X remote_is_unix = 1;
- X if (command("SYST") == COMPLETE) {
- X if (tmpverbose == V_VERBOSE) {
- X register char *cp, c;
- X cp = index(reply_string+4, ' ');
- X if (cp == NULL)
- X cp = index(reply_string+4, '\r');
- X if (cp) {
- X if (cp[-1] == '.')
- X cp--;
- X c = *cp;
- X *cp = '\0';
- X }
- X
- X (void) printf("Remote system type is %s.\n",
- X reply_string+4);
- X if (cp)
- X *cp = c;
- X }
- X remote_is_unix = !strncmp(reply_string + 4, "UNIX", (size_t) 4);
- X }
- X
- X if (auto_binary || path || !strncmp(reply_string, "215 UNIX Type: L8", (size_t) 17)) {
- X _settype("binary");
- X if (tmpverbose > V_TERSE)
- X (void) printf("Using %s mode to transfer files.\n", curtypename);
- X }
- X if (tmpverbose >= V_ERRS &&
- X !strncmp(reply_string, "215 TOPS20", (size_t) 10)) {
- X (void) printf(
- X "Remember to set tenex mode when transfering _binary_ files from this machine.\n");
- X }
- X verbose = tmpverbose;
- X
- X if (!login(newhost, openmode, ignore_rc) || cout == NULL)
- X goto nextdial; /* error! */
- X if (logf != NULL) {
- X (void) time(&now);
- X (void) fprintf(logf, "%s opened at %s",
- X hostname,
- X ctime(&now));
- X }
- X
- X /* Freshen 'cwd' variable for the prompt. */
- X (void) _cd(NULL);
- X if (path != NULL) {
- X if (! _cd(pathname)) {
- X /* Couldn't cd to this path, must be a file then. */
- X (void) sprintf(line, "get %s", pathname);
- X makeargv();
- X (void) get(margc, margv);
- X /* If we were invoked from the command line, quit
- X * after we got this file.
- X */
- X if (eventnumber == 0L) {
- X (void) quit(0, NULL);
- X }
- X }
- X }
- X break;
- X /* end if we are connected */
- X } else {
- X /* Irrecoverable error, so don't bother redialing. */
- X break;
- X }
- Xnextdial: continue;
- X }
- X} /* setpeer */
- X
- X
- X/*
- X * Set transfer type.
- X */
- Xint settype(int argc, char **argv)
- X{
- X if (argc > 2) {
- X (void) printf("usage: %s [ ascii | binary | ebcdic | image | tenex ]\n", argv[0]);
- X code = -1;
- X return;
- X }
- X code = 0;
- X if (argc < 2) {
- Xxx: (void) printf("Using %s mode to transfer files.\n", curtypename);
- X return;
- X }
- X _settype(argv[1]);
- X if (IS_VVERBOSE)
- X goto xx;
- X} /* settype */
- X
- X
- X
- X
- Xvoid _settype(char *typename)
- X{
- X register struct types *p;
- X int comret, i;
- X string cmd;
- X
- X *cmd = 0;
- X switch (isupper(*typename) ? tolower(*typename) : (*typename)) {
- X case 'a': i = 0; break;
- X case 'b': i = 1; break;
- X case 'i': i = 2; break;
- X case 'e': i = 3; break;
- X case 't': i = 4;
- X (void) strcpy(cmd, "TYPE L 8");
- X break;
- X default:
- X (void) printf("%s: unknown type\n", typename);
- X code = -1;
- X return;
- X }
- X p = &types[i];
- X if (*cmd == 0)
- X (void) sprintf(cmd, "TYPE %s", p->t_mode);
- X comret = command(cmd);
- X if (comret == COMPLETE) {
- X (void) Strncpy(curtypename, p->t_name);
- X curtype = p->t_type;
- X }
- X} /* _settype */
- X
- X
- X
- X
- X/*ARGSUSED*/
- Xint setbinary(int argc, char **argv) { _settype("binary"); }
- X/*ARGSUSED*/
- Xint setascii(int argc, char **argv) { _settype("ascii"); }
- X
- X
- X
- Xchar *verbose_msgs[] = {
- X "Only printing necessary error messages.\n",
- X "Printing error messages and announcements from the remote host.\n",
- X "Printing all messages, errors, acknowledgments, and announcements.\n"
- X};
- X
- Xvoid set_verbose(char *new, int unset)
- X{
- X int i;
- X
- X if (unset == -1) verbose = !verbose;
- X else if (unset || !new || !*new) verbose = V_ERRS;
- X else {
- X i = StrToBool(new);
- X if (i < V_QUIET) i = V_QUIET;
- X else if (i > V_VERBOSE) i = V_VERBOSE;
- X verbose = i;
- X }
- X if (!parsing_rc && NOT_VQUIET)
- X fputs(verbose_msgs[verbose], stdout);
- X} /* set_verbose */
- X
- X
- X
- X
- Xvoid set_prompt(char *new, int unset)
- X{
- X (void) Strncpy(prompt, (unset || !new || !*new) ? dPROMPT : new);
- X init_prompt();
- X} /* set_prompt */
- X
- X
- X
- X
- Xvoid set_log(char *fname, int unset)
- X{
- X if (logf) {
- X (void) fclose(logf);
- X logf = NULL;
- X }
- X if (!unset && fname && *fname) {
- X (void) Strncpy(logfname, fname);
- X logf = fopen (logfname, "a");
- X }
- X} /* set_log */
- X
- X
- X
- X
- Xvoid set_pager(char *new, int unset)
- X{
- X if (unset)
- X (void) strcpy(pager, "-");
- X else {
- X if (!new)
- X new = dPAGER;
- X if (!*new)
- X (void) strcpy(pager, "-");
- X else if (*new != '-')
- X (void) sprintf(pager, "|%s", (*new == '|' ? new + 1 : new));
- X }
- X} /* set_pager */
- X
- X
- X
- X
- Xvoid set_type(char *newtype, int unset)
- X{
- X int t = verbose;
- X verbose = V_QUIET;
- X if (!connected && t > V_QUIET)
- X (void) printf("Not connected.\n");
- X else
- X _settype(newtype && !unset ? newtype : "image");
- X verbose = t;
- X} /* set_type */
- X
- X
- X
- X
- Xvoid set_ldir(char *ldir, int unset)
- X{
- X int t = verbose;
- X char *argv[2];
- X
- X if (ldir && !unset) {
- X verbose = V_QUIET;
- X argv[1] = ldir;
- X lcd(2, argv);
- X verbose = t;
- X }
- X} /* set_ldir */
- X
- X
- X
- X
- Xint set(int argc, char **argv)
- X{
- X int unset, i, c;
- X struct var *v;
- X char *var, *val = NULL;
- X
- X if (argc < 2 || strncmp(argv[1], "all", (size_t)3) == 0) {
- X /* Show all variables. */
- X for (i=0; i<sizeof(vars)/sizeof(struct var); i++) {
- X (void) printf("%-20s= ", vars[i].name);
- X c = vars[i].type;
- X if (c < 0) c = -c;
- X if (vars[i].conn_required && !connected)
- X (void) printf("(not connected)\n");
- X else switch (c) {
- X case INT:
- X (void) printf("%d\n", *(int *)vars[i].var); break;
- X case LONG:
- X (void) printf("%ld\n", *(long *)vars[i].var); break;
- X case STR:
- X (void) printf("\"%s\"\n", (char *) vars[i].var); break;
- X }
- X }
- X } else {
- X unset = argv[0][0] == 'u';
- X var = argv[1];
- X if (argc == 2)
- X val = NULL;
- X else if (argc > 2) {
- X /* could be =, value or just value. */
- X if (*argv[2] == '=') {
- X if (argc > 3)
- X val = argv[3];
- X else return; /* can't do 'set var =' */
- X } else
- X val = argv[2];
- X }
- X for (i=0, v=NULL; i<sizeof(vars)/sizeof(struct var); i++) {
- X if (strncmp(vars[i].name, var, sizeof(vars[i].name)) == 0) {
- X v = &vars[i];
- X break;
- X }
- X }
- X if (v == NULL)
- X (void) fprintf(stderr, "%s: unknown variable.\n", var);
- X else {
- X if (v->conn_required && !connected)
- X (void) fprintf(stderr, "%s: must be connected.\n", var);
- X else if (v->type < 0)
- X (void) fprintf(stderr, "%s: read-only variable.\n", var);
- X else if (v->proc != (setvarproc) 0)
- X (*v->proc)(val, unset); /* a custom set proc. */
- X else if (unset) switch(v->type) {
- X case INT:
- X *(int *) v->var = 0; break;
- X case LONG:
- X *(long *) v->var = 0; break;
- X case STR:
- X *(char *) v->var = 0; break;
- X } else {
- X if (val == NULL) switch(v->type) {
- X /* User just said "set varname" */
- X case INT:
- X *(int *) v->var = 1; break;
- X case LONG:
- X *(long *) v->var = 1; break;
- X case STR:
- X *(char *) v->var = 0; break;
- X } else {
- X /* User said "set varname = value" */
- X switch (v->type) {
- X case INT:
- X (void) sscanf(val, "%d", (int *) v->var); break;
- X case LONG:
- X (void) sscanf(val, "%ld", (long *) v->var); break;
- X case STR:
- X (void) strcpy(v->var, val); break;
- X }
- X }
- X }
- X }
- X }
- X} /* set */
- X
- X
- X
- X
- X/*
- X * Send a single file.
- X */
- Xint put(int argc, char **argv)
- X{
- X char *cmd;
- X char *oldargv1;
- X
- X if (argc == 2) {
- X argc++;
- X argv[2] = argv[1];
- X }
- X if (argc < 2)
- X argv = re_makeargv("(local-file) ", &argc);
- X if (argc < 2) {
- Xusage:
- X (void) printf("usage:%s local-file remote-file\n", argv[0]);
- X code = -1;
- X return;
- X }
- X if (argc < 3)
- X argv = re_makeargv("(remote-file) ", &argc);
- X if (argc < 3)
- X goto usage;
- X oldargv1 = argv[1];
- X if (!globulize(&argv[1])) {
- X code = -1;
- X return;
- X }
- X /*
- X * If "globulize" modifies argv[1], and argv[2] is a copy of
- X * the old argv[1], make it a copy of the new argv[1].
- X */
- X if (argv[1] != oldargv1 && argv[2] == oldargv1) {
- X argv[2] = argv[1];
- X }
- X cmd = (argv[0][0] == 'a') ? "APPE" : "STOR";
- X sendrequest(cmd, argv[1], argv[2]);
- X} /* put */
- X
- X
- X
- X
- X/*
- X * Send multiple files.
- X */
- Xint mput(int argc, char **argv)
- X{
- X register int i;
- X void (*oldintr)(int);
- X char *tp;
- X
- X if (argc < 2)
- X argv = re_makeargv("(local-files) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage:%s local-files\n", argv[0]);
- X code = -1;
- X return;
- X }
- X mname = argv[0];
- X activemcmd = 1;
- X oldintr = signal(SIGINT, (void (*)(int)) mabort);
- X (void) setjmp(jabort);
- X for (i = 1; i < argc; i++) {
- X register char **cpp, **gargs;
- X
- X gargs = glob(argv[i]);
- X if (globerr != NULL) {
- X (void) printf("%s\n", globerr);
- X if (gargs) {
- X blkfree(gargs);
- X free(gargs);
- X }
- X continue;
- X }
- X for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
- X if (activemcmd && confirm(argv[0], *cpp)) {
- X tp = *cpp;
- X sendrequest("STOR", *cpp, tp);
- X if (!activemcmd && fromatty) {
- X if (confirm("Continue with","mput")) {
- X activemcmd++;
- X }
- X }
- X }
- X }
- X if (gargs != NULL) {
- X blkfree(gargs);
- X free(gargs);
- X }
- X }
- X (void) signal(SIGINT, oldintr);
- X activemcmd = 0;
- X} /* mput */
- X
- X
- X
- Xint tmp_name(char *str)
- X{
- X (void) strcpy(str, "/tmp/ncftpXXXXXX");
- X return (mktemp(str) == NULL);
- X} /* tmp_name */
- X
- X
- X
- X
- Xint rem_glob_one(char *pattern)
- X{
- X int oldverbose, result = 0;
- X char *cp;
- X string str, tname;
- X FILE *ftemp;
- X
- X /* Check for wildcard characters. */
- X if (*pattern == '|' || strpbrk(pattern, globchars) == NULL)
- X return 0;
- X
- X (void) tmp_name(tname);
- X oldverbose = verbose;
- X verbose = V_QUIET;
- X recvrequest ("NLST", tname, pattern, "w");
- X verbose = oldverbose;
- X ftemp = fopen(tname, "r");
- X if (ftemp == NULL || FGets(str, ftemp) == NULL) {
- X if (NOT_VQUIET)
- X (void) printf("%s: no match.\n", pattern);
- X result = -1;
- X goto done;
- X }
- X if ((cp = index(str, '\n')) != NULL)
- X *cp = '\0';
- X (void) strcpy(pattern, str);
- X cp = FGets(str, ftemp);
- X /* It is an error if the pattern matched more than one file. */
- X if (cp != NULL) {
- X if (NOT_VQUIET)
- X (void) printf("?Ambiguous remote file name.\n");
- X result = -2;
- X }
- Xdone:
- X if (ftemp != NULL)
- X (void) fclose(ftemp);
- X (void) unlink(tname);
- X return (result);
- X} /* rem_glob_one */
- X
- X
- X
- X
- X/*
- X * Receive (and maybe page) one file.
- X */
- Xint get(int argc, char **argv)
- X{
- X string local_file;
- X string remote_file;
- X
- X /* paging mode is set if the command name is 'page' or 'more.' */
- X paging = (**argv != 'g');
- X
- X if (argc < 2)
- X argv = re_makeargv("(remote-file) ", &argc);
- X
- X if (argc < 2) {
- X if (paging)
- X (void) printf("usage: %s remote-file\n", argv[0]);
- X else {
- Xgetusage:
- X (void) printf("usage: %s remote-file [local-file]\n", argv[0]);
- X }
- X return;
- X }
- X argv[1] = Strncpy(remote_file, argv[1]);
- X if (rem_glob_one(argv[1]) < 0)
- X return;
- X
- X if (paging) {
- X size_t len = strlen(remote_file);
- X
- X /* Run compressed remote files through zcat, then the pager. */
- X if (strlen(remote_file) > 2 && remote_file[len - 1] == 'Z' && remote_file[len - 2] == '.') {
- X _settype("b");
- X (void) sprintf(local_file, "|%s", ZCAT);
- X argv[2] = Strncat(local_file, pager);
- X } else
- X argv[2] = pager;
- X } else {
- X /* normal get */
- X if (argc == 2) {
- X (void) Strncpy(local_file, argv[1]);
- X argv[2] = local_file;
- X } else {
- X if (argc < 3)
- X argv = re_makeargv("(local-file) ", &argc);
- X if (argc < 3)
- X goto getusage;
- X if (!globulize(&argv[2])) {
- X code = -1;
- X return;
- X }
- X }
- X }
- X recvrequest("RETR", argv[2], argv[1], "w");
- X paging = 0;
- X} /* get */
- X
- X
- X
- X/*ARGSUSED*/
- Xvoid mabort(int unused)
- X{
- X (void) printf("\n");
- X (void) fflush(stdout);
- X if (activemcmd && fromatty) {
- X if (confirm("Continue with", mname)) {
- X longjmp(jabort,0);
- X }
- X }
- X activemcmd = 0;
- X longjmp(jabort,0);
- X} /* mabort */
- X
- X
- X
- X
- X/*
- X * Get multiple files.
- X */
- Xint mget(int argc, char **argv)
- X{
- X char *cp, *tp;
- X void (*oldintr)(int);
- X
- X if (argc < 2)
- X argv = re_makeargv("(remote-files) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage:%s remote-files\n", argv[0]);
- X code = -1;
- X return;
- X }
- X mname = argv[0];
- X activemcmd = 1;
- X oldintr = signal(SIGINT,mabort);
- X (void) setjmp(jabort);
- X while ((cp = remglob(argv)) != NULL) {
- X if (*cp == '\0') {
- X activemcmd = 0;
- X continue;
- X }
- X if (activemcmd && confirm(argv[0], cp)) {
- X tp = cp;
- X recvrequest("RETR", tp, cp, "w");
- X if (!activemcmd && fromatty) {
- X if (confirm("Continue with","mget")) {
- X activemcmd++;
- X }
- X }
- X }
- X }
- X (void) signal(SIGINT,oldintr);
- X activemcmd = 0;
- X} /* mget */
- X
- X
- X
- X
- Xchar *remglob(char *argv[])
- X{
- X static FILE *ftemp = NULL;
- X int oldverbose;
- X char *cp, *mode;
- X static string tmpname, str;
- X
- X if (!activemcmd) {
- Xxx:
- X if (ftemp) {
- X (void) fclose(ftemp);
- X ftemp = NULL;
- X (void) unlink(tmpname);
- X }
- X return(NULL);
- X }
- X if (ftemp == NULL) {
- X (void) tmp_name(tmpname);
- X oldverbose = verbose, verbose = V_QUIET;
- X for (mode = "w"; *++argv != NULL; mode = "a")
- X recvrequest ("NLST", tmpname, *argv, mode);
- X verbose = oldverbose;
- X ftemp = fopen(tmpname, "r");
- X if (ftemp == NULL) {
- X (void) printf("Can't find list of remote files (%s), oops.\n", tmpname);
- X return (NULL);
- X }
- X }
- X if (FGets(str, ftemp) == NULL)
- X goto xx;
- X if ((cp = index(str, '\n')) != NULL)
- X *cp = '\0';
- X return (str);
- X} /* remglob */
- X
- X
- X
- X
- Xchar *
- Xonoff(int boolf)
- X{
- X return (boolf ? "on" : "off");
- X} /* onoff */
- X
- X
- X
- X
- Xint
- XStrToBool(char *s)
- X{
- X register char c;
- X
- X c = *s | 32; /* lcase(*value) */
- X switch (c) {
- X case 'f': /* false */
- X return (0);
- X case 'o': /* test for "off" and "on" */
- X c = s[1] | 32;
- X return(c == 'f' ? 0 : 1);
- X case 't': /* true */
- X return (1);
- X default: /* 1, 0, -1, other number? */
- X return (atoi(s));
- X }
- X} /* StrToBool */
- X
- X
- X/*
- X * Turn on/off printing of server echo's, messages, and statistics.
- X */
- Xint setverbose(int argc, char **argv)
- X{
- X if (argc > 1)
- X set_verbose(argv[1], 0);
- X else set_verbose(argv[1], -1);
- X code = verbose;
- X} /* setverbose */
- X
- X
- X
- X/*
- X * Toggle interactive prompting
- X * during mget, mput, and mdelete.
- X */
- Xint setprompt(int argc, char **argv)
- X{
- X if (argc > 1)
- X mprompt = StrToBool(argv[1]);
- X else mprompt = !mprompt;
- X if (IS_VVERBOSE)
- X (void) printf("Interactive prompting for m* commmands %s.\n", onoff(mprompt));
- X code = mprompt;
- X} /* setprompt */
- X
- X
- X/*
- X * Set debugging mode on/off and/or
- X * set level of debugging.
- X */
- Xint setdebug(int argc, char **argv)
- X{
- X int val;
- X
- X if (argc > 1) {
- X val = StrToBool(argv[1]);
- X if (val < 0) {
- X (void) printf("%s: bad debugging value.\n", argv[1]);
- X code = -1;
- X return;
- X }
- X } else
- X val = !debug;
- X debug = val;
- X fix_options();
- X if (IS_VVERBOSE)
- X (void) printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
- X code = debug > 0;
- X} /* debug */
- X
- X
- X
- Xvoid fix_options(void)
- X{
- X if (debug)
- X options |= SO_DEBUG;
- X else
- X options &= ~SO_DEBUG;
- X} /* fix_options */
- X
- X
- X
- X/*
- X * Set current working directory
- X * on remote machine.
- X */
- Xint cd(int argc, char **argv)
- X{
- X if (argc < 2)
- X argv = re_makeargv("(remote-directory) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage:%s remote-directory\n", argv[0]);
- X code = -1;
- X return;
- X }
- X (void) _cd(argv[1]);
- X} /* cd */
- X
- X
- X
- X
- Xint implicit_cd(char *dir)
- X{
- X int i, j = 0;
- X
- X if (connected) {
- X i = verbose;
- X /* Special verbosity level that ignores errors and prints other stuff,
- X * so you will get just the unknown command message and not an error
- X * message from cd.
- X */
- X verbose = V_IMPLICITCD;
- X j = _cd(dir);
- X verbose = i;
- X }
- X return j;
- X} /* implicit_cd */
- X
- X
- X
- X
- Xint _cd(char *dir)
- X{
- X register char *cp;
- X int result = 0, tmpverbose;
- X string str;
- X
- X if (dir == NULL)
- X goto getrwd;
- X /* Won't work because glob really is a ls, so 'cd pu*' will match
- X * pub/README, pub/file2, etc.
- X * if (result = rem_glob_one(dir) < 0)
- X * return result;
- X */
- X if (strncmp(dir, "CDUP", (size_t) 4) == 0)
- X (void) Strncpy(str, dir);
- X else
- X (void) sprintf(str, "CWD %s", dir);
- X if (command(str) != 5) {
- Xgetrwd:
- X /* (void) Strncpy(cwd, dir); */
- X tmpverbose = verbose; verbose = V_QUIET;
- X (void) command("PWD");
- X verbose = tmpverbose;
- X cp = rindex(reply_string, '\"');
- X if (cp != NULL) {
- X result = 1;
- X *cp = '\0';
- X cp = index(reply_string, '\"');
- X if (cp != NULL)
- X (void) Strncpy(cwd, ++cp);
- X }
- X }
- X if (debug > 0)
- X (void) printf("---> Current remote directory is \"%s\"\n", cwd);
- X return (result);
- X} /* _cd */
- X
- X
- X
- X
- X/*
- X * Set current working directory
- X * on local machine.
- X */
- Xint lcd(int argc, char **argv)
- X{
- X if (argc < 2)
- X argc++, argv[1] = home;
- X if (argc != 2) {
- X (void) printf("usage:%s local-directory\n", argv[0]);
- X code = -1;
- X return;
- X }
- X if (!globulize(&argv[1])) {
- X code = -1;
- X return;
- X }
- X if (chdir(argv[1]) < 0) {
- X Perror(argv[1]);
- X code = -1;
- X return;
- X }
- X (void) get_cwd(lcwd, (int) sizeof(lcwd));
- X if (IS_VVERBOSE)
- X (void) printf("Local directory now %s\n", lcwd);
- X code = 0;
- X} /* lcd */
- X
- X
- X
- X
- X/*
- X * Delete a single file.
- X */
- Xint do_delete(int argc, char **argv)
- X{
- X string str;
- X
- X if (argc < 2)
- X argv = re_makeargv("(remote file to delete) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage:%s remote-file\n", argv[0]);
- X code = -1;
- X return;
- X }
- X if (rem_glob_one(argv[1]) == 0) {
- X (void) sprintf(str, "DELE %s", argv[1]);
- X (void) command(str);
- X }
- X} /* do_delete */
- X
- X
- X
- X
- X/*
- X * Delete multiple files.
- X */
- Xint mdelete(int argc, char **argv)
- X{
- X char *cp;
- X void (*oldintr)(int);
- X string str;
- X
- X if (argc < 2)
- X argv = re_makeargv("(remote-files) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage:%s remote-files\n", argv[0]);
- X code = -1;
- X return;
- X }
- X mname = argv[0];
- X activemcmd = 1;
- X oldintr = signal(SIGINT, mabort);
- X (void) setjmp(jabort);
- X while ((cp = remglob(argv)) != NULL) {
- X if (*cp == '\0') {
- X activemcmd = 0;
- X continue;
- X }
- X if (activemcmd && confirm(argv[0], cp)) {
- X (void) sprintf(str, "DELE %s", cp);
- X (void) command(str);
- X if (!activemcmd && fromatty) {
- X if (confirm("Continue with", "mdelete")) {
- X activemcmd++;
- X }
- X }
- X }
- X }
- X (void) signal(SIGINT, oldintr);
- X activemcmd = 0;
- X} /* mdelete */
- X
- X
- X
- X
- X/*
- X * Rename a remote file.
- X */
- Xint renamefile(int argc, char **argv)
- X{
- X string str;
- X
- X if (argc < 2)
- X argv = re_makeargv("(from-name) ", &argc);
- X if (argc < 2) {
- Xusage:
- X (void) printf("%s from-name to-name\n", argv[0]);
- X code = -1;
- X return;
- X }
- X if (argc < 3)
- X argv = re_makeargv("(to-name) ", &argc);
- X if (argc < 3)
- X goto usage;
- X if (rem_glob_one(argv[1]) < 0)
- X return;
- X (void) sprintf(str, "RNFR %s", argv[1]);
- X if (command(str) == CONTINUE) {
- X (void) sprintf(str, "RNTO %s", argv[1]);
- X (void) command(str);
- X }
- X} /* renamefile */
- X
- X
- X
- X/*
- X * Get a directory listing
- X * of remote files.
- X */
- Xint ls(int argc, char **argv)
- X{
- X char *whichcmd, *cp;
- X str32 lsflags;
- X string remote, local, str;
- X int listmode, pagemode, i;
- X
- X#ifdef REDIR
- X register struct lslist *a, *b;
- X for (a = lshead; a != NULL; ) {
- X b = a->next;
- X if (a->string)
- X free(a->string); /* free string */
- X free(a); /* free node */
- X a = b;
- X }
- X lshead = lstail = NULL;
- X#endif
- X
- X pagemode = 0;
- X switch (**argv) {
- X case 'p': /* pls, pdir, pnlist */
- X pagemode = 1;
- X listmode = argv[0][1] == 'd';
- X break;
- X case 'd': /* dir */
- X listmode = 1;
- X break;
- X default: /* ls, nlist */
- X listmode = 0;
- X }
- X whichcmd = listmode ? "LIST" : "NLST";
- X
- X (void) strncpy(local, (pagemode ? pager : "-"), sizeof(local));
- X remote[0] = lsflags[0] = 0;
- X
- X /* Possible scenarios:
- X * 1. ls
- X * 2. ls -flags
- X * 3. ls directory
- X * 4. ls -flags >outfile
- X * 5. ls directory >outfile
- X * 6. ls -flags directory
- X * 7. ls -flags directory >outfile
- X */
- X
- X for (i=1; i<argc; i++) {
- X switch (argv[i][0]) {
- X case '-':
- X /*
- X * If you give more than one set of flags, concat the each
- X * additional set to the first one (without the dash).
- X */
- X (void) strncat(lsflags, (argv[i] + (lsflags[0] == '-')), sizeof(lsflags));
- X break;
- X case '|':
- X case '>': (void) Strncpy(local, argv[i] + (argv[i][0] == '>')); break;
- X default:
- X if (remote[0] != 0) {
- X printf("ls: only one directory at a time please (or don't forget the '>' in >outfile).\n");
- Xlsusage:
- X (void) printf("usage: %s [-flags] [remote-directory] [>local-file]\n", argv[0]);
- X code = -1;
- X return;
- X }
- X /*
- X * In case you want to get a remote file called '--README--'
- X * or '>README,' you can use '\--README--' and '\>README.'
- X */
- X (void) strncpy(remote, ((argv[i][0] == '\\') && (argv[i][1] != 0)) ? argv[i] + 1 : argv[i], sizeof(remote));
- X } /* end switch */
- X } /* end loop */
- X
- X /*
- X * If we are given an ls with some flags, make sure we use
- X * columnized output (-C) unless one column output (-1) is
- X * specified.
- X */
- X if (!listmode) {
- X if (lsflags[0] != 0) {
- X (void) Strncpy(str, lsflags);
- X for (cp = str + 1; *cp; cp++)
- X if (*cp == '1')
- X goto aa;
- X (void) sprintf(lsflags, "-FC%s", str + 1);
- X } else {
- X if (remote_is_unix)
- X (void) strcpy(lsflags, "-FC");
- X }
- X }
- Xaa: if (strcmp(local, "-") != 0) {
- X char *lp = local;
- X
- X if ((!globulize(&lp)) || ((local[0] != '|') && (!confirm("Output to local-file: ", local)))) {
- X code = -1;
- X return;
- X }
- X if (lp != local) {
- X (void) Strncpy(str, lp);
- X (void) Strncpy(local, str);
- X }
- X }
- X#ifdef REDIR
- X is_ls=1; /* tells getreply() to buffer output on a lshead list */
- X#endif
- X (void) Strncpy(str, remote);
- X if (lsflags[0] && remote[0])
- X (void) sprintf(remote, "%s%c%s", lsflags, LS_FLAGS_AND_FILE, str);
- X else
- X (void) strncpy(remote, lsflags[0] ? lsflags : str, sizeof(remote));
- X recvrequest(whichcmd, local, (remote[0] == 0 ? NULL : remote), "w");
- X#ifdef REDIR
- X is_ls=0;
- X#endif
- X} /* ls */
- X
- X
- X
- X
- X/*
- X * Get a directory listing
- X * of multiple remote files.
- X */
- Xint mls(int argc, char **argv)
- X{
- X char *cmd, mode[1], *dest;
- X int i;
- X void (*oldintr)(int);
- X
- X if (argc < 2)
- X argv = re_makeargv("(remote-files) ", &argc);
- X if (argc < 3)
- X argv = re_makeargv("(local-file) ", &argc);
- X if (argc < 3) {
- X (void) printf("usage:%s remote-files local-file\n", argv[0]);
- X code = -1;
- X return;
- X }
- X dest = argv[argc - 1];
- X argv[argc - 1] = NULL;
- X if (strcmp(dest, "-") && *dest != '|')
- X if (!globulize(&dest) || !confirm("output to local-file:", dest)) {
- X code = -1;
- X return;
- X }
- X cmd = argv[0][1] != 'd' ? "NLST" : "LIST";
- X mname = argv[0];
- X activemcmd = 1;
- X oldintr = signal(SIGINT, mabort);
- X (void) setjmp(jabort);
- X for (i = 1; activemcmd && i < argc-1; ++i) {
- X *mode = (i == 1) ? 'w' : 'a';
- X recvrequest(cmd, dest, argv[i], mode);
- X if (!activemcmd && fromatty) {
- X if (confirm("Continue with", argv[0])) {
- X activemcmd++;
- X }
- X }
- X }
- X (void) signal(SIGINT, oldintr);
- X activemcmd = 0;
- X} /* mls */
- X
- X
- X
- X
- X/*
- X * Do a shell escape
- X */
- X/*ARGSUSED*/
- Xint shell(int argc, char **argv)
- X{
- X int pid;
- X void (*old1)(int), (*old2)(int);
- X char *theShell, *namep;
- X#ifndef U_WAIT
- X int Status;
- X#else
- X union wait Status;
- X#endif
- X string str;
- X
- X old1 = signal (SIGINT, SIG_IGN);
- X old2 = signal (SIGQUIT, SIG_IGN);
- X if ((pid = fork()) == 0) {
- X for (pid = 3; pid < 20; pid++)
- X (void) close(pid);
- X (void) signal(SIGINT, SIG_DFL);
- X (void) signal(SIGQUIT, SIG_DFL);
- X if ((theShell = getenv("SHELL")) == NULL)
- X theShell = uinfo.shell;
- X if (theShell == NULL)
- X theShell = "/bin/sh";
- X namep = rindex(theShell, '/');
- X if (namep == NULL)
- X namep = theShell;
- X (void) strcpy(str, "-");
- X (void) strcat(str, ++namep);
- X if (strcmp(namep, "sh") != 0)
- X str[0] = '+';
- X if (debug) {
- X (void) printf ("%s\n", theShell);
- X (void) fflush (stdout);
- X }
- X if (argc > 1)
- X (void) execl(theShell, str, "-c", altarg, (char *)0);
- X else
- X (void) execl(theShell, str, (char *)0);
- X Perror(theShell);
- X code = -1;
- X exit(1);
- X }
- X if (pid > 0)
- X while (wait((void *) &Status) != pid)
- X ;
- X (void) signal(SIGINT, old1);
- X (void) signal(SIGQUIT, old2);
- X if (pid == -1) {
- X Perror("Try again later");
- X code = -1;
- X } else code = 0;
- X return (0);
- X} /* shell */
- X
- X
- X
- X
- X/*
- X * Send new user information (re-login)
- X */
- Xint do_user(int argc, char **argv)
- X{
- X char acct[80];
- X int n, aflag = 0;
- X string str;
- X
- X if (argc < 2)
- X argv = re_makeargv("(username) ", &argc);
- X if (argc > 4) {
- X (void) printf("usage: %s username [password] [account]\n", argv[0]);
- X code = -1;
- X return (0);
- X }
- X (void) sprintf(str, "USER %s", argv[1]);
- X n = command(str);
- X if (n == CONTINUE) {
- X if (argc < 3 )
- X argv[2] = Getpass("Password: "), argc++;
- X (void) sprintf(str, "PASS %s", argv[2]);
- X n = command(str);
- X }
- X if (n == CONTINUE) {
- X if (argc < 4) {
- X (void) printf("Account: "); (void) fflush(stdout);
- X (void) FGets(acct, stdin);
- X acct[strlen(acct) - 1] = '\0';
- X argv[3] = acct; argc++;
- X }
- X (void) sprintf(str, "ACCT %s", argv[3]);
- X n = command(str);
- X aflag++;
- X }
- X if (n != COMPLETE) {
- X (void) fprintf(stdout, "Login failed.\n");
- X return (0);
- X }
- X if (!aflag && argc == 4) {
- X (void) sprintf(str, "ACCT %s", argv[3]);
- X (void) command(str);
- X }
- X return (1);
- X} /* user */
- X
- X
- X
- X
- X/*
- X * Print working directory.
- X */
- X/*ARGSUSED*/
- Xint pwd(int argc, char **argv)
- X{
- X int tmpverbose = verbose;
- X verbose = V_VERBOSE;
- X (void) command("PWD");
- X verbose = tmpverbose;
- X} /* pwd */
- X
- X
- X
- X
- X/*
- X * Make a directory.
- X */
- Xint makedir(int argc, char **argv)
- X{
- X string str;
- X
- X if (argc < 2)
- X argv = re_makeargv("(directory-name) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage: %s directory-name\n", argv[0]);
- X code = -1;
- X return;
- X }
- X (void) sprintf(str, "MKD %s", argv[1]);
- X (void) command(str);
- X} /* makedir */
- X
- X
- X
- X
- X/*
- X * Remove a directory.
- X */
- Xint removedir(int argc, char **argv)
- X{
- X string str;
- X if (argc < 2)
- X argv = re_makeargv("(directory-name) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage: %s directory-name\n", argv[0]);
- X code = -1;
- X return;
- X }
- X if (rem_glob_one(argv[1]) == 0) {
- X (void) sprintf(str, "RMD %s", argv[1]);
- X (void) command(str);
- X }
- X} /* removedir */
- X
- X
- X
- X
- X/*
- X * Send a line, verbatim, to the remote machine.
- X */
- Xint quote(int argc, char **argv)
- X{
- X int i, tmpverbose;
- X string str;
- X
- X if (argc < 2)
- X argv = re_makeargv("(command line to send) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage: %s line-to-send\n", argv[0]);
- X code = -1;
- X return;
- X }
- X (void) Strncpy(str, argv[1]);
- X for (i = 2; i < argc; i++) {
- X (void) Strncat(str, " ");
- X (void) Strncat(str, argv[i]);
- X }
- X tmpverbose = verbose;
- X verbose = V_VERBOSE;
- X if (command(str) == PRELIM) {
- X while (getreply(0) == PRELIM);
- X }
- X verbose = tmpverbose;
- X} /* quote */
- X
- X
- X
- X
- X/*
- X * Ask the other side for help.
- X */
- Xint rmthelp(int argc, char **argv)
- X{
- X int oldverbose = verbose;
- X string str;
- X
- X verbose = V_VERBOSE;
- X if (argc == 1) (void) command("HELP");
- X else {
- X (void) sprintf(str, "HELP %s", argv[1]);
- X (void) command(str);
- X }
- X verbose = oldverbose;
- X} /* rmthelp */
- X
- X
- X
- X
- X/*
- X * Terminate session and exit.
- X */
- X/*ARGSUSED*/
- Xint quit(int argc, char **argv)
- X{
- X close_up_shop();
- X trim_log();
- X exit(0);
- X} /* quit */
- X
- X
- X
- Xvoid close_streams(int wantShutDown)
- X{
- X if (cout != NULL) {
- X if (wantShutDown)
- X (void) shutdown(fileno(cout), 1+1);
- X (void) fclose(cout);
- X cout = NULL;
- X }
- X if (cin != NULL) {
- X if (wantShutDown)
- X (void) shutdown(fileno(cin), 1+1);
- X (void) fclose(cin);
- X cin = NULL;
- X }
- X} /* close_streams */
- X
- X
- X
- X
- X/*
- X * Terminate session, but don't exit.
- X */
- X/*ARGSUSED*/
- Xint disconnect(int argc, char **argv)
- X{
- X#ifdef SYSLOG
- X syslog (LOG_INFO, "%s disconnected from %s.", uinfo.username, hostname);
- X#endif
- X
- X (void) command("QUIT");
- X close_streams(0);
- X hostname[0] = cwd[0] = 0;
- X connected = 0;
- X data = -1;
- X macnum = 0;
- X} /* disconnect */
- X
- X
- X
- X
- Xint confirm(char *cmd, char *file)
- X{
- X str32 str;
- X
- X if (!fromatty || (activemcmd && !mprompt))
- X return 1;
- X (void) printf("%s %s? ", cmd, file);
- X (void) fflush(stdout);
- X (void) Gets(str, sizeof(str));
- X return (*str != 'n' && *str != 'N');
- X} /* confirm */
- X
- X
- X
- Xvoid
- Xfatal(char *msg)
- X{
- X (void) fprintf(stderr, "%s: %s\n", progname, msg);
- X close_up_shop();
- X exit(1);
- X} /* fatal */
- X
- X
- X
- Xvoid
- Xclose_up_shop(void)
- X{
- X static int only_once = 0;
- X if (only_once++ > 0)
- X return;
- X if (connected)
- X disconnect(0, NULL);
- X if (logf != NULL) {
- X (void) fclose(logf);
- X logf = NULL;
- X }
- X} /* close_up_shop */
- X
- X
- X
- X
- X/*
- X * Glob a local file name specification with
- X * the expectation of a single return value.
- X * Can't control multiple values being expanded
- X * from the expression, we return only the first.
- X */
- Xint globulize(char **cpp)
- X{
- X char **globbed;
- X
- X globbed = glob(*cpp);
- X if (globerr != NULL) {
- X (void) printf("%s: %s\n", *cpp, globerr);
- X if (globbed) {
- X blkfree(globbed);
- X free(globbed);
- X }
- X return (0);
- X }
- X if (globbed) {
- X *cpp = *globbed++;
- X /* don't waste too much memory */
- X if (*globbed) {
- X blkfree(globbed);
- X free(globbed);
- X }
- X }
- X return (1);
- X} /* globulize */
- X
- X
- X
- X/* change directory to perent directory */
- X/*ARGSUSED*/
- Xint cdup(int argc, char **argv)
- X{
- X (void) _cd("CDUP");
- X}
- X
- X
- X/* show remote system type */
- X/*ARGSUSED*/
- Xint syst(int argc, char **argv)
- X{
- X (void) command("SYST");
- X}
- X
- X
- X
- X
- Xint make_macro(char *name, FILE *fp)
- X{
- X char *tmp;
- X char *cp;
- X string str;
- X size_t len;
- X
- X if (macnum == MAXMACROS) {
- X (void) fprintf(stderr, "Limit of %d macros have already been defined.\n", MAXMACROS);
- X return -1;
- X }
- X (void) strncpy(macros[macnum].mac_name, name, (size_t)8);
- X if (macnum == 0)
- X macros[macnum].mac_start = macbuf;
- X else
- X macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
- X tmp = macros[macnum].mac_start;
- X while (1) {
- X cp = fgets(str, sizeof(str) - 1, fp);
- X if (cp == NULL) {
- X /*
- X * If we had started a macro, we will say it is
- X * okay to skip the blank line delimiter if we
- X * are at the EOF.
- X */
- X if (tmp > macros[macnum].mac_start)
- X goto endmac;
- X (void) fprintf(stderr, "No text supplied for macro \"%s.\"\n", name);
- X }
- X /* see if we have a 'blank' line: just whitespace. */
- X while (*cp && isspace(*cp)) ++cp;
- X if (*cp == '\0') {
- X /* Blank line; end this macro. */
- Xendmac:
- X macros[macnum++].mac_end = tmp;
- X return 0;
- X }
- X len = strlen(cp) + 1; /* we need the \0 too. */
- X if (tmp + len >= macbuf + MACBUFLEN) {
- X (void) fprintf(stderr, "Macro \"%s\" not defined -- %d byte buffer exceeded.\n", name, MACBUFLEN);
- X return -1;
- X }
- X (void) strcpy(tmp, cp);
- X tmp += len;
- X }
- X} /* make_macro */
- X
- X
- X
- X
- Xint macdef(int argc, char **argv)
- X{
- X if (argc < 2)
- X argv = re_makeargv("(macro name) ", &argc);
- X if (argc != 2) {
- X (void) printf("Usage: %s macro_name\n", argv[0]);
- X domacro(0, NULL);
- X return;
- X }
- X (void) printf("Enter macro line by line, terminating it with a blank line\n");
- X code = make_macro(argv[1], stdin);
- X} /* macdef */
- X
- X
- X
- X
- Xint domacro(int argc, char **argv)
- X{
- X register int i, j;
- X register char *cp1, *cp2;
- X int count = 2, loopflg = 0;
- X string str;
- X struct cmd *c;
- X
- X if (argc < 2) {
- X /* print macros. */
- X if (macnum == 0)
- X (void) printf("No macros defined.\n");
- X else {
- X printf("Current macro definitions:\n");
- X for (i = 0; i < macnum; ++i) {
- X (void) printf("%s:\n", macros[i].mac_name);
- X cp1 = macros[i].mac_start;
- X cp2 = macros[i].mac_end;
- X while (cp1 < cp2) {
- X (void) printf(" > ");
- X while (cp1 < cp2 && *cp1)
- X putchar(*cp1++);
- X ++cp1;
- X }
- X }
- X }
- X if (argc == 0) return; /* called from macdef(), above. */
- X argv = re_makeargv("(macro to run) ", &argc);
- X }
- X if (argc < 2) {
- X (void) printf("Usage: %s macro_name.\n", argv[0]);
- X code = -1;
- X return;
- X }
- X for (i = 0; i < macnum; ++i) {
- X if (!strncmp(argv[1], macros[i].mac_name, (size_t) 9)) {
- X break;
- X }
- X }
- X if (i == macnum) {
- X (void) printf("'%s' macro not found.\n", argv[1]);
- X code = -1;
- X return;
- X }
- X (void) Strncpy(str, line);
- XTOP:
- X cp1 = macros[i].mac_start;
- X while (cp1 != macros[i].mac_end) {
- X while (isspace(*cp1)) {
- X cp1++;
- X }
- X cp2 = line;
- X while (*cp1 != '\0') {
- X switch(*cp1) {
- X case '\\':
- X *cp2++ = *++cp1;
- X break;
- X case '$':
- X if (isdigit(*(cp1+1))) {
- X j = 0;
- X while (isdigit(*++cp1)) {
- X j = 10*j + *cp1 - '0';
- X }
- X cp1--;
- X if (argc - 2 >= j) {
- X (void) strcpy(cp2, argv[j+1]);
- X cp2 += strlen(argv[j+1]);
- X }
- X break;
- X }
- X if (*(cp1+1) == 'i') {
- X loopflg = 1;
- X cp1++;
- X if (count < argc) {
- X (void) strcpy(cp2, argv[count]);
- X cp2 += strlen(argv[count]);
- X }
- X break;
- X }
- X /* intentional drop through */
- X default:
- X *cp2++ = *cp1;
- X break;
- X }
- X if (*cp1 != '\0') {
- X cp1++;
- X }
- X }
- X *cp2 = '\0';
- X makeargv();
- X c = getcmd(margv[0]);
- X if ((c == (struct cmd *)-1) && !parsing_rc) {
- X (void) printf("?Ambiguous command\n");
- X code = -1;
- X }
- X else if (c == NULL && !parsing_rc) {
- X (void) printf("?Invalid command\n");
- X code = -1;
- X } else if (c->c_conn && !connected) {
- X (void) printf("Not connected.\n");
- X code = -1;
- X } else {
- X if (IS_VVERBOSE)
- X (void) printf("%s\n",line);
- X (*c->c_handler)(margc, margv);
- X (void) strcpy(line, str);
- X makeargv();
- X argc = margc;
- X argv = margv;
- X }
- X if (cp1 != macros[i].mac_end) {
- X cp1++;
- X }
- X }
- X if (loopflg && ++count < argc) {
- X goto TOP;
- X }
- X} /* domacro */
- X
- X
- X
- X/*
- X * get size of file on remote machine
- X */
- Xint sizecmd(int argc, char **argv)
- X{
- X string str;
- X int oldv;
- X
- X if (argc < 2)
- X argv = re_makeargv("(remote-file) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage:%s filename\n", argv[0]);
- X code = -1;
- X return;
- X }
- X if (rem_glob_one(argv[1]) == 0) {
- X (void) sprintf(str, "SIZE %s", argv[1]);
- X oldv = verbose;
- X verbose = V_VERBOSE;
- X (void) command(str);
- X verbose = oldv;
- X }
- X} /* sizecmd */
- X
- X
- X
- X
- X/*
- X * get last modification time of file on remote machine
- X */
- Xint modtime(int argc, char **argv)
- X{
- X int overbose;
- X string str;
- X
- X if (argc < 2)
- X argv = re_makeargv("(remote-file) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage:%s filename\n", argv[0]);
- X code = -1;
- X return;
- X }
- X if (rem_glob_one(argv[1]) == 0) {
- X overbose = verbose;
- X if (debug == 0)
- X verbose = V_QUIET;
- X (void) sprintf(str, "MDTM %s", argv[1]);
- X if (command(str) == COMPLETE) {
- X int yy, mo, day, hour, min, sec;
- X (void) sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
- X &day, &hour, &min, &sec);
- X /* might want to print this in local time */
- X (void) printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
- X mo, day, yy, hour, min, sec);
- X } else
- X (void) fputs(reply_string, stdout);
- X verbose = overbose;
- X }
- X} /* modtime */
- X
- X
- X
- Xint lookup(int argc, char **argv)
- X{
- X int i, j, by_name, result = 0;
- X unsigned long addr; /* address in host order */
- X struct hostent *host; /* structure returned by gethostbyaddr() */
- X extern int h_errno;
- X
- X if (argc < 2)
- X argv = re_makeargv("(sitename) ", &argc);
- X if (argc < 2) {
- X (void) printf("usages:\n\t%s <sitenames>\n\t%s <ip numbers>\n",
- X argv[0], argv[0]);
- X }
- X
- X lasthostname[0] = 0;
- X for (i=1; i<argc; i++) {
- X /* does the argument look like an address? */
- X if (4 == sscanf (argv[i], "%d.%d.%d.%d", &j, &j, &j, &j)) {
- X /* ip */
- X if ((addr = inet_addr (argv[i])) == 0xffffffff) {
- X (void) fprintf(stderr, "## could not convert \"%s\" into a valid IP address.\n", argv[i]);
- X continue;
- X }
- X host = gethostbyaddr ((char *) &addr, 4, AF_INET);
- X by_name = 0;
- X } else {
- X /* name */
- X host = gethostbyname (argv[i]);
- X by_name = 1;
- X }
- X if (host == NULL) {
- X if (NOT_VQUIET) {
- X /* gethostxxx error */
- X result = h_errno;
- X if (h_errno == HOST_NOT_FOUND) {
- X (void) printf("%s: lookup error (%d).\n",
- X argv[i], h_errno);
- X result = h_errno;
- X } else {
- X (void) printf("%s \"%s\"\n",
- X (by_name==0 ? "unknown address" : "unknown host"),
- X argv[i]);
- X result =
- X h_errno != 0 ? h_errno :
- X -1;
- X }
- X }
- X } else {
- X if (*host->h_name)
- X Strncpy(lasthostname, host->h_name);
- X if (NOT_VQUIET) {
- X (void) printf("%-32s ", *host->h_name ? host->h_name : "???");
- X if (*host->h_addr_list) {
- X unsigned long horder;
- X
- X horder = ntohl (*(unsigned long *) *(char **)host->h_addr_list);
- X (void) printf ("%lu.%lu.%lu.%lu\n",
- X (horder >> 24),
- X (horder >> 16) & 0xff,
- X (horder >> 8) & 0xff,
- X horder & 0xff);
- X }
- X else (void) printf("???\n");
- X }
- X }
- X } /* loop thru all sites */
- X return result;
- X} /* lookup */
- X
- X
- X
- X
- Xint getlocalhostname(char *host, size_t size)
- X{
- X int oldv, r;
- X char *argv[2];
- X
- X#ifdef HOSTNAME
- X (void) strncpy(host, HOSTNAME, size);
- X return 0;
- X#else
- X *host = 0;
- X if ((r = gethostname(host, size)) == 0) {
- X oldv = verbose;
- X verbose = V_QUIET;
- X argv[0] = "lookup";
- X (void) sprintf(line, "lookup %s", host);
- X (void) makeargv();
- X if (lookup(margc, margv) == 0 && lasthostname[0])
- X (void) strncpy(host, lasthostname, size);
- X verbose = oldv;
- X }
- X return r;
- X#endif
- X} /* getlocalhostname */
- X
- X
- X
- X
- X/*
- X * show status on remote machine
- X */
- Xint rmtstatus(int argc, char **argv)
- X{
- X string str;
- X if (argc > 1) {
- X (void) sprintf(str, "STAT %s" , argv[1]);
- X (void) command(str);
- X } else (void) command("STAT");
- X} /* rmtstatus */
- X
- X
- X
- X
- X/*
- X * create an empty file on remote machine.
- X */
- Xint create(int argc, char **argv)
- X{
- X string str;
- X FILE *ftemp;
- X
- X if (argc < 2)
- X argv = re_makeargv("(remote-file) ", &argc);
- X if (argc < 2) {
- X (void) printf("usage:%s filename\n", argv[0]);
- X code = -1;
- X return;
- X }
- X (void) tmp_name(str);
- X ftemp = fopen(str, "w");
- X /* (void) fputc('x', ftemp); */
- X (void) fclose(ftemp);
- X creating = 1;
- X sendrequest("STOR", str, argv[1]);
- X creating = 0;
- X (void) unlink(str);
- X} /* create */
- X
- X
- X
- X
- X/* show version info */
- X/*ARGSUSED*/
- Xint show_version(int argc, char **argv)
- X{
- X char *DStrs[20];
- X int nDStrs = 0, i, j;
- X
- X (void) printf("%s\n%-30s %s\n", version, "Author:",
- X "Mike Gleason, NCEMRSoft (mgleason@cse.unl.edu).");
- X
- X/* Now entering CPP hell... */
- X#ifdef __DATE__
- X (void) printf("%-30s %s\n", "Compile Date:", __DATE__);
- X#endif
- X (void) printf("%-30s %s (%s)\n", "Operating System:",
- X#ifdef System
- X System,
- X#else
- X# ifdef unix
- X "UNIX",
- X# else
- X "??",
- X# endif
- X#endif
- X#ifdef SYSV
- X "SYSV");
- X#else
- X# ifdef BSD
- X "BSD");
- X# else
- X "neither BSD nor SYSV?");
- X# endif
- X#endif
- X
- X /* Show which CPP symbols were used in compilation. */
- X#ifdef __GNUC__
- X DStrs[nDStrs++] = "__GNUC__";
- X#endif
- X#ifdef RINDEX
- X DStrs[nDStrs++] = "RINDEX";
- X#endif
- X#ifdef CURSES
- X DStrs[nDStrs++] = "CURSES";
- X#endif
- X#ifdef HERROR
- X DStrs[nDStrs++] = "HERROR";
- X#endif
- X#ifdef U_WAIT
- X DStrs[nDStrs++] = "U_WAIT";
- X#endif
- X#if defined(CONST) || defined(const)
- X DStrs[nDStrs++] = "CONST";
- X#endif
- X#ifdef GETPASS
- X DStrs[nDStrs++] = "GETPASS";
- X#endif
- X#ifdef GETCWDSIZET
- X DStrs[nDStrs++] = "GETCWDSIZET";
- X#endif
- X#ifdef HOSTNAME
- X DStrs[nDStrs++] = "HOSTNAME";
- X#endif
- X#ifdef SYSDIRH
- X DStrs[nDStrs++] = "SYSDIRH";
- X#endif
- X#ifdef SYSSELECTH
- X DStrs[nDStrs++] = "SYSSELECTH";
- X#endif
- X#ifdef NO_UNISTDH
- X DStrs[nDStrs++] = "NO_UNISTDH";
- X#endif
- X#ifdef NO_STDLIBH
- X DStrs[nDStrs++] = "NO_STDLIBH";
- X#endif
- X#ifdef SYSLOG
- X DStrs[nDStrs++] = "SYSLOG";
- X#endif
- X#ifdef REDIR
- X DStrs[nDStrs++] = "REDIR";
- X#endif
- X#ifdef BAD_INETADDR
- X DStrs[nDStrs++] = "BAD_INETADDR";
- X#endif
- X#ifdef SGTTYB
- X DStrs[nDStrs++] = "SGTTYB";
- X#endif
- X#ifdef TERMIOS
- X DStrs[nDStrs++] = "TERMIOS";
- X#endif
- X#ifdef _POSIX_SOURCE
- X DStrs[nDStrs++] = "_POSIX_SOURCE";
- X#endif
- X
- X
- X (void) printf ("\nCompile Options:\n");
- X for (i=j=0; i<nDStrs; i++) {
- X if (j == 0)
- X (void) printf(" ");
- X (void) printf("%-15s", DStrs[i]);
- X if (++j == 4) {
- X j = 0;
- X (void) putchar('\n');
- X }
- X }
- X if (j != 0)
- X (void) putchar('\n');
- X
- X (void) printf("\nDefaults:\n");
- X (void) printf("\
- X Xfer Buf Size: %8d Debug: %d MPrompt: %d Verbosity: %d\n\
- X Prompt: %s Pager: %s ZCat: %s\n\
- X Logname: %s Logging: %d Type: %s Cmd Len: %d\n\
- X Recv Line Len: %d #Macros: %d Macbuf: %d Auto-Binary: %d\n\
- X Redial Delay: %d New Mail Message: \"%s\"\n",
- X MAX_XFER_BUFSIZE, dDEBUG, dMPROMPT, dVERBOSE,
- X dPROMPT, dPAGER, ZCAT,
- X dLOGNAME, dLOGGING, dTYPESTR, CMDLINELEN,
- X RECEIVEDLINELEN, MAXMACROS, MACBUFLEN, dAUTOBINARY,
- X dREDIALDELAY, NEWMAILMESSAGE
- X );
- X} /* show_version */
- X
- X
- X
- Xvoid Perror(char *s)
- X{
- X extern int errno;
- X
- X if (NOT_VQUIET) {
- X if (s != NULL)
- X (void) fprintf(stderr, "NcFTP: %s (%d): ", s, errno);
- X perror(NULL);
- X }
- X} /* Perror */
- X
- X
- X
- X#ifdef REDIR
- X/*ARGSUSED*/
- Xint showlsbuffer(int argc, char **argv)
- X{
- X register struct lslist *a = lshead;
- X int pagemode;
- X FILE *fp;
- X void (*oldintp)(int);
- X
- X if (a == NULL)
- X return;
- X pagemode= (**argv) == 'p' && pager[0] == '|';
- X if (pagemode) {
- X fp = popen(pager + 1, "w");
- X if (!fp) {
- X Perror(pager + 1);
- X return;
- X }
- X } else
- X fp = stdout;
- X oldintp = signal(SIGPIPE, SIG_IGN);
- X while (a) {
- X if (a->string)
- X (void) fprintf(fp, "%s\n", a->string);
- X a = a->next;
- X }
- X if (pagemode)
- X (void) pclose(fp);
- X if (oldintp)
- X signal(SIGPIPE, oldintp);
- X} /* showlsbuffer */
- X#endif
- X
- X/* eof cmds.c */
- END_OF_FILE
- if test 48279 -ne `wc -c <'cmds.c'`; then
- echo shar: \"'cmds.c'\" unpacked with wrong size!
- fi
- # end of 'cmds.c'
- fi
- if test -f 'ftp.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ftp.h'\"
- else
- echo shar: Extracting \"'ftp.h'\" \(852 characters\)
- sed "s/^X//" >'ftp.h' <<'END_OF_FILE'
- X/* ftp.h */
- X
- X#ifndef _ftp_h_
- X#define _ftp_h_
- X
- X#define IS_FILE 1
- X#define IS_STREAM 0
- X#define IS_PIPE -1
- X
- X/* Progress-meter types. */
- X#define pr_none 0
- X#define pr_percent 1
- X#define pr_philbar 2
- X#define pr_kbytes 3
- X
- Xint hookup(char *host, int port);
- Xint login(char *, int, int);
- Xvoid cmdabort(int unused);
- Xint command(char *cmd);
- Xint getreply(int expecteof);
- Xvoid abortsend(int unused);
- Xvoid sendrequest(char *cmd, char *local, char *remote);
- Xvoid abortrecv(int unused);
- Xvoid recvrequest(char *cmd, char *local, char *remote, char *mode);
- Xint initconn(void);
- XFILE *dataconn(char *mode);
- Xvoid close_file(FILE **fin, int filetype);
- Xlong get_remote_size(char *remote, int filetype);
- Xint start_progress(int sending, char *local);
- Xvoid progress_report(int);
- Xvoid end_progress(char *direction, char *local, char *remote);
- X
- X#endif /* _ftp_h_ */
- X
- X/* eof ftp.h */
- END_OF_FILE
- if test 852 -ne `wc -c <'ftp.h'`; then
- echo shar: \"'ftp.h'\" unpacked with wrong size!
- fi
- # end of 'ftp.h'
- fi
- echo shar: End of archive 1 \(of 4\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 3 4 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 4 archives.
- rm -f ark[1-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-