home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume34
/
ncftp
/
part01
next >
Wrap
Text File
|
1992-12-08
|
55KB
|
2,492 lines
Newsgroups: comp.sources.misc
From: mgleason@cse.unl.edu (Mike Gleason)
Subject: v34i014: ncftp - Alternative User Interface for FTP, Part01/03
Message-ID: <csm-v34i014=ncftp.150928@sparky.IMD.Sterling.COM>
X-Md4-Signature: 9ee3036605bd11603fa19c3d17f5fe55
Date: Mon, 7 Dec 1992 21:10:05 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: mgleason@cse.unl.edu (Mike Gleason)
Posting-number: Volume 34, Issue 14
Archive-name: ncftp/part01
Environment: UNIX, ANSI-C, getopt
ncftp - Alternative user interface for FTP
version 1.0 by Mike Gleason, NCEMRSoft.
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 :-).
------
#! /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 ftpdefs.h sys.h
# Wrapped by kent@sparky on Mon Dec 7 15:06:54 1992
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 3)."'
if test -f 'cmds.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'cmds.c'\"
else
echo shar: Extracting \"'cmds.c'\" \(44217 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#ifdef SCO324
X# include <net/sys/wait.h>
X#else
X# include <sys/wait.h>
X#endif /* SCO324 */
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 <stdio.h>
X#include <string.h>
X#include <stdlib.h>
X#include <errno.h>
X#include <netdb.h>
X#include <netinet/in.h>
X#include <ctype.h>
X#include <sys/time.h>
X#include <time.h>
X#include <unistd.h>
X#include <termio.h>
X/* #include <sys/ioctl.h> */
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 "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. */
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, want_progress;
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;
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, &want_progress, (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, (setvarproc) 0 }
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
Xchar **re_makeargv(char *promptstr, int *argc)
X{
X (void) strcat(line, " ");
X (void) printf(promptstr);
X (void) gets(&line[strlen(line)]);
X (void) makeargv();
X *argc = margc;
X return (margv);
X} /* re_makeargv */
X
X
X
Xchar *get_cwd(char *buf, int size)
X{
X#ifdef SYSV
X extern char *getcwd(char *, int);
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 optind = 1;
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) {
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 switch (tolower(*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 goto xx;
X default:
X (void) printf("%s: unknown type\n", typename);
X code = -1;
X return;
X }
X p = &types[i];
X (void) sprintf(cmd, "TYPE %s", p->t_mode);
Xxx: 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
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) {
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 (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 bool)
X{
X return (bool ? "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 verbose = StrToBool(argv[1]);
X else verbose = !verbose;
X /* if (verbose > 0) */
X (void) printf("Verbose mode %s.\n", onoff(verbose));
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 verbose = V_QUIET;
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 if (result = rem_glob_one(dir) < 0)
X return result;
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, *remote, *local, *cp;
X str32 lsflags;
X string zpager;
X int listmode, pagemode, defltFlags;
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 remote = NULL;
X if (listmode) { /* dir */
X whichcmd = "LIST";
X } else { /* ls or nlist */
X whichcmd = "NLST";
X if (remote_is_unix) {
X remote = "-CF";
X defltFlags = 1;
X } else {
X defltFlags = 0;
X }
X }
X
X if (pagemode) {
X size_t len = strlen(remote);
X if (remote[len - 1] == 'Z' && remote[len - 2] == '.') {
X /* run uncompress first, then pipe through pager. */
X (void) Strncpy(zpager, "|uncompress ");
X (void) Strncat(zpager, pager);
X local = zpager;
X } else
X local = pager;
X } else
X local = "-";
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
X if (argc > 1) {
X remote = argv[1];
X defltFlags = 0;
X }
X if (argc > 2)
X local = argv[2];
X if (argc > 3) {
X (void) printf("usage: %s [remote-directory | flags] [local-file]\n", argv[0]);
X code = -1;
X return;
X }
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 && !defltFlags && remote != NULL && *remote == '-') {
X for (cp = remote + 1; *cp; cp++)
X if (*cp == '1')
X goto aa;
X (void) sprintf(lsflags, "-CF%s", remote + 1);
X remote = lsflags;
X }
Xaa: if (strcmp(local, "-") != 0 && !globulize(&local)) {
X /* if #2 is not stdout, but there was a glob error, barf. */
X code = -1;
X return;
X }
X if (strcmp(local, "-") != 0 && *local != '|')
X if (!globulize(&local) || !confirm("output to local-file:", local)) {
X code = -1;
X return;
X }
X#ifdef REDIR
X is_ls=1; /* tells getreply() to buffer output on a lshead list */
X#endif
X recvrequest(whichcmd, local, 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 long 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] = getpass2("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;
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 if (command(str) == PRELIM) {
X while (getreply(0) == PRELIM);
X }
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 (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);
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 code = -1;
X return;
X }
X (void) printf("Enter macro line by line, terminating it with a blank line\n");
X code = make_macro(argv[0], 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 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 /* putchar('\n'); */
X }
X }
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) {
X (void) printf("?Ambiguous command\n");
X code = -1;
X }
X else if (c == 0) {
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
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 (void) command(str);
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/* Peter Jaspers-Fayer pjf@osiris.cs.uoguelph.ca Nov'92 */
Xchar *getpass2(char *promptstr)
X{
X static char pass[80]; /* That should be enough! */
X
X struct termio t, s;
X
X (void) printf("%s", promptstr);
X if (0 > ioctl(0, TCGETA, &t))
X Perror("termio failed");
X s.c_lflag = t.c_lflag; /* -- save */
X
X t.c_lflag &= ~ECHO; /* disable echo */
X if (0 > ioctl(0, TCSETA, &t))
X Perror("termio failed");
X
X (void) gets(pass);
X
X t.c_lflag = s.c_lflag; /* -- restore */
X if (0 > ioctl(0, TCSETA, &t))
X Perror("termio failed");
X
X (void) printf("\n"); /* Only because the original did */
X return (pass);
X} /* getpass2 */
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 "??");
X# endif
X#endif
X
X#ifdef RINDEX
X DStrs[nDStrs++] = "RINDEX";
X#endif
X#ifdef HERROR
X DStrs[nDStrs++] = "HERROR";
X#endif
X#ifdef U_WAIT
X DStrs[nDStrs++] = "U_WAIT";
X#endif
X#ifdef const
X DStrs[nDStrs++] = "const";
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 REDIR
X DStrs[nDStrs++] = "REDIR";
X#endif
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 44217 -ne `wc -c <'cmds.c'`; then
echo shar: \"'cmds.c'\" unpacked with wrong size!
fi
# end of 'cmds.c'
fi
if test -f 'ftpdefs.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'ftpdefs.h'\"
else
echo shar: Extracting \"'ftpdefs.h'\" \(644 characters\)
sed "s/^X//" >'ftpdefs.h' <<'END_OF_FILE'
X/* ftpdefs.h */
X
X#ifndef _ftpdefs_h_
X#define _ftpdefs_h_
X
X#define FTP_VERSION "NcFTP 1.0 (6 Dec 92)"
X
Xtypedef char string[128], str32[32];
X
Xstruct userinfo {
X str32 username;
X string homedir;
X string shell;
X string hostname;
X int uid;
X};
X
X/* Your compiler may not like the 'const' directives. If it chokes
X * here, add -Dconst to your SDEFS line in the Makefile, or delete the word
X * const here.
X */
X#define Strncpy(a,b) strncpy((a), (const char *) (b), (size_t) sizeof (a))
X#define Strncat(a,b) strncat((a), (const char *) (b), (size_t) sizeof (a))
X#define FGets(a,b) fgets((a), sizeof(a) - 1, (b))
X
X#endif /* _ftpdefs_h_ */
X/* eof */
END_OF_FILE
if test 644 -ne `wc -c <'ftpdefs.h'`; then
echo shar: \"'ftpdefs.h'\" unpacked with wrong size!
fi
# end of 'ftpdefs.h'
fi
if test -f 'sys.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'sys.h'\"
else
echo shar: Extracting \"'sys.h'\" \(4116 characters\)
sed "s/^X//" >'sys.h' <<'END_OF_FILE'
X/* sys.h */
X
X/*
X * ncftp may need work arounds for some things due to the differences
X * in implementations of unix. The following systems are taken care
X * of automatically:
X *
X * SunOS/Solaris (but use gcc)
X * Silicon Graphics IRIX
X * AIX
X * SINIX
X *
X * For those systems, you should be able to 'make' ncftp without any
X * problems. Otherwise you will have to configure ncftp manually.
X * You will need to add these things to the SDEFS line in the Makefile
X * as applicable.
X *
X * For these systems, some things are taken care of automatically, but
X * you still need to add something to CFLAGS or SDEFS:
X *
X * Hewlett-Packard HP-UX: If you have 7.0, you'll need to find
X * a copy of <ftp.h> from somewhere (8.0 has it though). Then
X * set CFLAGS= -Aa. You may also need to use gcc if your
X * compiler is non-ANSI.
X *
X * SCO Unix: Add -DSCO324 to SDEFS.
X *
X * Bull DPX/2: Add -DBULL to SDEFS, add -linet to MORELIBS, and
X * use gcc.
X *
X * Is your system closer to System V or BSD? Your SDEFS line should have
X * either -DBSD or -DSYSV. If you don't know, try leaving it blank first;
X * some compilers automatically define it for you. So far, defining
X * SYSV just defines a couple of macros for similar functions in BSD.
X *
X * You may need to add -DRINDEX if your system uses strrchr instead.
X * If SYSV is defined, RINDEX is defined automatically because System V
X * uses strrchr.
X *
X * Add -Dconst if your compiler chokes on the const directive.
X *
X * Add -DSYSSELECTH if you need <sys/select.h> included for definitions
X * of fd_set, etc.
X *
X * (Optional) Add -DHERROR if you know you have the herror() system
X * call.
X *
X * (Optional) Add -DU_WAIT if you know your wait system call takes
X * a pointer to a 'union wait.' Defined automatically if you define
X * BSD.
X *
X * (Optional) Add -DHOSTNAME=\"machine.domain.nam\" if your system
X * doesn't generate it's own hostname. To check this, compile ncftp
X * then run it and type 'set.' Look at the variable anon-password.
X * If the hostname is wrong, recompile it with HOSTNAME set to your
X * machine's address.
X */
X
X#ifdef sun
X# define System "SunOS"
X# ifndef RINDEX
X# define RINDEX 1
X# endif
X#endif /* sun */
X
X#ifdef sgi
X# define System "IRIX"
X# ifndef SYSV
X# define SYSV 1
X# endif
X# ifndef HERROR
X# define HERROR 1
X# endif
X# ifndef U_WAIT
X# define U_WAIT 1
X# endif
X#endif /* sgi */
X
X#ifdef _AIX
X# define System "AIX"
X# define SYSSELECTH 1
X#endif /* _AIX */
X
X#ifdef SCO324
X# define System "SCO Unix"
X# ifndef SYSV
X# define SYSV 1
X# endif
X#endif /* SCO */
X
X#if defined(__hpux) || defined(HPUX)
X# define System "HP-UX"
X# ifndef _HPUX_SOURCE
X# define _HPUX_SOURCE 1
X# endif
X# define SYSV 1
X#endif /* HPUX */
X
X#ifdef SINIX
X# define System "SINIX"
X# ifndef SYSV
X# define SYSV 1
X# endif
X/* You may need to add -lresolv, -lport, -lcurses to MORELIBS in Makefile. */
X#endif
X
X#ifdef BULL /* added 23nov92 for Bull DPX/2 */
X# define _POSIX_SOURCE
X# define _XOPEN_SOURCE
X# define _BULL_SOURCE
X# ifndef SYSV
X# define SYSV 1
X# endif
X# define bull
X# define System "Bull DPX/2 BOS"
X# include <sys/types.h>
X# define SYSSELECTH
X#endif /* BULL */ /* added 23nov92 for Bull DPX/2 */
X
X/* -------------------------------------------------------------------- */
X
X#ifdef _SYSV
X# ifndef SYSV
X# define SYSV 1
X# endif
X#endif
X
X#ifdef USG
X# ifndef SYSV
X# define SYSV 1
X# endif
X#endif
X
X#ifdef _BSD
X# ifndef BSD
X# define BSD 1
X# endif
X# ifndef SYSDIRH
X# define SYSDIRH 1
X# endif
X#endif
X
X#ifdef SYSV
X# ifndef RINDEX
X# define RINDEX 1
X# endif
X# define unlink remove
X# define bcopy(s,d,l) memcpy((d),(s),(l))
X# define bzero(cp,l) memset((cp),0,(l))
X#endif
X
X#ifdef BSD
X# ifndef U_WAIT
X# define U_WAIT 1 /* Use a 'union wait' parameter with wait(). */
X# endif
X#endif
X
X/*
X * Some systems besides System V don't use rindex/index (like SunOS).
X * Add -DRINDEX to your SDEFS line if you need to.
X */
X#ifdef RINDEX
X /* or #include <strings.h> if you have it. */
X# define rindex strrchr
X# define index strchr
X#endif /* RINDEX */
X
X/* Turn on the redir command. */
X#ifndef REDIR
X# define REDIR 1
X#endif
X
X/* eof sys.h */
END_OF_FILE
if test 4116 -ne `wc -c <'sys.h'`; then
echo shar: \"'sys.h'\" unpacked with wrong size!
fi
# end of 'sys.h'
fi
echo shar: End of archive 1 \(of 3\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 3 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...