diff options
author | ache <ache@FreeBSD.org> | 1994-09-22 23:45:37 +0000 |
---|---|---|
committer | ache <ache@FreeBSD.org> | 1994-09-22 23:45:37 +0000 |
commit | 41cb9decc65e51e29f0eb6fe06bcb3594726bd6b (patch) | |
tree | 31cb31bfb69915fc791ce9c2ec7d345124bedebf /usr.bin/ncftp/open.c | |
download | FreeBSD-src-41cb9decc65e51e29f0eb6fe06bcb3594726bd6b.zip FreeBSD-src-41cb9decc65e51e29f0eb6fe06bcb3594726bd6b.tar.gz |
ncftp 1.8.5
Diffstat (limited to 'usr.bin/ncftp/open.c')
-rw-r--r-- | usr.bin/ncftp/open.c | 638 |
1 files changed, 638 insertions, 0 deletions
diff --git a/usr.bin/ncftp/open.c b/usr.bin/ncftp/open.c new file mode 100644 index 0000000..66733a8 --- /dev/null +++ b/usr.bin/ncftp/open.c @@ -0,0 +1,638 @@ +/* open.c */ + +/* $RCSfile: open.c,v $ + * $Revision: 1.1 $ + * $Date: 93/07/09 11:27:07 $ + */ + +#include "sys.h" + +#include <netdb.h> +#include <netinet/in.h> +#include <arpa/ftp.h> + +#include <errno.h> + +#include "util.h" +#include "open.h" +#include "cmds.h" +#include "ftp.h" +#include "ftprc.h" +#include "main.h" +#include "defaults.h" +#include "copyright.h" + +/* open.c globals */ +int remote_is_unix; /* TRUE if remote host is unix. */ +int auto_binary = dAUTOBINARY; +int anon_open = dANONOPEN; + /* Anonymous logins by default? */ +int connected = 0; /* TRUE if connected to server */ + /* If TRUE, set binary each connection. */ +Hostname hostname; /* Name of current host */ +RemoteSiteInfo gRmtInfo; +#ifdef GATEWAY +string gateway; /* node name of firewall gateway */ +string gate_login; /* login at firewall gateway */ +#endif + +/* open.c externs */ +extern char *reply_string, *line, *Optarg, *margv[]; +extern int Optind, margc, verbose, macnum; +extern long eventnumber; +extern struct servent serv; +extern FILE *cout; +extern string anon_password; + +/* Given a pointer to an OpenOptions (structure containing all variables + * that can be set from the command line), this routine makes sure all + * the variables have valid values by setting them to their defaults. + */ + +void InitOpenOptions(OpenOptions *openopt) +{ + /* How do you want to open a site if neither -a or -u are given? + * anon_open is true (default to anonymous login), unless + * defaults.h was edited to set dANONOPEN to 0 instead. + */ + openopt->openmode = anon_open ? openImplicitAnon : openImplicitUser; + + /* Normally you don't want to ignore the entry in your netrc. */ + openopt->ignore_rc = 0; + + /* Set the default delay if the user specifies redial mode without + * specifying the redial delay. + */ + openopt->redial_delay = dREDIALDELAY; + + /* Normally, you only want to try once. If you specify redial mode, + * this is changed. + */ + openopt->max_dials = 1; + + /* You don't want to cat the file to stdout by default. */ + openopt->ftpcat = NO_FTPCAT; + + /* Setup the port number to try. */ +#ifdef dFTP_PORT + /* If dFTP_PORT is defined, we use a different port number by default + * than the one supplied in the servent structure. + */ + openopt->port = dFTP_PORT; + /* Make sure the correct byte order is supplied! */ + openopt->port = htons(openopt->port); +#else + /* Use the port number supplied by the operating system's servent + * structure. + */ + openopt->port = serv.s_port; +#endif + + /* We are not in colon-mode (yet). */ + openopt->colonmodepath[0] = 0; + + /* Set the hostname to a null string, since there is no default host. */ + openopt->hostname[0] = 0; + + /* Set the opening directory path to a null string. */ + openopt->cdpath[0] = 0; +} /* InitOpenOptions */ + + + + +/* This is responsible for parsing the command line and setting variables + * in the OpenOptions structure according to the user's flags. + */ + +int GetOpenOptions(int argc, char **argv, OpenOptions *openopt) +{ + int opt, www; + char *cp, *hostp, *cpath; + + /* First setup the openopt variables. */ + InitOpenOptions(openopt); + + /* Tell Getopt() that we want to start over with a new command. */ + Getopt_Reset(); + while ((opt = Getopt(argc, argv, "aiup:rd:g:cm")) >= 0) { + switch (opt) { + case 'a': + /* User wants to open anonymously. */ + openopt->openmode = openExplicitAnon; + break; + + case 'u': + /* User wants to open with a login and password. */ + openopt->openmode = openExplicitUser; + break; + + case 'i': + /* User wants to ignore the entry in the netrc. */ + openopt->ignore_rc = 1; + break; + + case 'p': + /* User supplied a port number different from the default + * ftp port. + */ + openopt->port = atoi(Optarg); + if (openopt->port <= 0) { + /* Probably never happen, but just in case. */ + (void) printf("%s: bad port number (%s).\n", argv[0], Optarg); + goto usage; + } + /* Must ensure that the port is in the correct byte order! */ + openopt->port = htons(openopt->port); + break; + + case 'd': + /* User supplied a delay (in seconds) that differs from + * the default. + */ + openopt->redial_delay = atoi(Optarg); + break; + + case 'g': + /* User supplied an upper-bound on the number of redials + * to try. + */ + openopt->max_dials = atoi(Optarg); + break; + + case 'r': + openopt->max_dials = -1; + break; + + case 'm': + /* ftpcat mode is only available from your shell command-line, + * not from the ncftp shell. Do that yourself with 'more zz'. + */ + if (eventnumber == 0L) { + /* If eventnumber is zero, then we were called directly + * from main(), and before the ftp shell has started. + */ + openopt->ftpcat = FTPMORE; + /* ftpcat mode is really ftpmore mode. */ + break; + } else { + fprintf(stderr, +"You can only use this form of colon-mode (-m) from your shell command line.\n\ +Try 'ncftp -m wuarchive.wustl.edu:/README'\n"); + goto usage; + } + /* break; */ + + case 'c': + /* ftpcat mode is only available from your shell command-line, + * not from the ncftp shell. Do that yourself with 'get zz -'. + */ + if (eventnumber == 0L) { + /* If eventnumber is zero, then we were called directly + * from main(), and before the ftp shell has started. + */ + openopt->ftpcat = FTPCAT; + break; + } else { + fprintf(stderr, +"You can only use ftpcat/colon-mode from your shell command line.\n\ +Try 'ncftp -c wuarchive.wustl.edu:/README > file.'\n"); + goto usage; + } + /* break; */ + + default: + usage: + return USAGE; + } + } + + if (argv[Optind] == NULL) { + /* No host was supplied. Print out the list of sites we know + * about and ask the user for one. + */ + PrintSiteList(); + (void) Gets("(site to open) ", openopt->hostname, sizeof(openopt->hostname)); + /* Make sure the user just didn't hit return, in which case we + * just give up and go home. + */ + if (openopt->hostname[0] == 0) + goto usage; + } else { + /* The user gave us a host to open. + * + * First, check to see if they gave us a colon-mode path + * along with the hostname. We also understand a WWW path, + * like "ftp://bang.nta.no/pub/fm2html.v.0.8.4.tar.Z". + */ + hostp = argv[Optind]; + cpath = NULL; + if ((cp = index(hostp, ':')) != NULL) { + *cp++ = '\0'; + cpath = cp; + www = 0; /* Is 0 or 1, depending on the type of path. */ + if ((*cp == '/') && (cp[1] == '/')) { + /* First make sure the path was intended to be used + * with ftp and not one of the other URLs. + */ + if (strcmp(argv[Optind], "ftp")) { + fprintf( + stderr, + "Bad URL '%s' -- WWW paths must be prefixed by 'ftp://'.\n", + argv[Optind] + ); + goto usage; + } + + cp += 2; + hostp = cp; + cpath = NULL; /* It could have been ftp://hostname only. */ + + if ((cp = index(hostp, '/')) != NULL) { + *cp++ = '\0'; + cpath = cp; + } + www = 1; + } + if (cpath != NULL) { + (void) Strncpy(openopt->colonmodepath, www ? "/" : ""); + (void) Strncat(openopt->colonmodepath, cpath); + dbprintf("Colon-Mode Path = '%s'\n", openopt->colonmodepath); + } + } + (void) Strncpy(openopt->hostname, hostp); + dbprintf("Host = '%s'\n", hostp); + } + return NOERR; +} /* GetOpenOptions */ + + + + +/* This examines the format of the string stored in the hostname + * field of the OpenOptions, and sees if has to strip out a colon-mode + * pathname (to store in the colonmodepath field). Since colon-mode + * is run quietly (without any output being generated), we init the + * login_verbosity variable here to quiet if we are running colon-mode. + */ +int CheckForColonMode(OpenOptions *openopt, int *login_verbosity) +{ + /* Usually the user doesn't supply hostname in colon-mode format, + * and wants to interactively browse the remote host, so set the + * login_verbosity to whatever it is set to now. + */ + *login_verbosity = verbose; + + if (openopt->colonmodepath[0] != 0) { + /* But if the user does use colon-mode, we want to do our business + * and leave, without all the login messages, etc., so set + * login_verbosity to quiet so we won't print anything until + * we finish. Colon-mode can be specified from the shell command + * line, so we would like to be able to execute ncftp as a one + * line command from the shell without spewing gobs of output. + */ + *login_verbosity = V_QUIET; + } else if (openopt->ftpcat != 0) { + /* User specified ftpcat mode, but didn't supply the host:file. */ + (void) fprintf(stderr, "You didn't use colon mode correctly.\n\ +If you use -c or -m, you need to do something like this:\n\ + ncftp -c wuarchive.wustl.edu:/pub/README (to cat this file to stdout).\n"); + return USAGE; + } + return NOERR; +} /* CheckForColonMode */ + + + + +/* All this short routine does is to hookup a socket to either the + * remote host or the firewall gateway host. + */ +int HookupToRemote(OpenOptions *openopt) +{ + int hErr; + +#ifdef GATEWAY + /* Try connecting to the gateway host. */ + if (*gateway) { + hErr = hookup(gateway, openopt->port); + (void) Strncpy(hostname, openopt->hostname); + } else +#endif + hErr = hookup(openopt->hostname, openopt->port); + + return hErr; +} /* HookupToRemote */ + + + + +void CheckRemoteSystemType(int force_binary) +{ + int tmpverbose; + char *cp, c; + + /* As of this writing, UNIX is pretty much standard. */ + remote_is_unix = 1; + + /* Do a SYSTem command quietly. */ + tmpverbose = verbose; + verbose = V_QUIET; + if (command("SYST") == COMPLETE) { + if (tmpverbose == V_VERBOSE) { + /* Find the system type embedded in the reply_string, + * and separate it from the rest of the junk. + */ + cp = index(reply_string+4, ' '); + if (cp == NULL) + cp = index(reply_string+4, '\r'); + if (cp) { + if (cp[-1] == '.') + cp--; + c = *cp; + *cp = '\0'; + } + + (void) printf("Remote system type is %s.\n", + reply_string+4); + if (cp) + *cp = c; + } + remote_is_unix = !strncmp(reply_string + 4, "UNIX", (size_t) 4); + } + + /* Set to binary mode if any of the following are true: + * (a) The user has auto-binary set; + * (b) The user is using colon-mode (force_binary); + * (c) The reply-string from SYST said it was UNIX with 8-bit chars. + */ + if (auto_binary || force_binary + || !strncmp(reply_string, "215 UNIX Type: L8", (size_t) 17)) { + (void) _settype("binary"); + if (tmpverbose > V_TERSE) + (void) printf("Using binary mode to transfer files.\n"); + } + + /* Print a warning for that (extremely) rare Tenex machine. */ + if (tmpverbose >= V_ERRS && + !strncmp(reply_string, "215 TOPS20", (size_t) 10)) { + (void) _settype("tenex"); + (void) printf("Using tenex mode to transfer files.\n"); + } + verbose = tmpverbose; +} /* CheckRemoteSystemType */ + + + +/* This is called if the user opened the host with a file appended to + * the host's name, like "wuarchive.wustl.edu:/pub/readme," or + * "wuarchive.wustl.edu:/pub." In the former case, we open wuarchive, + * and fetch "readme." In the latter case, we open wuarchive, then set + * the current remote directory to "/pub." If we are fetching a file, + * we can do some other tricks if "ftpcat mode" is enabled. This mode + * must be selected from your shell's command line, and this allows you + * to use the program as a one-liner to pipe a remote file into something, + * like "ncftp -c wu:/pub/README | wc." If the user uses ftpcat mode, + * the program immediately quits instead of going into it's own command + * shell. + */ +void ColonMode(OpenOptions *openopt) +{ + int tmpverbose; + + /* How do we tell if colonmodepath is a file or a directory? + * We first try cd'ing to the path first. If we can, then it + * was a directory. If we could not, we'll assume it was a file. + */ + + /* Shut up, so cd won't print 'foobar: Not a directory.' */ + tmpverbose = verbose; + verbose = V_QUIET; + + /* If we are using ftpcat|more mode, or we couldn't cd to the + * colon-mode path (then it must be a file to fetch), then + * we need to fetch a file. + */ + if (openopt->ftpcat || ! _cd(openopt->colonmodepath)) { + /* We call the appropriate fetching routine, so we have to + * have the argc and argv set up correctly. To do this, + * we just make an entire command line, then let makeargv() + * convert it to argv/argc. + */ + if (openopt->ftpcat == FTPCAT) + (void) sprintf(line, "get %s -", openopt->colonmodepath); + else if (openopt->ftpcat == FTPMORE) + (void) sprintf(line, "more %s", openopt->colonmodepath); + else { + /* Regular colon-mode, where we fetch the file, putting the + * copy in the current local directory. + */ + (void) sprintf(line, "mget %s", openopt->colonmodepath); + } + makeargv(); + + /* Turn on messaging if we aren't catting. */ + if (openopt->ftpcat == 0) + verbose = tmpverbose; + + /* get() also handles 'more'. */ + if (openopt->ftpcat) + (void) get(margc, margv); + else + (void) mget(margc, margv); + + /* If we were invoked from the command line, quit + * after we got this file. + */ + if (eventnumber == 0L) { + (void) quit(0, NULL); + } + } + verbose = tmpverbose; +} /* ColonMode */ + + + + +/* Given a properly set up OpenOptions, we try connecting to the site, + * redialing if necessary, and do some initialization steps so the user + * can send commands. + */ +int Open(OpenOptions *openopt) +{ + int hErr; + int dials; + char *ruser, *rpass, *racct; + int siteInRC; + char *user, *pass, *acct; + int login_verbosity, oldv; + + macnum = 0; /* Reset macros. */ + + /* If the hostname supplied is in the form host.name.str:/path/file, + * then colon mode was used, and we need to fix the hostname to be + * just the hostname, copy the /path/file to colonmode path, and init + * the login_verbosity variable. + */ + if (CheckForColonMode(openopt, &login_verbosity) == USAGE) + return USAGE; + + /* If the hostname supplied was an abbreviation, such as just + * "wu" (wuarchive.wustl.edu), look through the list of sites + * we know about and get the whole name. We also would like + * the path we want to start out in, if it is available. + */ + GetFullSiteName(openopt->hostname, openopt->cdpath); + +#ifdef GATEWAY + /* Make sure the gateway host name is a full name and not an + * abbreviation. + */ + if (*gateway) + GetFullSiteName(gateway, NULL); +#endif + + ruser = rpass = racct = NULL; + /* This also loads the init macro. */ + siteInRC = ruserpass2(openopt->hostname, &ruser, &rpass, &racct); + if (ISANONOPEN(openopt->openmode)) { + user = "anonymous"; + pass = anon_password; + } else { + user = NULL; + pass = NULL; + } + acct = NULL; + + if (siteInRC && !openopt->ignore_rc) { + acct = racct; + if (ruser != NULL) { + /* We were given a username. If we were given explicit + * instructions from the command line, follow those and + * ignore what the RC had. Otherwise if no -a or -u + * was specified, we use whatever was in the RC. + */ + if (ISIMPLICITOPEN(openopt->openmode)) { + user = ruser; + pass = rpass; + } + } + } + + for ( + dials = 0; + openopt->max_dials < 0 || dials < openopt->max_dials; + dials++) + { + if (dials > 0) { + /* If this is the second dial or higher, sleep a bit. */ + (void) sleep(openopt->redial_delay); + (void) fprintf(stderr, "Retry Number: %d\n", dials + 1); + } + + if ((hErr = HookupToRemote(openopt)) == -2) + /* Recoverable, so we can try re-dialing. */ + continue; + else if (hErr == NOERR) { + /* We were hookup'd successfully. */ + connected = 1; + + oldv = verbose; verbose = login_verbosity; + +#ifdef GATEWAY + if (*gateway) { + if ((Login( + user, + pass, + acct, + (!openopt->ignore_rc && !openopt->colonmodepath[0]) + ) != NOERR) || cout == NULL) + goto nextdial; /* error! */ + } +#endif + +#ifdef GATEWAY + if (!*gateway) { +#endif + /* We don't want to run the init macro for colon-mode. */ + if ((Login( + user, + pass, + acct, + (!openopt->ignore_rc && !openopt->colonmodepath[0]) + ) != NOERR) || cout == NULL) + { + goto nextdial; /* error! */ + } +#ifdef GATEWAY + } +#endif + + verbose = oldv; + + /* We need to check for unix and see if we should set binary + * mode automatically. + */ + CheckRemoteSystemType(openopt->colonmodepath[0] != (char)0); + + if (openopt->colonmodepath[0]) { + ColonMode(openopt); + } else if (openopt->cdpath[0]) { + /* If we didn't have a colon-mode path, we try setting + * the current remote directory to cdpath. cdpath is + * usually the last directory we were in the previous + * time we called this site. + */ + (void) _cd(openopt->cdpath); + } else { + /* Freshen 'cwd' variable for the prompt. + * We have to do atleast one 'cd' so our variable + * cwd (which is saved by _cd()) is set to something + * valid. + */ + (void) _cd(NULL); + } + break; /* we are connected, so break the redial loop. */ + /* end if we are connected */ + } else { + /* Irrecoverable error, so don't bother redialing. */ + /* The error message should have already been printed + * from Hookup(). + */ + break; + } +nextdial: + disconnect(0, NULL); + continue; /* Try re-dialing. */ + } + return (NOERR); +} /* Open */ + + + +/* This stub is called by our command parser. */ +int cmdOpen(int argc, char **argv) +{ + OpenOptions openopt; + + /* If there is already a site open, close that one so we can + * open a new one. + */ + if (connected && NOT_VQUIET && hostname[0]) { + (void) printf("Closing %s...\n", hostname); + (void) disconnect(0, NULL); + } + + /* Reset the remote info structure for the new site we want to open. + * Assume we have these properties until we discover otherwise. + */ + gRmtInfo.hasSIZE = 1; + gRmtInfo.hasMDTM = 1; + + if ((GetOpenOptions(argc, argv, &openopt) == USAGE) || + (Open(&openopt) == USAGE)) + return USAGE; + return NOERR; +} /* cmdOpen */ + +/* eof open.c */ |