* add url_decode() - `in-place' decode %xx escapes in a given url component

* parse_url()
-   only look for user[:pass] for an ftp url (per rfc1738)
-   strip leading /'s in an ftp url. (almost per rfc 1738)
* fetch_url()
-   decode a copy of the path and use that to build local filenames
-   send port in http Host: header (suggested by cgd@netbsd.org)
* fetch_ftp()
-   url_decode() the user, pass and path
-   fix splitting of path into dir & file (partially from [bin/7073])
-   don't bother caching the last host; it can cause problems when
    using ftp:// transfers, or when the user changes between xfers
* improve documentation of auto-fetched url arguments (especially regarding
  escape sequences in ftp:// urls)
* some whitespace & copyright updates

this should fix [bin/7073] William O Ferry <woferry@warp.wofme.com>,
as well as the metaissues raised in that PR.
This commit is contained in:
lukem 1999-03-08 04:36:12 +00:00
parent babd00aa2c
commit 5a1118c5f9
4 changed files with 178 additions and 115 deletions

View File

@ -1,7 +1,7 @@
/* $NetBSD: fetch.c,v 1.49 1999/01/25 23:17:37 lukem Exp $ */
/* $NetBSD: fetch.c,v 1.50 1999/03/08 04:36:12 lukem Exp $ */
/*-
* Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
* Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: fetch.c,v 1.49 1999/01/25 23:17:37 lukem Exp $");
__RCSID("$NetBSD: fetch.c,v 1.50 1999/03/08 04:36:12 lukem Exp $");
#endif /* not lint */
/*
@ -78,15 +78,16 @@ typedef enum {
FILE_URL_T
} url_t;
void aborthttp __P((int));
static int auth_url __P((const char *, char **));
static void base64_enc __P((const char *, size_t, char *));
static void base64_encode __P((const char *, size_t, char *));
static int go_fetch __P((const char *, const char *));
static int fetch_ftp __P((const char *, const char *));
static int fetch_url __P((const char *, const char *, const char *,
char *, char *));
static int parse_url __P((const char *, const char *, url_t *, char **,
char **, char **, in_port_t *, char **));
void aborthttp __P((int));
static void url_decode __P((char *));
static int redirect_loop;
@ -169,7 +170,7 @@ auth_url(challenge, response)
len = strlen(scheme) + 1 + (len + 2) * 4 / 3;
*response = (char *)xmalloc(len + 1);
len = sprintf(*response, "%s ", scheme);
base64_enc(clear, strlen(clear), *response + len);
base64_encode(clear, strlen(clear), *response + len);
rval = 0;
cleanup_auth_url:
@ -184,7 +185,7 @@ cleanup_auth_url:
* which should be at least ((len + 2) * 4 / 3 + 1) in size.
*/
void
base64_enc(clear, len, encoded)
base64_encode(clear, len, encoded)
const char *clear;
size_t len;
char *encoded;
@ -208,11 +209,40 @@ base64_enc(clear, len, encoded)
*(--cp) = '=';
}
/*
* Decode %xx escapes in given string, `in-place'.
*/
static void
url_decode(url)
char *url;
{
unsigned char *p, *q;
if (EMPTYSTRING(url))
return;
p = q = url;
#define HEXTOINT(x) (x - (isdigit(x) ? '0' : (islower(x) ? 'a' : 'A') - 10))
while (*p) {
if (p[0] == '%'
&& p[1] && isxdigit((unsigned char)p[1])
&& p[2] && isxdigit((unsigned char)p[2])) {
*q++ = HEXTOINT(p[1]) * 16 + HEXTOINT(p[2]);
p+=3;
} else
*q++ = *p++;
}
*q = '\0';
}
/*
* Parse URL of form:
* <type>://[<user>[:<password>@]]<host>[:<port>]/<url-path>
* Returns -1 if a parse error occurred, otherwise 0.
* Only permit [<user>[:<password>@]] for ftp:// URLs
* It's the caller's responsibility to url_decode() the returned
* user, pass and path.
* Sets type to url_t, each of the given char ** pointers to a
* malloc(3)ed strings of the relevant section, and port to
* the number given, or ftpport if ftp://, or httpport if http://.
@ -229,6 +259,7 @@ parse_url(url, desc, type, user, pass, host, port, path)
char **path;
{
char *cp, *ep, *thost;
size_t len;
if (url == NULL || desc == NULL || type == NULL || user == NULL
|| pass == NULL || host == NULL || port == NULL || path == NULL)
@ -267,15 +298,21 @@ cleanup_parse_url:
if (ep == NULL)
thost = xstrdup(url);
else {
size_t len = ep - url;
len = ep - url;
thost = (char *)xmalloc(len + 1);
strncpy(thost, url, len);
thost[len] = '\0';
ep++; /* skip first / for all URLs */
if (*type == FTP_URL_T) /* skip all leading /'s for ftp URLs */
while (*ep && *ep == '/')
ep++;
*path = xstrdup(ep);
}
cp = strchr(thost, '@');
if (cp != NULL) {
/* look for user[:pass]@ in ftp URLs */
if (*type == FTP_URL_T && cp != NULL) {
anonftp = 0; /* disable anonftp */
*user = thost;
*cp = '\0';
*host = xstrdup(cp + 1);
@ -303,7 +340,7 @@ cleanup_parse_url:
if (debug)
fprintf(ttyout,
"parse_url: user `%s', pass `%s', host %s:%d, path `%s'\n",
"parse_url: user `%s' pass `%s' host %s:%d path `%s'\n",
*user ? *user : "", *pass ? *pass : "", *host ? *host : "",
ntohs(*port), *path ? *path : "");
@ -314,9 +351,10 @@ cleanup_parse_url:
jmp_buf httpabort;
/*
* Retrieve URL, via a proxy if necessary. If proxyenv is set, use that for
* the proxy, otherwise try ftp_proxy or http_proxy as appropriate.
* Supports http redirects.
* Retrieve URL, via a proxy if necessary, using HTTP.
* If proxyenv is set, use that for the proxy, otherwise try ftp_proxy or
* http_proxy as appropriate.
* Supports HTTP redirects.
* Returns -1 on failure, 0 on completed xfer, 1 if ftp connection
* is still open (e.g, ftp xfer with trailing /)
*/
@ -336,7 +374,7 @@ fetch_url(url, outfile, proxyenv, proxyauth, wwwauth)
size_t len;
char *cp, *ep, *buf, *savefile;
char *auth, *location, *message;
char *user, *pass, *host, *path;
char *user, *pass, *host, *path, *decodedpath;
off_t hashbytes;
int (*closefunc) __P((FILE *));
FILE *fin, *fout;
@ -352,6 +390,7 @@ fetch_url(url, outfile, proxyenv, proxyauth, wwwauth)
ischunked = isproxy = 0;
rval = 1;
hp = NULL;
user = pass = host = path = decodedpath = NULL;
#ifdef __GNUC__ /* shut up gcc warnings */
(void)&closefunc;
@ -384,14 +423,17 @@ fetch_url(url, outfile, proxyenv, proxyauth, wwwauth)
}
}
decodedpath = xstrdup(path);
url_decode(decodedpath);
if (outfile)
savefile = xstrdup(outfile);
else {
cp = strrchr(path, '/'); /* find savefile */
cp = strrchr(decodedpath, '/'); /* find savefile */
if (cp != NULL)
savefile = xstrdup(cp + 1);
else
savefile = xstrdup(path);
savefile = xstrdup(decodedpath);
}
if (EMPTYSTRING(savefile)) {
if (urltype == FTP_URL_T) {
@ -408,9 +450,9 @@ fetch_url(url, outfile, proxyenv, proxyauth, wwwauth)
struct stat sb;
direction = "copied";
fin = fopen(path, "r");
fin = fopen(decodedpath, "r");
if (fin == NULL) {
warn("Cannot open file `%s'", path);
warn("Cannot open file `%s'", decodedpath);
goto cleanup_fetch_url;
}
if (fstat(fileno(fin), &sb) == 0) {
@ -418,7 +460,7 @@ fetch_url(url, outfile, proxyenv, proxyauth, wwwauth)
filesize = sb.st_size;
}
if (verbose)
fprintf(ttyout, "Copying %s\n", path);
fprintf(ttyout, "Copying %s\n", decodedpath);
} else { /* ftp:// or http:// URLs */
if (proxyenv == NULL) {
if (urltype == HTTP_URL_T)
@ -577,7 +619,7 @@ fetch_url(url, outfile, proxyenv, proxyauth, wwwauth)
if (verbose)
fprintf(ttyout, "Requesting %s\n", url);
fprintf(fin, "GET %s HTTP/1.1\r\n", path);
fprintf(fin, "Host: %s\r\n", host);
fprintf(fin, "Host: %s:%d\r\n", host, ntohs(port));
fprintf(fin, "Accept: */*\r\n");
if (uname(&unam) != -1) {
fprintf(fin, "User-Agent: %s-%s/ftp\r\n",
@ -937,6 +979,7 @@ cleanup_fetch_url:
FREEPTR(pass);
FREEPTR(host);
FREEPTR(path);
FREEPTR(decodedpath);
FREEPTR(buf);
FREEPTR(auth);
FREEPTR(location);
@ -945,7 +988,7 @@ cleanup_fetch_url:
}
/*
* Abort a http retrieval
* Abort a HTTP retrieval
*/
void
aborthttp(notused)
@ -958,7 +1001,7 @@ aborthttp(notused)
}
/*
* Retrieve ftp URL or classic ftp argument.
* Retrieve ftp URL or classic ftp argument using FTP.
* Returns -1 on failure, 0 on completed xfer, 1 if ftp connection
* is still open (e.g, ftp xfer with trailing /)
*/
@ -967,12 +1010,11 @@ fetch_ftp(url, outfile)
const char *url;
const char *outfile;
{
static char lasthost[MAXHOSTNAMELEN];
char *cp, *xargv[5], rempath[MAXPATHLEN];
char portnum[6]; /* large enough for "65535\0" */
char *host, *path, *dir, *file, *user, *pass;
in_port_t port;
int dirhasglob, filehasglob, rval, xargc;
int dirhasglob, filehasglob, oautologin, rval, xargc;
host = path = dir = file = user = pass = NULL;
port = 0;
@ -989,6 +1031,9 @@ fetch_ftp(url, outfile)
warnx("Invalid URL `%s'", url);
goto cleanup_fetch_ftp;
}
url_decode(user);
url_decode(pass);
url_decode(path);
} else { /* classic style `host:file' */
host = xstrdup(url);
cp = strchr(host, ':');
@ -1000,15 +1045,14 @@ fetch_ftp(url, outfile)
if (EMPTYSTRING(host))
goto cleanup_fetch_ftp;
/*
* Extract the file and (if present) directory name.
*/
/* Extract the file and (if present) directory name. */
dir = path;
if (! EMPTYSTRING(dir)) {
if (*dir == '/')
dir++; /* skip leading / */
cp = strrchr(dir, '/');
if (cp != NULL) {
if (cp == dir) {
file = cp + 1;
dir = "/";
} else if (cp != NULL) {
*cp++ = '\0';
file = cp;
} else {
@ -1018,7 +1062,7 @@ fetch_ftp(url, outfile)
}
if (debug)
fprintf(ttyout,
"fetch_ftp: user `%s', pass `%s', host %s:%d, path, `%s', dir `%s', file `%s'\n",
"fetch_ftp: user `%s' pass `%s' host %s:%d path `%s' dir `%s' file `%s'\n",
user ? user : "", pass ? pass : "",
host ? host : "", ntohs(port), path ? path : "",
dir ? dir : "", file ? file : "");
@ -1031,49 +1075,32 @@ fetch_ftp(url, outfile)
filehasglob = 1;
}
/*
* Set up the connection if we don't have one.
*/
if (strcasecmp(host, lasthost) != 0) {
int oautologin;
(void)strcpy(lasthost, host);
if (connected)
disconnect(0, NULL);
xargv[0] = __progname;
xargv[1] = host;
xargv[2] = NULL;
xargc = 2;
if (port) {
snprintf(portnum, sizeof(portnum), "%d", ntohs(port));
xargv[2] = portnum;
xargv[3] = NULL;
xargc = 3;
}
oautologin = autologin;
if (user != NULL)
autologin = 0;
setpeer(xargc, xargv);
autologin = oautologin;
if ((connected == 0)
|| ((connected == 1) && !ftp_login(host, user, pass)) ) {
warnx("Can't connect or login to host `%s'",
host);
goto cleanup_fetch_ftp;
}
/* Set up the connection */
if (connected)
disconnect(0, NULL);
xargv[0] = __progname;
xargv[1] = host;
xargv[2] = NULL;
xargc = 2;
if (port) {
snprintf(portnum, sizeof(portnum), "%d", ntohs(port));
xargv[2] = portnum;
xargv[3] = NULL;
xargc = 3;
}
oautologin = autologin;
if (user != NULL)
autologin = 0;
setpeer(xargc, xargv);
autologin = oautologin;
if ((connected == 0) || ((connected == 1)
&& !ftp_login(host, user, pass))) {
warnx("Can't connect or login to host `%s'", host);
goto cleanup_fetch_ftp;
}
/* Always use binary transfers. */
setbinary(0, NULL);
} else {
/* connection exists, cd back to `/' */
xargv[0] = "cd";
xargv[1] = "/";
xargv[2] = NULL;
dirchange = 0;
cd(2, xargv);
if (! dirchange)
goto cleanup_fetch_ftp;
}
setbinary(0, NULL);
/* Change directories, if necessary. */
if (! EMPTYSTRING(dir) && !dirhasglob) {
@ -1137,7 +1164,7 @@ cleanup_fetch_ftp:
* Supports arguments of the form:
* "host:path", "ftp://host/path" if $ftpproxy, call fetch_url() else
* call fetch_ftp()
* "http://host/path" call fetch_url() to use http
* "http://host/path" call fetch_url() to use HTTP
* "file:///path" call fetch_url() to copy
* "about:..." print a message
*
@ -1159,7 +1186,7 @@ go_fetch(url, outfile)
if (strcasecmp(url, "ftp") == 0) {
fprintf(ttyout, "%s\n%s\n",
"This version of ftp has been enhanced by Luke Mewburn <lukem@netbsd.org>.",
"Execute 'man ftp' for more details");
"Execute `man ftp' for more details");
} else if (strcasecmp(url, "netbsd") == 0) {
fprintf(ttyout, "%s\n%s\n",
"NetBSD is a freely available and redistributable UNIX-like operating system.",
@ -1227,6 +1254,7 @@ auto_fetch(argc, argv, outfile)
if (strchr(argv[argpos], ':') == NULL)
break;
redirect_loop = 0;
anonftp = 1; /* Handle "automatic" transfers. */
rval = go_fetch(argv[argpos], outfile);
if (rval > 0)
rval = argpos + 1;

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ftp.1,v 1.33 1999/03/07 11:29:59 mycroft Exp $
.\" $NetBSD: ftp.1,v 1.34 1999/03/08 04:36:13 lukem Exp $
.\"
.\" Copyright (c) 1985, 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@ -35,7 +35,7 @@
.\"
.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
.Dd January 24, 1999
.Dd March 8, 1999
.Dt FTP 1
.Os BSD 4.2
.Sh NAME
@ -76,7 +76,7 @@ file:///\fIfile\fR
.Bk -words
.Op Fl o Ar output
.Ek
ftp://[\fIuser\fR:\fIpassword\fR@]\fIhost\fR[:\fIport\fR]/\fIfile\fR[/]
ftp://[\fIuser\fR[:\fIpassword]\fR@]\fIhost\fR[:\fIport\fR]/\fIfile\fR[/]
.Nm ftp
.Op Fl f
.Bk -words
@ -98,7 +98,7 @@ The program allows a user to transfer files to and from a
remote network site.
.Pp
The last four usage formats will fetch a file using the
http or ftp protocols, or by direct copying, into the current directory.
HTTP or FTP protocols, or by direct copying, into the current directory.
This is ideal for scripts.
Refer to
.Sx AUTO-FETCHING FILES
@ -130,7 +130,7 @@ This is useful for Emacs ange-ftp mode.
.It Fl f
Forces a cache reload for transfers that go through the
.Ev ftp_proxy
or
or
.Ev http_proxy .
.It Fl g
Disables file name globbing.
@ -405,11 +405,11 @@ The current settings for
and
.Ic structure
are used while transferring the file.
.It Ic gate Op Ar host Op Ar port
.It Ic gate Op Ar host Op Ar port
Toggle gate-ftp mode.
This will not be permitted if the gate-ftp server hasn't been set
(either explicitly by the user, or from the
.Ev FTPSERVER
.Ev FTPSERVER
environment variable).
If
.Ar host
@ -740,7 +740,7 @@ server (see below).
Retrieve
.Ic file
and display with the program defined in
.Ev PAGER
.Ev PAGER
(which defaults to
.Xr more 1 ).
.It Ic passive
@ -1109,26 +1109,54 @@ To enable auto-fetch, simply pass the list of hostnames/files
on the command line.
.Pp
The following formats are valid syntax for an auto-fetch element:
.Bl -tag -width "host:/file"
.It host:/file
.Bl -tag -width "FOO "
.It host:/file
.Dq Classic
ftp format
.It ftp://[user:password@]host[:port]/file
.It ftp://[user[:password]@]host[:port]/file
An ftp URL, retrieved using the ftp protocol if
.Ev ftp_proxy
isn't defined.
Otherwise, transfer using http via the proxy defined in
Otherwise, transfer using HTTP via the proxy defined in
.Ev ftp_proxy .
If
.Ar user:password@
is given and
.Ev ftp_proxy
isn't defined, login as
isn't defined and
.Ar user
with a password of
.Ar password .
is given, login as
.Ar user .
In this case, use
.Ar password
if supplied, otherwise prompt the user for one.
.Pp
In order to be compliant with
.Cm RFC 1738 ,
.Nm
strips any leading
.Sq /
from
.Ar path ,
resulting in a transfer relative from the default login directory of
the user.
If the
.Pa /
directory is required, use a leading path of
.Dq %2F .
If a user's home directory is required (and the remote server supports
the syntax), use a leading path of
.Dq %7Euser/ .
For example, to retrieve
.Pa /etc/motd
from
.Sq localhost
as the user
.Sq myname
with the password
.Sq mypass ,
use
.Dq ftp://myname:mypass@localhost/%2fetc/motd
.It http://host[:port]/file
An HTTP URL, retrieved using the http protocol.
An HTTP URL, retrieved using the HTTP protocol.
If
.Ev http_proxy
is defined, it is used as a URL to an HTTP proxy server.
@ -1151,7 +1179,7 @@ connection creation and deletion.
.Pp
If
.Ic file
contains a glob character and globbing is enabled,
contains a glob character and globbing is enabled,
(see
.Ic glob ) ,
then the equivalent of
@ -1232,7 +1260,7 @@ c.f. the
command.
If the
.Nm
command expects a single local file (.e.g.
command expects a single local file (e.g.
.Ic put ) ,
only the first filename generated by the "globbing" operation is used.
.It
@ -1388,7 +1416,7 @@ auto-login process.
.El
.Sh COMMAND LINE EDITING
.Nm
supports interactive command line editing, via the
supports interactive command line editing, via the
.Xr editline 3
library.
It is enabled with the
@ -1445,7 +1473,7 @@ Port to use when connecting to gate-ftp server when
is enabled.
Default is port returned by a
.Fn getservbyname
lookup of
lookup of
.Dq ftpgate/tcp .
.It Ev HOME
For default location of a
@ -1473,13 +1501,21 @@ the matching to connections to that port.
.Xr editrc 5 ,
.Xr services 5 ,
.Xr ftpd 8
.Sh STANDARDS
.Nm
attempts to be compliant with
.Cm RFC 959 ,
.Cm RFC 1123 ,
.Cm RFC 1738 ,
and
.Cm RFC 2068 .
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .
.Pp
Various features such as command line editing, context sensitive
Various features such as command line editing, context sensitive
command and file completion, dynamic progress bar, automatic
fetching of files and URLs, and modification time
preservation were implemented in

View File

@ -1,4 +1,4 @@
/* $NetBSD: ftp_var.h,v 1.29 1999/01/23 15:46:24 lukem Exp $ */
/* $NetBSD: ftp_var.h,v 1.30 1999/03/08 04:36:13 lukem Exp $ */
/*
* Copyright (c) 1985, 1989, 1993, 1994
@ -120,7 +120,7 @@ char bytename[32]; /* local byte size in ascii */
int bytesize; /* local byte size in binary */
int anonftp; /* automatic anonymous login */
int dirchange; /* remote directory changed by cd command */
int flushcache; /* set http cache flush headers with request */
int flushcache; /* set HTTP cache flush headers with request */
int retry_connect; /* seconds between retrying connection */
int ttywidth; /* width of tty */
char *tmpdir; /* temporary directory */
@ -144,8 +144,8 @@ char *hostname; /* name of host connected to */
int unix_server; /* server is unix, can use binary for ascii */
int unix_proxy; /* proxy is unix, can use binary for ascii */
in_port_t ftpport; /* port number to use for ftp connections */
in_port_t httpport; /* port number to use for http connections */
in_port_t ftpport; /* port number to use for FTP connections */
in_port_t httpport; /* port number to use for HTTP connections */
in_port_t gateport; /* port number to use for gateftp connections */
const char *ftpproxy; /* ftp:// proxy server */

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.37 1999/01/24 02:39:30 lukem Exp $ */
/* $NetBSD: main.c,v 1.38 1999/03/08 04:36:13 lukem Exp $ */
/*
* Copyright (c) 1985, 1989, 1993, 1994
@ -43,7 +43,7 @@ __COPYRIGHT("@(#) Copyright (c) 1985, 1989, 1993, 1994\n\
#if 0
static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 10/9/94";
#else
__RCSID("$NetBSD: main.c,v 1.37 1999/01/24 02:39:30 lukem Exp $");
__RCSID("$NetBSD: main.c,v 1.38 1999/03/08 04:36:13 lukem Exp $");
#endif
#endif /* not lint */
@ -65,9 +65,9 @@ __RCSID("$NetBSD: main.c,v 1.37 1999/01/24 02:39:30 lukem Exp $");
#include "ftp_var.h"
#include "pathnames.h"
#define FTP_PROXY "ftp_proxy" /* env var with ftp proxy location */
#define HTTP_PROXY "http_proxy" /* env var with http proxy location */
#define NO_PROXY "no_proxy" /* env var with list of non-proxied
#define FTP_PROXY "ftp_proxy" /* env var with FTP proxy location */
#define HTTP_PROXY "http_proxy" /* env var with HTTP proxy location */
#define NO_PROXY "no_proxy" /* env var with list of non-proxied
* hosts, comma or space separated */
int main __P((int, char **));
@ -299,7 +299,6 @@ main(argc, argv)
if (argc > 0) {
if (strchr(argv[0], ':') != NULL) {
anonftp = 1; /* Handle "automatic" transfers. */
rval = auto_fetch(argc, argv, outfile);
if (rval >= 0) /* -1 == connected and cd-ed */
exit(rval);
@ -402,7 +401,7 @@ cmdscanner(top)
struct cmd *c;
int num;
if (!top
if (!top
#ifndef SMALL
&& !editing
#endif /* !SMALL */
@ -469,7 +468,7 @@ cmdscanner(top)
* false positive if prog != "ftp", so treat
* such commands as invalid.
*/
if (strchr(margv[0], ':') != NULL ||
if (strchr(margv[0], ':') != NULL ||
el_parse(el, margc, margv) != 0)
#endif /* !SMALL */
fputs("?Invalid command.\n", ttyout);
@ -563,7 +562,7 @@ makeargv()
cursor_argo = ap-argbase; \
cursor_pos = NULL; \
} }
#endif /* !SMALL */
/*
@ -746,11 +745,11 @@ void
usage()
{
(void)fprintf(stderr,
"usage: %s [-AadeginptvV] [-r retry] [-P port] [host [port]]\n"
" %s [-f] [-o outfile] file:///file\n"
" %s [-f] [-o outfile] ftp://host[:port]/path[/]\n"
" %s [-f] [-o outfile] http://host[:port]/file\n"
" %s [-f] [-o outfile] host:path[/]\n",
"usage: %s [-AadeginptvV] [-r retry] [-P port] [host [port]]\n"
" %s [-f] [-o outfile] file:///file\n"
" %s [-f] [-o outfile] ftp://[user[:pass]@]host[:port]/path[/]\n"
" %s [-f] [-o outfile] http://host[:port]/path\n"
" %s [-f] [-o outfile] host:path[/]\n",
__progname, __progname, __progname, __progname, __progname);
exit(1);
}