1999-09-21 16:57:51 +04:00
|
|
|
/* $NetBSD: fetch.c,v 1.70 1999/09/21 12:57:51 lukem Exp $ */
|
1997-01-19 17:19:02 +03:00
|
|
|
|
|
|
|
/*-
|
1999-03-08 07:36:12 +03:00
|
|
|
* Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
|
1997-01-19 17:19:02 +03:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
1999-05-12 15:16:43 +04:00
|
|
|
* by Luke Mewburn.
|
1997-01-19 17:19:02 +03:00
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the NetBSD
|
|
|
|
* Foundation, Inc. and its contributors.
|
|
|
|
* 4. Neither the name of The NetBSD Foundation nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
|
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
1997-08-18 14:20:13 +04:00
|
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
|
|
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
1997-01-19 17:19:02 +03:00
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
1997-07-20 13:45:35 +04:00
|
|
|
#include <sys/cdefs.h>
|
1997-01-19 17:19:02 +03:00
|
|
|
#ifndef lint
|
1999-09-21 16:57:51 +04:00
|
|
|
__RCSID("$NetBSD: fetch.c,v 1.70 1999/09/21 12:57:51 lukem Exp $");
|
1997-01-19 17:19:02 +03:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FTP User Program -- Command line file retrieval
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/socket.h>
|
1998-08-08 07:06:00 +04:00
|
|
|
#include <sys/stat.h>
|
1998-08-08 08:04:17 +04:00
|
|
|
#include <sys/time.h>
|
1998-12-31 05:10:34 +03:00
|
|
|
#include <sys/utsname.h>
|
1997-01-19 17:19:02 +03:00
|
|
|
|
|
|
|
#include <netinet/in.h>
|
|
|
|
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
#include <arpa/ftp.h>
|
1997-01-19 17:19:02 +03:00
|
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <err.h>
|
1998-06-04 12:28:35 +04:00
|
|
|
#include <errno.h>
|
1997-01-19 17:19:02 +03:00
|
|
|
#include <netdb.h>
|
|
|
|
#include <fcntl.h>
|
1997-03-13 09:23:11 +03:00
|
|
|
#include <signal.h>
|
1997-01-19 17:19:02 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
1999-06-24 18:48:35 +04:00
|
|
|
#include <time.h>
|
1998-07-22 20:06:27 +04:00
|
|
|
#include <util.h>
|
1997-01-19 17:19:02 +03:00
|
|
|
|
|
|
|
#include "ftp_var.h"
|
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
typedef enum {
|
|
|
|
UNKNOWN_URL_T=-1,
|
|
|
|
HTTP_URL_T,
|
|
|
|
FTP_URL_T,
|
1999-04-28 17:35:40 +04:00
|
|
|
FILE_URL_T,
|
|
|
|
CLASSIC_URL_T
|
1998-08-03 05:49:25 +04:00
|
|
|
} url_t;
|
|
|
|
|
1999-03-08 07:36:12 +03:00
|
|
|
void aborthttp __P((int));
|
1999-05-12 15:16:43 +04:00
|
|
|
static int auth_url __P((const char *, char **, const char *,
|
|
|
|
const char *));
|
1999-03-08 07:36:12 +03:00
|
|
|
static void base64_encode __P((const char *, size_t, char *));
|
1999-03-22 10:36:40 +03:00
|
|
|
static int go_fetch __P((const char *));
|
|
|
|
static int fetch_ftp __P((const char *));
|
|
|
|
static int fetch_url __P((const char *, const char *, char *, char *));
|
1998-08-03 05:49:25 +04:00
|
|
|
static int parse_url __P((const char *, const char *, url_t *, char **,
|
1999-07-02 12:07:40 +04:00
|
|
|
char **, char **, char **, char **));
|
1999-03-08 07:36:12 +03:00
|
|
|
static void url_decode __P((char *));
|
1997-07-20 13:45:35 +04:00
|
|
|
|
1998-12-29 17:59:04 +03:00
|
|
|
static int redirect_loop;
|
|
|
|
|
1997-07-20 13:45:35 +04:00
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
#define ABOUT_URL "about:" /* propaganda */
|
|
|
|
#define FILE_URL "file://" /* file URL prefix */
|
1997-01-19 17:19:02 +03:00
|
|
|
#define FTP_URL "ftp://" /* ftp URL prefix */
|
|
|
|
#define HTTP_URL "http://" /* http URL prefix */
|
|
|
|
|
|
|
|
|
|
|
|
#define EMPTYSTRING(x) ((x) == NULL || (*(x) == '\0'))
|
1998-08-03 05:49:25 +04:00
|
|
|
#define FREEPTR(x) if ((x) != NULL) { free(x); (x) = NULL; }
|
|
|
|
|
1999-01-01 13:00:46 +03:00
|
|
|
/*
|
|
|
|
* Generate authorization response based on given authentication challenge.
|
|
|
|
* Returns -1 if an error occurred, otherwise 0.
|
|
|
|
* Sets response to a malloc(3)ed string; caller should free.
|
|
|
|
*/
|
|
|
|
static int
|
1999-05-12 15:16:43 +04:00
|
|
|
auth_url(challenge, response, guser, gpass)
|
1999-01-01 13:00:46 +03:00
|
|
|
const char *challenge;
|
|
|
|
char **response;
|
1999-05-12 15:16:43 +04:00
|
|
|
const char *guser;
|
|
|
|
const char *gpass;
|
1999-01-01 13:00:46 +03:00
|
|
|
{
|
|
|
|
char *cp, *ep, *clear, *line, *realm, *scheme;
|
|
|
|
char user[BUFSIZ], *pass;
|
|
|
|
int rval;
|
|
|
|
size_t len;
|
|
|
|
|
|
|
|
*response = NULL;
|
|
|
|
clear = realm = scheme = NULL;
|
|
|
|
rval = -1;
|
|
|
|
line = xstrdup(challenge);
|
|
|
|
cp = line;
|
|
|
|
|
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout, "auth_url: challenge `%s'\n", challenge);
|
|
|
|
|
|
|
|
scheme = strsep(&cp, " ");
|
|
|
|
#define SCHEME_BASIC "Basic"
|
|
|
|
if (strncasecmp(scheme, SCHEME_BASIC, sizeof(SCHEME_BASIC) - 1) != 0) {
|
|
|
|
warnx("Unsupported WWW Authentication challenge - `%s'",
|
|
|
|
challenge);
|
|
|
|
goto cleanup_auth_url;
|
|
|
|
}
|
|
|
|
cp += strspn(cp, " ");
|
|
|
|
|
|
|
|
#define REALM "realm=\""
|
|
|
|
if (strncasecmp(cp, REALM, sizeof(REALM) - 1) == 0)
|
|
|
|
cp += sizeof(REALM) - 1;
|
|
|
|
else {
|
|
|
|
warnx("Unsupported WWW Authentication challenge - `%s'",
|
|
|
|
challenge);
|
|
|
|
goto cleanup_auth_url;
|
|
|
|
}
|
|
|
|
if ((ep = strchr(cp, '\"')) != NULL) {
|
|
|
|
size_t len = ep - cp;
|
|
|
|
|
|
|
|
realm = (char *)xmalloc(len + 1);
|
|
|
|
strncpy(realm, cp, len);
|
|
|
|
realm[len] = '\0';
|
|
|
|
} else {
|
|
|
|
warnx("Unsupported WWW Authentication challenge - `%s'",
|
|
|
|
challenge);
|
|
|
|
goto cleanup_auth_url;
|
|
|
|
}
|
|
|
|
|
1999-05-12 15:16:43 +04:00
|
|
|
if (guser != NULL) {
|
|
|
|
strncpy(user, guser, sizeof(user) - 1);
|
|
|
|
user[sizeof(user) - 1] = '\0';
|
|
|
|
} else {
|
|
|
|
fprintf(ttyout, "Username for `%s': ", realm);
|
|
|
|
(void)fflush(ttyout);
|
|
|
|
if (fgets(user, sizeof(user) - 1, stdin) == NULL)
|
|
|
|
goto cleanup_auth_url;
|
|
|
|
user[strlen(user) - 1] = '\0';
|
|
|
|
}
|
|
|
|
if (gpass != NULL)
|
|
|
|
pass = (char *)gpass;
|
|
|
|
else
|
|
|
|
pass = getpass("Password: ");
|
1999-01-01 13:00:46 +03:00
|
|
|
|
1999-08-01 16:22:23 +04:00
|
|
|
len = strlen(user) + strlen(pass) + 2; /* user + ":" + pass + "\0" */
|
|
|
|
clear = (char *)xmalloc(len);
|
1999-06-02 06:03:57 +04:00
|
|
|
snprintf(clear, len, "%s:%s", user, pass);
|
1999-05-12 15:16:43 +04:00
|
|
|
if (gpass == NULL)
|
|
|
|
memset(pass, '\0', strlen(pass));
|
1999-01-01 13:00:46 +03:00
|
|
|
|
1999-08-01 16:22:23 +04:00
|
|
|
/* scheme + " " + enc + "\0" */
|
|
|
|
len = strlen(scheme) + 1 + (len + 2) * 4 / 3 + 1;
|
|
|
|
*response = (char *)xmalloc(len);
|
1999-06-02 06:03:57 +04:00
|
|
|
len = snprintf(*response, len, "%s ", scheme);
|
1999-03-08 07:36:12 +03:00
|
|
|
base64_encode(clear, strlen(clear), *response + len);
|
1999-05-12 15:16:43 +04:00
|
|
|
memset(clear, '\0', strlen(clear));
|
1999-01-01 13:00:46 +03:00
|
|
|
rval = 0;
|
|
|
|
|
|
|
|
cleanup_auth_url:
|
|
|
|
FREEPTR(clear);
|
|
|
|
FREEPTR(line);
|
|
|
|
FREEPTR(realm);
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Encode len bytes starting at clear using base64 encoding into encoded,
|
|
|
|
* which should be at least ((len + 2) * 4 / 3 + 1) in size.
|
|
|
|
*/
|
|
|
|
void
|
1999-03-08 07:36:12 +03:00
|
|
|
base64_encode(clear, len, encoded)
|
1999-01-01 13:00:46 +03:00
|
|
|
const char *clear;
|
|
|
|
size_t len;
|
|
|
|
char *encoded;
|
|
|
|
{
|
|
|
|
static const char enc[] =
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
char *cp;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
cp = encoded;
|
|
|
|
for (i = 0; i < len; i += 3) {
|
|
|
|
*(cp++) = enc[((clear[i + 0] >> 2))];
|
|
|
|
*(cp++) = enc[((clear[i + 0] << 4) & 0x30)
|
|
|
|
| ((clear[i + 1] >> 4) & 0x0f)];
|
|
|
|
*(cp++) = enc[((clear[i + 1] << 2) & 0x3c)
|
|
|
|
| ((clear[i + 2] >> 6) & 0x03)];
|
|
|
|
*(cp++) = enc[((clear[i + 2] ) & 0x3f)];
|
|
|
|
}
|
|
|
|
*cp = '\0';
|
|
|
|
while (i-- > len)
|
|
|
|
*(--cp) = '=';
|
|
|
|
}
|
|
|
|
|
1999-03-08 07:36:12 +03:00
|
|
|
/*
|
|
|
|
* 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';
|
|
|
|
}
|
|
|
|
|
1999-01-01 13:00:46 +03:00
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
/*
|
|
|
|
* Parse URL of form:
|
1999-07-12 17:20:34 +04:00
|
|
|
* <type>://[<user>[:<password>@]]<host>[:<port>][/<path>]
|
1998-08-03 05:49:25 +04:00
|
|
|
* Returns -1 if a parse error occurred, otherwise 0.
|
1999-03-08 07:36:12 +03:00
|
|
|
* It's the caller's responsibility to url_decode() the returned
|
|
|
|
* user, pass and path.
|
1999-07-12 17:20:34 +04:00
|
|
|
*
|
1998-08-03 05:49:25 +04:00
|
|
|
* Sets type to url_t, each of the given char ** pointers to a
|
|
|
|
* malloc(3)ed strings of the relevant section, and port to
|
1998-12-27 08:49:53 +03:00
|
|
|
* the number given, or ftpport if ftp://, or httpport if http://.
|
1999-03-22 10:36:40 +03:00
|
|
|
*
|
1999-07-12 17:20:34 +04:00
|
|
|
* If <host> is surrounded by `[' and ']', it's parsed as an
|
|
|
|
* IPv6 address (as per draft-ietf-ipngwg-url-literal-01.txt).
|
|
|
|
*
|
|
|
|
* XXX: this is not totally RFC 1738 compliant; <path> will have the
|
1999-04-28 17:35:40 +04:00
|
|
|
* leading `/' unless it's an ftp:// URL, as this makes things easier
|
|
|
|
* for file:// and http:// URLs. ftp:// URLs have the `/' between the
|
|
|
|
* host and the url-path removed, but any additional leading slashes
|
|
|
|
* in the url-path are retained (because they imply that we should
|
|
|
|
* later do "CWD" with a null argument).
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
* input url output path
|
|
|
|
* --------- -----------
|
1999-07-12 17:20:34 +04:00
|
|
|
* "ftp://host" NULL
|
|
|
|
* "http://host/" NULL
|
|
|
|
* "file://host/dir/file" "dir/file"
|
|
|
|
* "ftp://host/" ""
|
|
|
|
* "ftp://host//" NULL
|
1999-04-28 17:35:40 +04:00
|
|
|
* "ftp://host//dir/file" "/dir/file"
|
1998-08-03 05:49:25 +04:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
parse_url(url, desc, type, user, pass, host, port, path)
|
|
|
|
const char *url;
|
|
|
|
const char *desc;
|
|
|
|
url_t *type;
|
|
|
|
char **user;
|
|
|
|
char **pass;
|
|
|
|
char **host;
|
1999-07-02 12:07:40 +04:00
|
|
|
char **port;
|
1998-08-03 05:49:25 +04:00
|
|
|
char **path;
|
|
|
|
{
|
1999-07-12 17:20:34 +04:00
|
|
|
char *cp, *ep, *thost, *tport;
|
1999-03-08 07:36:12 +03:00
|
|
|
size_t len;
|
1998-08-03 05:49:25 +04:00
|
|
|
|
|
|
|
if (url == NULL || desc == NULL || type == NULL || user == NULL
|
|
|
|
|| pass == NULL || host == NULL || port == NULL || path == NULL)
|
|
|
|
errx(1, "parse_url: invoked with NULL argument!");
|
|
|
|
|
|
|
|
*type = UNKNOWN_URL_T;
|
1999-07-12 17:20:34 +04:00
|
|
|
*user = *pass = *host = *port = *path = NULL;
|
|
|
|
tport = NULL;
|
1998-08-03 05:49:25 +04:00
|
|
|
|
|
|
|
if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) {
|
|
|
|
url += sizeof(HTTP_URL) - 1;
|
|
|
|
*type = HTTP_URL_T;
|
1999-07-12 17:20:34 +04:00
|
|
|
tport = httpport;
|
1998-08-03 05:49:25 +04:00
|
|
|
} else if (strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
|
|
|
|
url += sizeof(FTP_URL) - 1;
|
|
|
|
*type = FTP_URL_T;
|
1999-07-12 17:20:34 +04:00
|
|
|
tport = ftpport;
|
1998-08-03 05:49:25 +04:00
|
|
|
} else if (strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
|
|
|
|
url += sizeof(FILE_URL) - 1;
|
|
|
|
*type = FILE_URL_T;
|
|
|
|
} else {
|
|
|
|
warnx("Invalid %s `%s'", desc, url);
|
|
|
|
cleanup_parse_url:
|
|
|
|
FREEPTR(*user);
|
|
|
|
FREEPTR(*pass);
|
|
|
|
FREEPTR(*host);
|
1999-07-02 12:07:40 +04:00
|
|
|
FREEPTR(*port);
|
1998-08-03 05:49:25 +04:00
|
|
|
FREEPTR(*path);
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*url == '\0')
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
/* find [user[:pass]@]host[:port] */
|
|
|
|
ep = strchr(url, '/');
|
|
|
|
if (ep == NULL)
|
|
|
|
thost = xstrdup(url);
|
|
|
|
else {
|
1999-03-08 07:36:12 +03:00
|
|
|
len = ep - url;
|
1998-08-03 05:49:25 +04:00
|
|
|
thost = (char *)xmalloc(len + 1);
|
|
|
|
strncpy(thost, url, len);
|
|
|
|
thost[len] = '\0';
|
1999-04-28 17:35:40 +04:00
|
|
|
if (*type == FTP_URL_T) /* skip first / for ftp URLs */
|
|
|
|
ep++;
|
1998-08-03 05:49:25 +04:00
|
|
|
*path = xstrdup(ep);
|
|
|
|
}
|
|
|
|
|
1999-07-12 17:20:34 +04:00
|
|
|
cp = strchr(thost, '@'); /* look for user[:pass]@ in URLs */
|
1999-05-12 15:16:43 +04:00
|
|
|
if (cp != NULL) {
|
|
|
|
if (*type == FTP_URL_T)
|
|
|
|
anonftp = 0; /* disable anonftp */
|
1998-08-03 05:49:25 +04:00
|
|
|
*user = thost;
|
|
|
|
*cp = '\0';
|
1999-07-12 17:20:34 +04:00
|
|
|
thost = xstrdup(cp + 1);
|
1998-08-03 05:49:25 +04:00
|
|
|
cp = strchr(*user, ':');
|
|
|
|
if (cp != NULL) {
|
|
|
|
*cp = '\0';
|
|
|
|
*pass = xstrdup(cp + 1);
|
|
|
|
}
|
1999-07-02 12:07:40 +04:00
|
|
|
}
|
|
|
|
|
1999-07-12 17:20:34 +04:00
|
|
|
#ifdef INET6
|
|
|
|
/*
|
|
|
|
* Check if thost is an encoded IPv6 address, as per
|
|
|
|
* draft-ietf-ipngwg-url-literal-01.txt:
|
|
|
|
* `[' ipv6-address ']'
|
|
|
|
*/
|
|
|
|
if (*thost == '[') {
|
|
|
|
cp = thost + 1;
|
|
|
|
if ((ep = strchr(cp, ']')) == NULL ||
|
|
|
|
(ep[1] != '\0' && ep[1] != '\0')) {
|
|
|
|
warnx("Invalid address `%s' in %s `%s'",
|
|
|
|
thost, desc, url);
|
|
|
|
goto cleanup_parse_url;
|
|
|
|
}
|
|
|
|
len = ep - cp; /* change `[xxx]' -> `xxx' */
|
|
|
|
memmove(thost, thost + 1, len);
|
|
|
|
thost[len] = '\0';
|
|
|
|
if (! isipv6addr(thost)) {
|
|
|
|
warnx("Invalid IPv6 address `%s' in %s `%s'",
|
|
|
|
thost, desc, url);
|
|
|
|
goto cleanup_parse_url;
|
|
|
|
}
|
|
|
|
cp = ep + 1;
|
|
|
|
if (*cp == ':')
|
|
|
|
cp++;
|
|
|
|
else
|
|
|
|
cp = NULL;
|
|
|
|
} else
|
|
|
|
#endif /* INET6 */
|
|
|
|
if ((cp = strchr(thost, ':')) != NULL)
|
|
|
|
*cp++ = '\0';
|
|
|
|
*host = thost;
|
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
/* look for [:port] */
|
|
|
|
if (cp != NULL) {
|
|
|
|
long nport;
|
|
|
|
|
1999-07-12 17:20:34 +04:00
|
|
|
nport = strtol(cp, &ep, 10);
|
1998-08-03 05:49:25 +04:00
|
|
|
if (nport < 1 || nport > MAX_IN_PORT_T || *ep != '\0') {
|
1998-12-29 17:59:04 +03:00
|
|
|
warnx("Invalid port `%s' in %s `%s'", cp, desc, url);
|
1998-08-03 05:49:25 +04:00
|
|
|
goto cleanup_parse_url;
|
|
|
|
}
|
1999-07-12 17:20:34 +04:00
|
|
|
tport = cp;
|
1998-08-03 05:49:25 +04:00
|
|
|
}
|
1999-07-12 17:20:34 +04:00
|
|
|
if (tport != NULL);
|
|
|
|
*port = xstrdup(tport);
|
1998-08-03 05:49:25 +04:00
|
|
|
|
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout,
|
1999-07-02 12:07:40 +04:00
|
|
|
"parse_url: user `%s' pass `%s' host %s:%s path `%s'\n",
|
1999-04-28 17:35:40 +04:00
|
|
|
*user ? *user : "<null>", *pass ? *pass : "<null>",
|
1999-07-02 12:07:40 +04:00
|
|
|
*host ? *host : "<null>", *port ? *port : "<null>",
|
1999-04-28 17:35:40 +04:00
|
|
|
*path ? *path : "<null>");
|
1998-08-03 05:49:25 +04:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1997-01-19 17:19:02 +03:00
|
|
|
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
jmp_buf httpabort;
|
|
|
|
|
1997-01-19 17:19:02 +03:00
|
|
|
/*
|
1999-03-08 07:36:12 +03:00
|
|
|
* 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.
|
1998-12-27 08:49:53 +03:00
|
|
|
* Returns -1 on failure, 0 on completed xfer, 1 if ftp connection
|
|
|
|
* is still open (e.g, ftp xfer with trailing /)
|
1997-01-19 17:19:02 +03:00
|
|
|
*/
|
1997-07-20 13:45:35 +04:00
|
|
|
static int
|
1999-03-22 10:36:40 +03:00
|
|
|
fetch_url(url, proxyenv, proxyauth, wwwauth)
|
1999-01-01 13:00:46 +03:00
|
|
|
const char *url;
|
|
|
|
const char *proxyenv;
|
|
|
|
char *proxyauth;
|
|
|
|
char *wwwauth;
|
1998-12-29 17:59:04 +03:00
|
|
|
{
|
1999-08-30 02:21:57 +04:00
|
|
|
#ifdef NI_NUMERICHOST
|
|
|
|
struct addrinfo hints, *res = NULL;
|
|
|
|
int error;
|
|
|
|
#else
|
|
|
|
struct sockaddr_in sin;
|
|
|
|
struct hostent *hp = NULL;
|
|
|
|
#endif
|
1998-12-29 17:59:04 +03:00
|
|
|
volatile sig_t oldintr, oldintp;
|
|
|
|
volatile int s;
|
1999-01-01 16:26:31 +03:00
|
|
|
int ischunked, isproxy, rval, hcode;
|
1998-12-29 17:59:04 +03:00
|
|
|
size_t len;
|
1999-01-01 13:00:46 +03:00
|
|
|
char *cp, *ep, *buf, *savefile;
|
|
|
|
char *auth, *location, *message;
|
1999-07-12 17:20:34 +04:00
|
|
|
char *user, *pass, *host, *port, *path, *decodedpath;
|
1999-05-12 15:16:43 +04:00
|
|
|
char *puser, *ppass;
|
1998-12-29 17:59:04 +03:00
|
|
|
off_t hashbytes;
|
|
|
|
int (*closefunc) __P((FILE *));
|
|
|
|
FILE *fin, *fout;
|
|
|
|
time_t mtime;
|
|
|
|
url_t urltype;
|
1999-07-02 12:07:40 +04:00
|
|
|
in_port_t portnum;
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-06-04 12:28:35 +04:00
|
|
|
closefunc = NULL;
|
1998-07-22 20:06:27 +04:00
|
|
|
fin = fout = NULL;
|
1997-01-19 17:19:02 +03:00
|
|
|
s = -1;
|
1999-01-01 13:00:46 +03:00
|
|
|
buf = savefile = NULL;
|
|
|
|
auth = location = message = NULL;
|
1999-03-22 10:36:40 +03:00
|
|
|
ischunked = isproxy = hcode = 0;
|
1998-12-29 17:59:04 +03:00
|
|
|
rval = 1;
|
1999-05-12 15:16:43 +04:00
|
|
|
user = pass = host = path = decodedpath = puser = ppass = NULL;
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
#ifdef __GNUC__ /* shut up gcc warnings */
|
1998-06-04 12:28:35 +04:00
|
|
|
(void)&closefunc;
|
1998-07-22 20:06:27 +04:00
|
|
|
(void)&fin;
|
1998-06-04 12:28:35 +04:00
|
|
|
(void)&fout;
|
1998-07-22 20:06:27 +04:00
|
|
|
(void)&buf;
|
1998-06-04 12:28:35 +04:00
|
|
|
(void)&savefile;
|
1998-12-29 17:59:04 +03:00
|
|
|
(void)&rval;
|
1998-08-03 23:10:29 +04:00
|
|
|
(void)&isproxy;
|
1999-03-15 11:52:17 +03:00
|
|
|
(void)&hcode;
|
|
|
|
(void)&ischunked;
|
|
|
|
(void)&message;
|
|
|
|
(void)&location;
|
|
|
|
(void)&auth;
|
|
|
|
(void)&decodedpath;
|
1997-07-20 13:45:35 +04:00
|
|
|
#endif
|
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
if (parse_url(url, "URL", &urltype, &user, &pass, &host, &port, &path)
|
|
|
|
== -1)
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1999-09-01 01:30:25 +04:00
|
|
|
portnum = strtol(port, &ep, 10);
|
|
|
|
if (*ep || port == ep) {
|
|
|
|
struct servent *svp = getservbyname(port, "tcp");
|
|
|
|
if (svp != NULL)
|
|
|
|
portnum = ntohs(svp->s_port);
|
|
|
|
}
|
1997-04-05 07:27:32 +04:00
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
if (urltype == FILE_URL_T && ! EMPTYSTRING(host)
|
|
|
|
&& strcasecmp(host, "localhost") != 0) {
|
|
|
|
warnx("No support for non local file URL `%s'", url);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
1998-08-03 05:49:25 +04:00
|
|
|
|
1997-05-23 22:42:36 +04:00
|
|
|
if (EMPTYSTRING(path)) {
|
1998-12-29 17:59:04 +03:00
|
|
|
if (urltype == FTP_URL_T) {
|
1999-03-22 10:36:40 +03:00
|
|
|
rval = fetch_ftp(url);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1998-08-03 05:49:25 +04:00
|
|
|
if (urltype != HTTP_URL_T || outfile == NULL) {
|
|
|
|
warnx("Invalid URL (no file after host) `%s'", url);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-08-03 05:49:25 +04:00
|
|
|
}
|
1997-05-23 22:42:36 +04:00
|
|
|
}
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1999-03-08 07:36:12 +03:00
|
|
|
decodedpath = xstrdup(path);
|
|
|
|
url_decode(decodedpath);
|
|
|
|
|
1998-06-04 12:28:35 +04:00
|
|
|
if (outfile)
|
1998-08-04 07:35:24 +04:00
|
|
|
savefile = xstrdup(outfile);
|
1998-06-04 12:28:35 +04:00
|
|
|
else {
|
1999-03-08 07:36:12 +03:00
|
|
|
cp = strrchr(decodedpath, '/'); /* find savefile */
|
1998-08-04 07:35:24 +04:00
|
|
|
if (cp != NULL)
|
|
|
|
savefile = xstrdup(cp + 1);
|
1998-06-04 12:28:35 +04:00
|
|
|
else
|
1999-03-08 07:36:12 +03:00
|
|
|
savefile = xstrdup(decodedpath);
|
1998-06-04 12:28:35 +04:00
|
|
|
}
|
1997-05-23 22:42:36 +04:00
|
|
|
if (EMPTYSTRING(savefile)) {
|
1998-12-29 17:59:04 +03:00
|
|
|
if (urltype == FTP_URL_T) {
|
1999-03-22 10:36:40 +03:00
|
|
|
rval = fetch_ftp(url);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1998-08-03 05:49:25 +04:00
|
|
|
warnx("Invalid URL (no file after directory) `%s'", url);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1999-03-22 10:36:40 +03:00
|
|
|
} else {
|
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout, "got savefile as `%s'\n", savefile);
|
1997-05-23 22:42:36 +04:00
|
|
|
}
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
filesize = -1;
|
|
|
|
mtime = -1;
|
|
|
|
if (urltype == FILE_URL_T) { /* file:// URLs */
|
|
|
|
struct stat sb;
|
|
|
|
|
|
|
|
direction = "copied";
|
1999-03-08 07:36:12 +03:00
|
|
|
fin = fopen(decodedpath, "r");
|
1998-07-26 16:58:16 +04:00
|
|
|
if (fin == NULL) {
|
1999-03-08 07:36:12 +03:00
|
|
|
warn("Cannot open file `%s'", decodedpath);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1997-04-05 07:27:32 +04:00
|
|
|
}
|
1998-07-26 16:58:16 +04:00
|
|
|
if (fstat(fileno(fin), &sb) == 0) {
|
|
|
|
mtime = sb.st_mtime;
|
|
|
|
filesize = sb.st_size;
|
|
|
|
}
|
1999-01-26 02:17:37 +03:00
|
|
|
if (verbose)
|
1999-03-08 07:36:12 +03:00
|
|
|
fprintf(ttyout, "Copying %s\n", decodedpath);
|
1998-07-26 16:58:16 +04:00
|
|
|
} else { /* ftp:// or http:// URLs */
|
1999-08-22 16:49:00 +04:00
|
|
|
char *leading;
|
|
|
|
int hasleading;
|
|
|
|
|
1998-12-29 17:59:04 +03:00
|
|
|
if (proxyenv == NULL) {
|
|
|
|
if (urltype == HTTP_URL_T)
|
|
|
|
proxyenv = httpproxy;
|
|
|
|
else if (urltype == FTP_URL_T)
|
|
|
|
proxyenv = ftpproxy;
|
|
|
|
}
|
1998-07-26 16:58:16 +04:00
|
|
|
direction = "retrieved";
|
|
|
|
if (proxyenv != NULL) { /* use proxy */
|
1998-08-03 05:49:25 +04:00
|
|
|
url_t purltype;
|
1999-05-12 15:16:43 +04:00
|
|
|
char *phost, *ppath;
|
1999-07-02 12:07:40 +04:00
|
|
|
char *pport;
|
1998-08-03 05:49:25 +04:00
|
|
|
|
|
|
|
isproxy = 1;
|
|
|
|
|
|
|
|
/* check URL against list of no_proxied sites */
|
|
|
|
if (no_proxy != NULL) {
|
|
|
|
char *np, *np_copy;
|
|
|
|
long np_port;
|
|
|
|
size_t hlen, plen;
|
|
|
|
|
|
|
|
np_copy = xstrdup(no_proxy);
|
|
|
|
hlen = strlen(host);
|
|
|
|
while ((cp = strsep(&np_copy, " ,")) != NULL) {
|
|
|
|
if (*cp == '\0')
|
|
|
|
continue;
|
1999-07-02 12:07:40 +04:00
|
|
|
if ((np = strrchr(cp, ':')) != NULL) {
|
1998-08-03 05:49:25 +04:00
|
|
|
*np = '\0';
|
|
|
|
np_port =
|
|
|
|
strtol(np + 1, &ep, 10);
|
|
|
|
if (*ep != '\0')
|
|
|
|
continue;
|
1999-07-02 12:07:40 +04:00
|
|
|
if (portnum !=
|
1998-08-03 05:49:25 +04:00
|
|
|
htons((in_port_t)np_port))
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
plen = strlen(cp);
|
|
|
|
if (strncasecmp(host + hlen - plen,
|
|
|
|
cp, plen) == 0) {
|
|
|
|
isproxy = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FREEPTR(np_copy);
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
if (isproxy) {
|
|
|
|
if (parse_url(proxyenv, "proxy URL", &purltype,
|
1999-07-02 12:07:40 +04:00
|
|
|
&puser, &ppass, &phost, &pport, &ppath)
|
1998-08-03 05:49:25 +04:00
|
|
|
== -1)
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
if ((purltype != HTTP_URL_T
|
|
|
|
&& purltype != FTP_URL_T) ||
|
|
|
|
EMPTYSTRING(phost) ||
|
|
|
|
(! EMPTYSTRING(ppath)
|
|
|
|
&& strcmp(ppath, "/") != 0)) {
|
|
|
|
warnx("Malformed proxy URL `%s'",
|
|
|
|
proxyenv);
|
|
|
|
FREEPTR(phost);
|
1999-07-02 12:07:40 +04:00
|
|
|
FREEPTR(pport);
|
1998-08-03 05:49:25 +04:00
|
|
|
FREEPTR(ppath);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-08-03 05:49:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
FREEPTR(host);
|
|
|
|
host = phost;
|
1999-07-07 02:11:37 +04:00
|
|
|
FREEPTR(port);
|
|
|
|
port = pport;
|
1998-08-03 05:49:25 +04:00
|
|
|
FREEPTR(path);
|
|
|
|
path = xstrdup(url);
|
1999-05-12 15:16:43 +04:00
|
|
|
FREEPTR(ppath);
|
1998-08-03 05:49:25 +04:00
|
|
|
}
|
|
|
|
} /* proxyenv != NULL */
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1999-08-30 02:21:57 +04:00
|
|
|
#ifndef NI_NUMERICHOST
|
1998-07-26 16:58:16 +04:00
|
|
|
memset(&sin, 0, sizeof(sin));
|
|
|
|
sin.sin_family = AF_INET;
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
if (isdigit((unsigned char)host[0])) {
|
|
|
|
if (inet_aton(host, &sin.sin_addr) == 0) {
|
1998-08-03 05:49:25 +04:00
|
|
|
warnx("Invalid IP address `%s'", host);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
hp = gethostbyname(host);
|
|
|
|
if (hp == NULL) {
|
|
|
|
warnx("%s: %s", host, hstrerror(h_errno));
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
|
|
|
if (hp->h_addrtype != AF_INET) {
|
1998-08-03 05:49:25 +04:00
|
|
|
warnx("`%s': not an Internet address?", host);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
1999-08-30 02:21:57 +04:00
|
|
|
if (hp->h_length > sizeof(sin.sin_addr))
|
|
|
|
hp->h_length = sizeof(sin.sin_addr);
|
1998-07-26 16:58:16 +04:00
|
|
|
memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
|
|
|
|
1999-07-02 12:07:40 +04:00
|
|
|
if (port == NULL) {
|
1998-12-27 08:49:53 +03:00
|
|
|
warnx("Unknown port for URL `%s'", url);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-12-27 08:49:53 +03:00
|
|
|
}
|
1999-09-01 02:05:22 +04:00
|
|
|
portnum = strtol(port, &ep, 10);
|
|
|
|
if (*ep || port == ep) {
|
|
|
|
struct servent *svp = getservbyname(port, "tcp");
|
|
|
|
if (svp != NULL)
|
|
|
|
portnum = ntohs(svp->s_port);
|
|
|
|
}
|
1999-07-12 17:20:34 +04:00
|
|
|
sin.sin_port = portnum;
|
1998-07-26 16:58:16 +04:00
|
|
|
|
|
|
|
s = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (s == -1) {
|
|
|
|
warn("Can't create socket");
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
while (xconnect(s, (struct sockaddr *)&sin,
|
|
|
|
sizeof(sin)) == -1) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
continue;
|
|
|
|
if (hp && hp->h_addr_list[1]) {
|
|
|
|
int oerrno = errno;
|
|
|
|
char *ia;
|
|
|
|
|
|
|
|
ia = inet_ntoa(sin.sin_addr);
|
|
|
|
errno = oerrno;
|
1998-08-03 05:49:25 +04:00
|
|
|
warn("Connect to address `%s'", ia);
|
1998-07-26 16:58:16 +04:00
|
|
|
hp->h_addr_list++;
|
|
|
|
memcpy(&sin.sin_addr, hp->h_addr_list[0],
|
|
|
|
(size_t)hp->h_length);
|
1999-01-26 02:17:37 +03:00
|
|
|
if (verbose)
|
|
|
|
fprintf(ttyout, "Trying %s...\n",
|
|
|
|
inet_ntoa(sin.sin_addr));
|
1998-07-26 16:58:16 +04:00
|
|
|
(void)close(s);
|
|
|
|
s = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (s < 0) {
|
|
|
|
warn("Can't create socket");
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
|
|
|
continue;
|
1998-06-04 12:28:35 +04:00
|
|
|
}
|
1998-08-03 05:49:25 +04:00
|
|
|
warn("Can't connect to `%s'", host);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-06-04 12:28:35 +04:00
|
|
|
}
|
1999-07-02 12:07:40 +04:00
|
|
|
#else
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
1999-08-22 16:49:00 +04:00
|
|
|
hints.ai_flags = 0;
|
1999-07-02 12:07:40 +04:00
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_protocol = 0;
|
|
|
|
error = getaddrinfo(host, port, &hints, &res);
|
|
|
|
if (error) {
|
1999-09-15 02:49:14 +04:00
|
|
|
warnx(gai_strerror(error));
|
1999-07-02 12:07:40 +04:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
s = socket(res->ai_family,
|
|
|
|
res->ai_socktype, res->ai_protocol);
|
|
|
|
if (s < 0) {
|
|
|
|
warn("Can't create socket");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xconnect(s, res->ai_addr, res->ai_addrlen) < 0) {
|
|
|
|
char hbuf[MAXHOSTNAMELEN];
|
|
|
|
getnameinfo(res->ai_addr, res->ai_addrlen,
|
|
|
|
hbuf, sizeof(hbuf), NULL, 0,
|
|
|
|
NI_NUMERICHOST);
|
|
|
|
warn("Connect to address `%s'", hbuf);
|
|
|
|
close(s);
|
|
|
|
res = res->ai_next;
|
|
|
|
if (res) {
|
1999-07-12 17:20:34 +04:00
|
|
|
getnameinfo(res->ai_addr,
|
|
|
|
res->ai_addrlen, hbuf, sizeof(hbuf),
|
|
|
|
NULL, 0, NI_NUMERICHOST);
|
1999-07-02 12:07:40 +04:00
|
|
|
if (verbose)
|
1999-07-12 17:20:34 +04:00
|
|
|
fprintf(ttyout,
|
|
|
|
"Trying %s...\n", hbuf);
|
1999-07-02 12:07:40 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
warn("Can't connect to %s", host);
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
fin = fdopen(s, "r+");
|
|
|
|
/*
|
1998-08-03 05:49:25 +04:00
|
|
|
* Construct and send the request.
|
1998-07-26 16:58:16 +04:00
|
|
|
*/
|
1999-08-22 16:49:00 +04:00
|
|
|
if (verbose)
|
|
|
|
fprintf(ttyout, "Requesting %s\n", url);
|
|
|
|
leading = " (";
|
|
|
|
hasleading = 0;
|
1998-08-03 05:49:25 +04:00
|
|
|
if (isproxy) {
|
1999-08-22 16:49:00 +04:00
|
|
|
if (verbose) {
|
|
|
|
fprintf(ttyout, "%svia %s:%s", leading,
|
|
|
|
host, port);
|
|
|
|
leading = ", ";
|
|
|
|
hasleading++;
|
|
|
|
}
|
1999-01-01 13:00:46 +03:00
|
|
|
fprintf(fin, "GET %s HTTP/1.0\r\n", path);
|
1999-01-23 18:46:24 +03:00
|
|
|
if (flushcache)
|
|
|
|
fprintf(fin, "Pragma: no-cache\r\n");
|
1998-08-03 05:49:25 +04:00
|
|
|
} else {
|
1998-12-31 05:10:34 +03:00
|
|
|
struct utsname unam;
|
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
fprintf(fin, "GET %s HTTP/1.1\r\n", path);
|
1999-07-02 12:07:40 +04:00
|
|
|
fprintf(fin, "Host: %s:%s\r\n", host, port);
|
1998-11-22 09:52:32 +03:00
|
|
|
fprintf(fin, "Accept: */*\r\n");
|
1998-12-31 05:10:34 +03:00
|
|
|
if (uname(&unam) != -1) {
|
|
|
|
fprintf(fin, "User-Agent: %s-%s/ftp\r\n",
|
|
|
|
unam.sysname, unam.release);
|
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
fprintf(fin, "Connection: close\r\n");
|
1999-01-23 18:46:24 +03:00
|
|
|
if (flushcache)
|
|
|
|
fprintf(fin, "Cache-Control: no-cache\r\n");
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
1999-01-01 13:00:46 +03:00
|
|
|
if (wwwauth) {
|
1999-08-22 16:49:00 +04:00
|
|
|
if (verbose) {
|
|
|
|
fprintf(ttyout, "%swith authorization",
|
|
|
|
leading);
|
|
|
|
leading = ", ";
|
|
|
|
hasleading++;
|
|
|
|
}
|
1999-01-01 13:00:46 +03:00
|
|
|
fprintf(fin, "Authorization: %s\r\n", wwwauth);
|
|
|
|
}
|
1999-01-05 03:31:20 +03:00
|
|
|
if (proxyauth) {
|
1999-08-22 16:49:00 +04:00
|
|
|
if (verbose) {
|
1999-01-26 02:17:37 +03:00
|
|
|
fprintf(ttyout,
|
1999-08-22 16:49:00 +04:00
|
|
|
"%swith proxy authorization", leading);
|
|
|
|
leading = ", ";
|
|
|
|
hasleading++;
|
|
|
|
}
|
1999-01-01 13:00:46 +03:00
|
|
|
fprintf(fin, "Proxy-Authorization: %s\r\n", proxyauth);
|
1999-01-05 03:31:20 +03:00
|
|
|
}
|
1999-08-22 16:49:00 +04:00
|
|
|
if (verbose && hasleading)
|
|
|
|
fputs(")\n", ttyout);
|
1999-01-01 13:00:46 +03:00
|
|
|
fprintf(fin, "\r\n");
|
1998-07-26 16:58:16 +04:00
|
|
|
if (fflush(fin) == EOF) {
|
|
|
|
warn("Writing HTTP request");
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
/* Read the response */
|
1998-07-22 20:06:27 +04:00
|
|
|
if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) {
|
|
|
|
warn("Receiving HTTP reply");
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-22 20:06:27 +04:00
|
|
|
}
|
|
|
|
while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n'))
|
|
|
|
buf[--len] = '\0';
|
|
|
|
if (debug)
|
1998-08-03 05:49:25 +04:00
|
|
|
fprintf(ttyout, "received `%s'\n", buf);
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-12-29 17:59:04 +03:00
|
|
|
/* Determine HTTP response code */
|
1998-07-26 16:58:16 +04:00
|
|
|
cp = strchr(buf, ' ');
|
|
|
|
if (cp == NULL)
|
|
|
|
goto improper;
|
|
|
|
else
|
|
|
|
cp++;
|
1998-12-29 17:59:04 +03:00
|
|
|
hcode = strtol(cp, &ep, 10);
|
|
|
|
if (*ep != '\0' && !isspace((unsigned char)*ep))
|
|
|
|
goto improper;
|
|
|
|
message = xstrdup(cp);
|
1998-07-26 16:58:16 +04:00
|
|
|
|
|
|
|
/* Read the rest of the header. */
|
1998-08-03 05:49:25 +04:00
|
|
|
FREEPTR(buf);
|
1998-07-26 16:58:16 +04:00
|
|
|
while (1) {
|
|
|
|
if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0))
|
|
|
|
== NULL) {
|
|
|
|
warn("Receiving HTTP reply");
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
|
|
|
while (len > 0 &&
|
|
|
|
(buf[len-1] == '\r' || buf[len-1] == '\n'))
|
|
|
|
buf[--len] = '\0';
|
|
|
|
if (len == 0)
|
|
|
|
break;
|
|
|
|
if (debug)
|
1998-08-03 05:49:25 +04:00
|
|
|
fprintf(ttyout, "received `%s'\n", buf);
|
1998-07-26 16:58:16 +04:00
|
|
|
|
|
|
|
/* Look for some headers */
|
|
|
|
cp = buf;
|
1998-12-29 17:59:04 +03:00
|
|
|
|
1997-01-19 17:19:02 +03:00
|
|
|
#define CONTENTLEN "Content-Length: "
|
1998-07-26 16:58:16 +04:00
|
|
|
if (strncasecmp(cp, CONTENTLEN,
|
1999-01-01 13:00:46 +03:00
|
|
|
sizeof(CONTENTLEN) - 1) == 0) {
|
1998-07-26 16:58:16 +04:00
|
|
|
cp += sizeof(CONTENTLEN) - 1;
|
|
|
|
filesize = strtol(cp, &ep, 10);
|
|
|
|
if (filesize < 1 || *ep != '\0')
|
|
|
|
goto improper;
|
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout,
|
|
|
|
#ifndef NO_QUAD
|
|
|
|
"parsed length as: %qd\n",
|
|
|
|
(long long)filesize);
|
|
|
|
#else
|
|
|
|
"parsed length as: %ld\n",
|
|
|
|
(long)filesize);
|
|
|
|
#endif
|
1998-12-29 17:59:04 +03:00
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
#define LASTMOD "Last-Modified: "
|
|
|
|
} else if (strncasecmp(cp, LASTMOD,
|
1999-01-01 13:00:46 +03:00
|
|
|
sizeof(LASTMOD) - 1) == 0) {
|
1998-07-26 16:58:16 +04:00
|
|
|
struct tm parsed;
|
|
|
|
char *t;
|
|
|
|
|
|
|
|
cp += sizeof(LASTMOD) - 1;
|
|
|
|
/* RFC 1123 */
|
|
|
|
if ((t = strptime(cp,
|
|
|
|
"%a, %d %b %Y %H:%M:%S GMT",
|
|
|
|
&parsed))
|
|
|
|
/* RFC 850 */
|
|
|
|
|| (t = strptime(cp,
|
|
|
|
"%a, %d-%b-%y %H:%M:%S GMT",
|
|
|
|
&parsed))
|
|
|
|
/* asctime */
|
|
|
|
|| (t = strptime(cp,
|
|
|
|
"%a, %b %d %H:%M:%S %Y",
|
|
|
|
&parsed))) {
|
1998-11-13 01:27:17 +03:00
|
|
|
parsed.tm_isdst = -1;
|
1998-07-26 16:58:16 +04:00
|
|
|
if (*t == '\0')
|
1998-11-18 10:24:25 +03:00
|
|
|
mtime = mkgmtime(&parsed);
|
1998-11-13 01:27:17 +03:00
|
|
|
if (debug && mtime != -1) {
|
1998-07-26 16:58:16 +04:00
|
|
|
fprintf(ttyout,
|
|
|
|
"parsed date as: %s",
|
|
|
|
ctime(&mtime));
|
1998-11-13 01:27:17 +03:00
|
|
|
}
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
|
1998-07-22 20:06:27 +04:00
|
|
|
#define LOCATION "Location: "
|
1998-12-29 17:59:04 +03:00
|
|
|
} else if (strncasecmp(cp, LOCATION,
|
1999-01-01 13:00:46 +03:00
|
|
|
sizeof(LOCATION) - 1) == 0) {
|
1998-07-26 16:58:16 +04:00
|
|
|
cp += sizeof(LOCATION) - 1;
|
1998-12-29 17:59:04 +03:00
|
|
|
location = xstrdup(cp);
|
1998-07-26 16:58:16 +04:00
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout,
|
|
|
|
"parsed location as: %s\n", cp);
|
1999-01-01 13:00:46 +03:00
|
|
|
|
1999-01-01 16:26:31 +03:00
|
|
|
#define TRANSENC "Transfer-Encoding: "
|
|
|
|
} else if (strncasecmp(cp, TRANSENC,
|
|
|
|
sizeof(TRANSENC) - 1) == 0) {
|
|
|
|
cp += sizeof(TRANSENC) - 1;
|
|
|
|
if (strcasecmp(cp, "chunked") != 0) {
|
|
|
|
warnx(
|
|
|
|
"Unsupported transfer encoding - `%s'",
|
|
|
|
cp);
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
ischunked++;
|
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout,
|
|
|
|
"using chunked encoding\n");
|
|
|
|
|
1999-01-01 13:00:46 +03:00
|
|
|
#define PROXYAUTH "Proxy-Authenticate: "
|
|
|
|
} else if (strncasecmp(cp, PROXYAUTH,
|
|
|
|
sizeof(PROXYAUTH) - 1) == 0) {
|
|
|
|
cp += sizeof(PROXYAUTH) - 1;
|
|
|
|
FREEPTR(auth);
|
|
|
|
auth = xstrdup(cp);
|
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout,
|
|
|
|
"parsed proxy-auth as: %s\n", cp);
|
|
|
|
|
|
|
|
#define WWWAUTH "WWW-Authenticate: "
|
|
|
|
} else if (strncasecmp(cp, WWWAUTH,
|
|
|
|
sizeof(WWWAUTH) - 1) == 0) {
|
|
|
|
cp += sizeof(WWWAUTH) - 1;
|
|
|
|
FREEPTR(auth);
|
|
|
|
auth = xstrdup(cp);
|
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout,
|
|
|
|
"parsed www-auth as: %s\n", cp);
|
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
1999-01-01 13:00:46 +03:00
|
|
|
|
1998-07-22 20:06:27 +04:00
|
|
|
}
|
1999-05-12 15:16:43 +04:00
|
|
|
/* finished parsing header */
|
1998-08-03 05:49:25 +04:00
|
|
|
FREEPTR(buf);
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1999-03-22 10:36:40 +03:00
|
|
|
switch (hcode) {
|
|
|
|
case 200:
|
|
|
|
break;
|
|
|
|
case 300:
|
|
|
|
case 301:
|
|
|
|
case 302:
|
|
|
|
case 303:
|
|
|
|
case 305:
|
|
|
|
if (EMPTYSTRING(location)) {
|
|
|
|
warnx(
|
|
|
|
"No redirection Location provided by server");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
if (redirect_loop++ > 5) {
|
|
|
|
warnx("Too many redirections requested");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
if (hcode == 305) {
|
|
|
|
if (verbose)
|
|
|
|
fprintf(ttyout, "Redirected via %s\n",
|
|
|
|
location);
|
|
|
|
rval = fetch_url(url, location,
|
|
|
|
proxyauth, wwwauth);
|
|
|
|
} else {
|
|
|
|
if (verbose)
|
|
|
|
fprintf(ttyout, "Redirected to %s\n",
|
|
|
|
location);
|
|
|
|
rval = go_fetch(location);
|
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1999-03-22 10:36:40 +03:00
|
|
|
case 401:
|
|
|
|
case 407:
|
|
|
|
{
|
|
|
|
char **authp;
|
1999-05-12 15:16:43 +04:00
|
|
|
char *auser, *apass;
|
1999-03-22 10:36:40 +03:00
|
|
|
|
|
|
|
fprintf(ttyout, "%s\n", message);
|
|
|
|
if (EMPTYSTRING(auth)) {
|
|
|
|
warnx(
|
|
|
|
"No authentication challenge provided by server");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1999-05-12 15:16:43 +04:00
|
|
|
if (hcode == 401) {
|
|
|
|
authp = &wwwauth;
|
|
|
|
auser = user;
|
|
|
|
apass = pass;
|
|
|
|
} else {
|
|
|
|
authp = &proxyauth;
|
|
|
|
auser = puser;
|
|
|
|
apass = ppass;
|
|
|
|
}
|
1999-03-22 10:36:40 +03:00
|
|
|
if (*authp != NULL) {
|
|
|
|
char reply[10];
|
|
|
|
|
|
|
|
fprintf(ttyout,
|
|
|
|
"Authorization failed. Retry (y/n)? ");
|
|
|
|
if (fgets(reply, sizeof(reply), stdin) != NULL
|
|
|
|
&& tolower(reply[0]) != 'y')
|
|
|
|
goto cleanup_fetch_url;
|
1999-05-12 15:16:43 +04:00
|
|
|
auser = NULL;
|
|
|
|
apass = NULL;
|
1999-03-22 10:36:40 +03:00
|
|
|
}
|
1999-05-12 15:16:43 +04:00
|
|
|
if (auth_url(auth, authp, auser, apass) == 0) {
|
1999-03-22 10:36:40 +03:00
|
|
|
rval = fetch_url(url, proxyenv,
|
|
|
|
proxyauth, wwwauth);
|
|
|
|
memset(*authp, '\0', strlen(*authp));
|
|
|
|
FREEPTR(*authp);
|
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1999-03-22 10:36:40 +03:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
if (message)
|
|
|
|
warnx("Error retrieving file - `%s'", message);
|
|
|
|
else
|
|
|
|
warnx("Unknown error retrieving file");
|
1999-01-01 13:00:46 +03:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1999-03-22 10:36:40 +03:00
|
|
|
} /* end of ftp:// or http:// specific setup */
|
1998-12-29 17:59:04 +03:00
|
|
|
|
1998-06-04 12:28:35 +04:00
|
|
|
oldintr = oldintp = NULL;
|
|
|
|
|
|
|
|
/* Open the output file. */
|
|
|
|
if (strcmp(savefile, "-") == 0) {
|
|
|
|
fout = stdout;
|
|
|
|
} else if (*savefile == '|') {
|
|
|
|
oldintp = signal(SIGPIPE, SIG_IGN);
|
|
|
|
fout = popen(savefile + 1, "w");
|
|
|
|
if (fout == NULL) {
|
1998-08-03 05:49:25 +04:00
|
|
|
warn("Can't run `%s'", savefile + 1);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-06-04 12:28:35 +04:00
|
|
|
}
|
|
|
|
closefunc = pclose;
|
|
|
|
} else {
|
|
|
|
fout = fopen(savefile, "w");
|
|
|
|
if (fout == NULL) {
|
1998-08-03 05:49:25 +04:00
|
|
|
warn("Can't open `%s'", savefile);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-06-04 12:28:35 +04:00
|
|
|
}
|
|
|
|
closefunc = fclose;
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
|
|
|
|
1998-06-04 12:28:35 +04:00
|
|
|
/* Trap signals */
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
if (setjmp(httpabort)) {
|
|
|
|
if (oldintr)
|
1997-03-13 09:23:11 +03:00
|
|
|
(void)signal(SIGINT, oldintr);
|
1998-06-04 12:28:35 +04:00
|
|
|
if (oldintp)
|
|
|
|
(void)signal(SIGPIPE, oldintp);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
}
|
|
|
|
oldintr = signal(SIGINT, aborthttp);
|
|
|
|
|
1997-01-19 17:19:02 +03:00
|
|
|
bytes = 0;
|
|
|
|
hashbytes = mark;
|
|
|
|
progressmeter(-1);
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
|
1998-07-22 20:06:27 +04:00
|
|
|
/* Finally, suck down the file. */
|
1999-01-01 16:26:31 +03:00
|
|
|
buf = xmalloc(BUFSIZ + 1);
|
|
|
|
do {
|
|
|
|
ssize_t chunksize;
|
|
|
|
|
|
|
|
chunksize = 0;
|
|
|
|
/* read chunksize */
|
|
|
|
if (ischunked) {
|
|
|
|
if (fgets(buf, BUFSIZ, fin) == NULL) {
|
|
|
|
warnx("Unexpected EOF reading chunksize");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
chunksize = strtol(buf, &ep, 16);
|
|
|
|
if (strcmp(ep, "\r\n") != 0) {
|
|
|
|
warnx("Unexpected data following chunksize");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
if (debug)
|
[fear this; more ftp hacking from lukem :-]
features:
---------
* transfer rate throttling with the new `rate' command. syntax:
rate direction [max [incr]]
where direction is `all', `get' or `put'.
if max is not supplied, the current settings are displayed.
if max is supplied, then transfers in the given direction will
be throttled to this value.
if incr is supplied, the increment for the `on-the-fly' scaling
will be set to that, otherwise `1024' is used.
currently implemented for binary get, binary put, and url fetches.
not yet supported for ascii get or put, or local file copies.
* on-the-fly scaling of the throttle based on signals:
- SIGUSR1 raises the throttle rate by the increment for that direction
- SIGUSR2 lowers the throttle rate by the increment for that direction
* -T dir,max[,incr] option to set rate from the command line
* `k', `m', `g' suffix support for bytecounts in the `hash', `rate',
`rcvbuf' and `sndbuf' commands)
bug fixes and code mods:
------------------------
* fix up ftp_login() so that ruserpass() is always called, even for
command-line url fetches.
* implement strsuftoi(), which parses a given number into a int with
suffix support. replaces getsockbufsize()
* implement parserate(), which does the argv parsing for -T and rate
* save and restore errno in signal handlers (may not be necessary, but
it doesn't hurt)
notes:
------
the rate command has had reasonable testing, but I'd like feedback
if it doesn't do the right thing, especially from people on slower
(i.e, modem) links.
I haven't tested the rate throttle against a http server which does
`transfer-encoding: chunked' because I couldn't find a server to
test against.
1999-06-29 14:43:16 +04:00
|
|
|
fprintf(ttyout,
|
|
|
|
#ifndef NO_QUAD
|
|
|
|
"got chunksize of %qd\n",
|
1999-01-01 16:26:31 +03:00
|
|
|
(long long)chunksize);
|
[fear this; more ftp hacking from lukem :-]
features:
---------
* transfer rate throttling with the new `rate' command. syntax:
rate direction [max [incr]]
where direction is `all', `get' or `put'.
if max is not supplied, the current settings are displayed.
if max is supplied, then transfers in the given direction will
be throttled to this value.
if incr is supplied, the increment for the `on-the-fly' scaling
will be set to that, otherwise `1024' is used.
currently implemented for binary get, binary put, and url fetches.
not yet supported for ascii get or put, or local file copies.
* on-the-fly scaling of the throttle based on signals:
- SIGUSR1 raises the throttle rate by the increment for that direction
- SIGUSR2 lowers the throttle rate by the increment for that direction
* -T dir,max[,incr] option to set rate from the command line
* `k', `m', `g' suffix support for bytecounts in the `hash', `rate',
`rcvbuf' and `sndbuf' commands)
bug fixes and code mods:
------------------------
* fix up ftp_login() so that ruserpass() is always called, even for
command-line url fetches.
* implement strsuftoi(), which parses a given number into a int with
suffix support. replaces getsockbufsize()
* implement parserate(), which does the argv parsing for -T and rate
* save and restore errno in signal handlers (may not be necessary, but
it doesn't hurt)
notes:
------
the rate command has had reasonable testing, but I'd like feedback
if it doesn't do the right thing, especially from people on slower
(i.e, modem) links.
I haven't tested the rate throttle against a http server which does
`transfer-encoding: chunked' because I couldn't find a server to
test against.
1999-06-29 14:43:16 +04:00
|
|
|
#else
|
|
|
|
"got chunksize of %ld\n",
|
|
|
|
(long)chunksize);
|
|
|
|
#endif
|
1999-01-01 16:26:31 +03:00
|
|
|
if (chunksize == 0)
|
|
|
|
break;
|
|
|
|
}
|
[fear this; more ftp hacking from lukem :-]
features:
---------
* transfer rate throttling with the new `rate' command. syntax:
rate direction [max [incr]]
where direction is `all', `get' or `put'.
if max is not supplied, the current settings are displayed.
if max is supplied, then transfers in the given direction will
be throttled to this value.
if incr is supplied, the increment for the `on-the-fly' scaling
will be set to that, otherwise `1024' is used.
currently implemented for binary get, binary put, and url fetches.
not yet supported for ascii get or put, or local file copies.
* on-the-fly scaling of the throttle based on signals:
- SIGUSR1 raises the throttle rate by the increment for that direction
- SIGUSR2 lowers the throttle rate by the increment for that direction
* -T dir,max[,incr] option to set rate from the command line
* `k', `m', `g' suffix support for bytecounts in the `hash', `rate',
`rcvbuf' and `sndbuf' commands)
bug fixes and code mods:
------------------------
* fix up ftp_login() so that ruserpass() is always called, even for
command-line url fetches.
* implement strsuftoi(), which parses a given number into a int with
suffix support. replaces getsockbufsize()
* implement parserate(), which does the argv parsing for -T and rate
* save and restore errno in signal handlers (may not be necessary, but
it doesn't hurt)
notes:
------
the rate command has had reasonable testing, but I'd like feedback
if it doesn't do the right thing, especially from people on slower
(i.e, modem) links.
I haven't tested the rate throttle against a http server which does
`transfer-encoding: chunked' because I couldn't find a server to
test against.
1999-06-29 14:43:16 +04:00
|
|
|
/* transfer file or chunk */
|
|
|
|
while (1) {
|
|
|
|
struct timeval then, now, td;
|
|
|
|
off_t bufrem;
|
|
|
|
|
|
|
|
(void)gettimeofday(&then, NULL);
|
|
|
|
bufrem = rate_get ? rate_get : BUFSIZ;
|
|
|
|
while (bufrem > 0) {
|
|
|
|
len = fread(buf, sizeof(char),
|
|
|
|
ischunked ? MIN(chunksize, bufrem) : BUFSIZ,
|
|
|
|
fin);
|
|
|
|
if (len <= 0)
|
|
|
|
goto chunkdone;
|
|
|
|
bytes += len;
|
|
|
|
bufrem -= len;
|
|
|
|
if (fwrite(buf, sizeof(char), len, fout)
|
|
|
|
!= len) {
|
|
|
|
warn("Writing `%s'", savefile);
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1999-01-01 16:26:31 +03:00
|
|
|
}
|
|
|
|
if (hash && !progress) {
|
|
|
|
while (bytes >= hashbytes) {
|
|
|
|
(void)putc('#', ttyout);
|
|
|
|
hashbytes += mark;
|
|
|
|
}
|
|
|
|
(void)fflush(ttyout);
|
|
|
|
}
|
[fear this; more ftp hacking from lukem :-]
features:
---------
* transfer rate throttling with the new `rate' command. syntax:
rate direction [max [incr]]
where direction is `all', `get' or `put'.
if max is not supplied, the current settings are displayed.
if max is supplied, then transfers in the given direction will
be throttled to this value.
if incr is supplied, the increment for the `on-the-fly' scaling
will be set to that, otherwise `1024' is used.
currently implemented for binary get, binary put, and url fetches.
not yet supported for ascii get or put, or local file copies.
* on-the-fly scaling of the throttle based on signals:
- SIGUSR1 raises the throttle rate by the increment for that direction
- SIGUSR2 lowers the throttle rate by the increment for that direction
* -T dir,max[,incr] option to set rate from the command line
* `k', `m', `g' suffix support for bytecounts in the `hash', `rate',
`rcvbuf' and `sndbuf' commands)
bug fixes and code mods:
------------------------
* fix up ftp_login() so that ruserpass() is always called, even for
command-line url fetches.
* implement strsuftoi(), which parses a given number into a int with
suffix support. replaces getsockbufsize()
* implement parserate(), which does the argv parsing for -T and rate
* save and restore errno in signal handlers (may not be necessary, but
it doesn't hurt)
notes:
------
the rate command has had reasonable testing, but I'd like feedback
if it doesn't do the right thing, especially from people on slower
(i.e, modem) links.
I haven't tested the rate throttle against a http server which does
`transfer-encoding: chunked' because I couldn't find a server to
test against.
1999-06-29 14:43:16 +04:00
|
|
|
if (ischunked) {
|
1999-01-01 16:26:31 +03:00
|
|
|
chunksize -= len;
|
[fear this; more ftp hacking from lukem :-]
features:
---------
* transfer rate throttling with the new `rate' command. syntax:
rate direction [max [incr]]
where direction is `all', `get' or `put'.
if max is not supplied, the current settings are displayed.
if max is supplied, then transfers in the given direction will
be throttled to this value.
if incr is supplied, the increment for the `on-the-fly' scaling
will be set to that, otherwise `1024' is used.
currently implemented for binary get, binary put, and url fetches.
not yet supported for ascii get or put, or local file copies.
* on-the-fly scaling of the throttle based on signals:
- SIGUSR1 raises the throttle rate by the increment for that direction
- SIGUSR2 lowers the throttle rate by the increment for that direction
* -T dir,max[,incr] option to set rate from the command line
* `k', `m', `g' suffix support for bytecounts in the `hash', `rate',
`rcvbuf' and `sndbuf' commands)
bug fixes and code mods:
------------------------
* fix up ftp_login() so that ruserpass() is always called, even for
command-line url fetches.
* implement strsuftoi(), which parses a given number into a int with
suffix support. replaces getsockbufsize()
* implement parserate(), which does the argv parsing for -T and rate
* save and restore errno in signal handlers (may not be necessary, but
it doesn't hurt)
notes:
------
the rate command has had reasonable testing, but I'd like feedback
if it doesn't do the right thing, especially from people on slower
(i.e, modem) links.
I haven't tested the rate throttle against a http server which does
`transfer-encoding: chunked' because I couldn't find a server to
test against.
1999-06-29 14:43:16 +04:00
|
|
|
if (chunksize <= 0)
|
|
|
|
goto chunkdone;
|
|
|
|
}
|
|
|
|
if (rate_get) {
|
|
|
|
while (1) {
|
|
|
|
(void)gettimeofday(&now, NULL);
|
|
|
|
timersub(&now, &then, &td);
|
|
|
|
if (td.tv_sec > 0)
|
|
|
|
break;
|
|
|
|
usleep(1000000 - td.tv_usec);
|
|
|
|
}
|
|
|
|
}
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
1999-01-01 16:26:31 +03:00
|
|
|
/* read CRLF after chunk*/
|
[fear this; more ftp hacking from lukem :-]
features:
---------
* transfer rate throttling with the new `rate' command. syntax:
rate direction [max [incr]]
where direction is `all', `get' or `put'.
if max is not supplied, the current settings are displayed.
if max is supplied, then transfers in the given direction will
be throttled to this value.
if incr is supplied, the increment for the `on-the-fly' scaling
will be set to that, otherwise `1024' is used.
currently implemented for binary get, binary put, and url fetches.
not yet supported for ascii get or put, or local file copies.
* on-the-fly scaling of the throttle based on signals:
- SIGUSR1 raises the throttle rate by the increment for that direction
- SIGUSR2 lowers the throttle rate by the increment for that direction
* -T dir,max[,incr] option to set rate from the command line
* `k', `m', `g' suffix support for bytecounts in the `hash', `rate',
`rcvbuf' and `sndbuf' commands)
bug fixes and code mods:
------------------------
* fix up ftp_login() so that ruserpass() is always called, even for
command-line url fetches.
* implement strsuftoi(), which parses a given number into a int with
suffix support. replaces getsockbufsize()
* implement parserate(), which does the argv parsing for -T and rate
* save and restore errno in signal handlers (may not be necessary, but
it doesn't hurt)
notes:
------
the rate command has had reasonable testing, but I'd like feedback
if it doesn't do the right thing, especially from people on slower
(i.e, modem) links.
I haven't tested the rate throttle against a http server which does
`transfer-encoding: chunked' because I couldn't find a server to
test against.
1999-06-29 14:43:16 +04:00
|
|
|
chunkdone:
|
1999-01-01 16:26:31 +03:00
|
|
|
if (ischunked) {
|
|
|
|
if (fgets(buf, BUFSIZ, fin) == NULL)
|
|
|
|
break;
|
|
|
|
if (strcmp(buf, "\r\n") != 0) {
|
|
|
|
warnx("Unexpected data following chunk");
|
|
|
|
goto cleanup_fetch_url;
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
|
|
|
}
|
1999-01-01 16:26:31 +03:00
|
|
|
} while (ischunked);
|
1997-01-19 17:19:02 +03:00
|
|
|
if (hash && !progress && bytes > 0) {
|
|
|
|
if (bytes < mark)
|
1998-06-04 12:28:35 +04:00
|
|
|
(void)putc('#', ttyout);
|
|
|
|
(void)putc('\n', ttyout);
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
1998-07-26 16:58:16 +04:00
|
|
|
if (ferror(fin)) {
|
|
|
|
warn("Reading file");
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
progressmeter(1);
|
1998-07-26 16:58:16 +04:00
|
|
|
(void)fflush(fout);
|
1997-03-13 09:23:11 +03:00
|
|
|
(void)signal(SIGINT, oldintr);
|
1998-06-04 12:28:35 +04:00
|
|
|
if (oldintp)
|
|
|
|
(void)signal(SIGPIPE, oldintp);
|
1998-07-26 16:58:16 +04:00
|
|
|
if (closefunc == fclose && mtime != -1) {
|
|
|
|
struct timeval tval[2];
|
|
|
|
|
|
|
|
(void)gettimeofday(&tval[0], NULL);
|
|
|
|
tval[1].tv_sec = mtime;
|
|
|
|
tval[1].tv_usec = 0;
|
1998-08-08 07:33:20 +04:00
|
|
|
(*closefunc)(fout);
|
|
|
|
fout = NULL;
|
|
|
|
|
|
|
|
if (utimes(savefile, tval) == -1) {
|
1998-07-26 16:58:16 +04:00
|
|
|
fprintf(ttyout,
|
|
|
|
"Can't change modification time to %s",
|
|
|
|
asctime(localtime(&mtime)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bytes > 0)
|
|
|
|
ptransfer(0);
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-12-29 17:59:04 +03:00
|
|
|
rval = 0;
|
|
|
|
goto cleanup_fetch_url;
|
1997-06-29 10:34:50 +04:00
|
|
|
|
1997-01-19 17:19:02 +03:00
|
|
|
improper:
|
1998-08-03 05:49:25 +04:00
|
|
|
warnx("Improper response from `%s'", host);
|
1997-06-29 10:34:50 +04:00
|
|
|
|
1998-12-29 17:59:04 +03:00
|
|
|
cleanup_fetch_url:
|
1998-07-10 08:39:03 +04:00
|
|
|
resetsockbufsize();
|
1998-07-22 20:06:27 +04:00
|
|
|
if (fin != NULL)
|
|
|
|
fclose(fin);
|
|
|
|
else if (s != -1)
|
1997-01-19 17:19:02 +03:00
|
|
|
close(s);
|
1998-06-04 12:28:35 +04:00
|
|
|
if (closefunc != NULL && fout != NULL)
|
|
|
|
(*closefunc)(fout);
|
1999-08-30 02:21:57 +04:00
|
|
|
#ifdef NI_NUMERICHOST
|
1999-08-22 16:49:00 +04:00
|
|
|
if (res != NULL)
|
|
|
|
freeaddrinfo(res);
|
1999-08-30 02:21:57 +04:00
|
|
|
#endif
|
1998-08-04 07:35:24 +04:00
|
|
|
FREEPTR(savefile);
|
1998-08-03 05:49:25 +04:00
|
|
|
FREEPTR(user);
|
|
|
|
FREEPTR(pass);
|
|
|
|
FREEPTR(host);
|
1999-07-02 12:07:40 +04:00
|
|
|
FREEPTR(port);
|
1998-08-03 05:49:25 +04:00
|
|
|
FREEPTR(path);
|
1999-03-08 07:36:12 +03:00
|
|
|
FREEPTR(decodedpath);
|
1999-05-12 15:16:43 +04:00
|
|
|
FREEPTR(puser);
|
|
|
|
FREEPTR(ppass);
|
1998-08-03 05:49:25 +04:00
|
|
|
FREEPTR(buf);
|
1999-01-01 13:00:46 +03:00
|
|
|
FREEPTR(auth);
|
1998-12-29 17:59:04 +03:00
|
|
|
FREEPTR(location);
|
|
|
|
FREEPTR(message);
|
|
|
|
return (rval);
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
|
|
|
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
/*
|
1999-03-08 07:36:12 +03:00
|
|
|
* Abort a HTTP retrieval
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
*/
|
|
|
|
void
|
1997-03-13 09:23:11 +03:00
|
|
|
aborthttp(notused)
|
|
|
|
int notused;
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
{
|
|
|
|
|
|
|
|
alarmtimer(0);
|
1998-07-22 20:06:27 +04:00
|
|
|
fputs("\nHTTP fetch aborted.\n", ttyout);
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
longjmp(httpabort, 1);
|
|
|
|
}
|
|
|
|
|
1997-01-19 17:19:02 +03:00
|
|
|
/*
|
1999-03-08 07:36:12 +03:00
|
|
|
* Retrieve ftp URL or classic ftp argument using FTP.
|
1999-07-12 17:20:34 +04:00
|
|
|
* Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
|
1998-12-29 17:59:04 +03:00
|
|
|
* is still open (e.g, ftp xfer with trailing /)
|
|
|
|
*/
|
|
|
|
static int
|
1999-03-22 10:36:40 +03:00
|
|
|
fetch_ftp(url)
|
1998-12-29 17:59:04 +03:00
|
|
|
const char *url;
|
|
|
|
{
|
|
|
|
char *cp, *xargv[5], rempath[MAXPATHLEN];
|
|
|
|
char *host, *path, *dir, *file, *user, *pass;
|
1999-07-02 12:07:40 +04:00
|
|
|
char *port;
|
1999-04-28 17:35:40 +04:00
|
|
|
int dirhasglob, filehasglob, oautologin, rval, type, xargc;
|
|
|
|
url_t urltype;
|
1998-12-29 17:59:04 +03:00
|
|
|
|
|
|
|
host = path = dir = file = user = pass = NULL;
|
1999-07-02 12:07:40 +04:00
|
|
|
port = NULL;
|
1998-12-29 17:59:04 +03:00
|
|
|
rval = 1;
|
1999-04-28 17:35:40 +04:00
|
|
|
type = TYPE_I;
|
1998-12-29 17:59:04 +03:00
|
|
|
|
|
|
|
if (strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0) {
|
|
|
|
if ((parse_url(url, "URL", &urltype, &user, &pass,
|
|
|
|
&host, &port, &path) == -1) ||
|
|
|
|
(user != NULL && *user == '\0') ||
|
|
|
|
(pass != NULL && *pass == '\0') ||
|
|
|
|
EMPTYSTRING(host)) {
|
|
|
|
warnx("Invalid URL `%s'", url);
|
|
|
|
goto cleanup_fetch_ftp;
|
|
|
|
}
|
1999-03-08 07:36:12 +03:00
|
|
|
url_decode(user);
|
|
|
|
url_decode(pass);
|
1999-04-28 17:35:40 +04:00
|
|
|
/*
|
|
|
|
* Note: Don't url_decode(path) here. We need to keep the
|
|
|
|
* distinction between "/" and "%2F" until later.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* check for trailing ';type=[aid]' */
|
1999-07-12 17:20:34 +04:00
|
|
|
if (! EMPTYSTRING(path) && (cp = strrchr(path, ';')) != NULL) {
|
1999-04-28 17:35:40 +04:00
|
|
|
if (strcasecmp(cp, ";type=a") == 0)
|
|
|
|
type = TYPE_A;
|
|
|
|
else if (strcasecmp(cp, ";type=i") == 0)
|
|
|
|
type = TYPE_I;
|
|
|
|
else if (strcasecmp(cp, ";type=d") == 0) {
|
|
|
|
warnx(
|
|
|
|
"Directory listing via a URL is not supported");
|
|
|
|
goto cleanup_fetch_ftp;
|
|
|
|
} else {
|
|
|
|
warnx("Invalid suffix `%s' in URL `%s'", cp,
|
|
|
|
url);
|
|
|
|
goto cleanup_fetch_ftp;
|
|
|
|
}
|
|
|
|
*cp = 0;
|
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
} else { /* classic style `host:file' */
|
1999-04-28 17:35:40 +04:00
|
|
|
urltype = CLASSIC_URL_T;
|
1998-12-29 17:59:04 +03:00
|
|
|
host = xstrdup(url);
|
|
|
|
cp = strchr(host, ':');
|
|
|
|
if (cp != NULL) {
|
|
|
|
*cp = '\0';
|
|
|
|
path = xstrdup(cp + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (EMPTYSTRING(host))
|
|
|
|
goto cleanup_fetch_ftp;
|
|
|
|
|
1999-03-08 07:36:12 +03:00
|
|
|
/* Extract the file and (if present) directory name. */
|
1998-12-29 17:59:04 +03:00
|
|
|
dir = path;
|
|
|
|
if (! EMPTYSTRING(dir)) {
|
1999-04-28 17:35:40 +04:00
|
|
|
/*
|
|
|
|
* If we are dealing with classic `host:path' syntax,
|
|
|
|
* then a path of the form `/file' (resulting from
|
|
|
|
* input of the form `host:/file') means that we should
|
1999-07-12 17:20:34 +04:00
|
|
|
* do "CWD /" before retrieving the file. So we set
|
1999-04-28 17:35:40 +04:00
|
|
|
* dir="/" and file="file".
|
|
|
|
*
|
|
|
|
* But if we are dealing with URLs like
|
|
|
|
* `ftp://host/path' then a path of the form `/file'
|
|
|
|
* (resulting from a URL of the form `ftp://host//file')
|
|
|
|
* means that we should do `CWD ' (with an empty
|
|
|
|
* argument) before retrieving the file. So we set
|
|
|
|
* dir="" and file="file".
|
|
|
|
*
|
|
|
|
* If the path does not contain / at all, we set
|
|
|
|
* dir=NULL. (We get a path without any slashes if
|
|
|
|
* we are dealing with classic `host:file' or URL
|
|
|
|
* `ftp://host/file'.)
|
|
|
|
*
|
|
|
|
* In all other cases, we set dir to a string that does
|
|
|
|
* not include the final '/' that separates the dir part
|
|
|
|
* from the file part of the path. (This will be the
|
|
|
|
* empty string if and only if we are dealing with a
|
|
|
|
* path of the form `/file' resulting from an URL of the
|
|
|
|
* form `ftp://host//file'.)
|
|
|
|
*/
|
1998-12-29 17:59:04 +03:00
|
|
|
cp = strrchr(dir, '/');
|
1999-04-28 17:35:40 +04:00
|
|
|
if (cp == dir && urltype == CLASSIC_URL_T) {
|
1999-03-08 07:36:12 +03:00
|
|
|
file = cp + 1;
|
|
|
|
dir = "/";
|
|
|
|
} else if (cp != NULL) {
|
1998-12-29 17:59:04 +03:00
|
|
|
*cp++ = '\0';
|
|
|
|
file = cp;
|
|
|
|
} else {
|
|
|
|
file = dir;
|
|
|
|
dir = NULL;
|
|
|
|
}
|
1999-07-12 17:20:34 +04:00
|
|
|
} else
|
|
|
|
dir = NULL;
|
1999-04-28 17:35:40 +04:00
|
|
|
if (urltype == FTP_URL_T && file != NULL) {
|
|
|
|
url_decode(file);
|
|
|
|
/* but still don't url_decode(dir) */
|
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout,
|
1999-07-02 12:07:40 +04:00
|
|
|
"fetch_ftp: user `%s' pass `%s' host %s:%s path `%s' dir `%s' file `%s'\n",
|
1999-04-28 17:35:40 +04:00
|
|
|
user ? user : "<null>", pass ? pass : "<null>",
|
1999-07-02 12:07:40 +04:00
|
|
|
host ? host : "<null>", port ? port : "<null>",
|
|
|
|
path ? path : "<null>",
|
1999-04-28 17:35:40 +04:00
|
|
|
dir ? dir : "<null>", file ? file : "<null>");
|
1998-12-29 17:59:04 +03:00
|
|
|
|
|
|
|
dirhasglob = filehasglob = 0;
|
1999-04-28 17:35:40 +04:00
|
|
|
if (doglob && urltype == CLASSIC_URL_T) {
|
1998-12-29 17:59:04 +03:00
|
|
|
if (! EMPTYSTRING(dir) && strpbrk(dir, "*?[]{}") != NULL)
|
|
|
|
dirhasglob = 1;
|
|
|
|
if (! EMPTYSTRING(file) && strpbrk(file, "*?[]{}") != NULL)
|
|
|
|
filehasglob = 1;
|
|
|
|
}
|
|
|
|
|
1999-03-08 07:36:12 +03:00
|
|
|
/* Set up the connection */
|
|
|
|
if (connected)
|
|
|
|
disconnect(0, NULL);
|
|
|
|
xargv[0] = __progname;
|
|
|
|
xargv[1] = host;
|
|
|
|
xargv[2] = NULL;
|
|
|
|
xargc = 2;
|
|
|
|
if (port) {
|
1999-07-02 12:07:40 +04:00
|
|
|
xargv[2] = port;
|
1999-03-08 07:36:12 +03:00
|
|
|
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;
|
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
|
1999-04-28 17:35:40 +04:00
|
|
|
switch (type) {
|
|
|
|
case TYPE_A:
|
|
|
|
setascii(0, NULL);
|
|
|
|
break;
|
|
|
|
case TYPE_I:
|
|
|
|
setbinary(0, NULL);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
errx(1, "fetch_ftp: unknown transfer type %d\n", type);
|
|
|
|
}
|
|
|
|
|
1999-07-12 17:20:34 +04:00
|
|
|
/*
|
|
|
|
* Change directories, if necessary.
|
|
|
|
*
|
|
|
|
* Note: don't use EMPTYSTRING(dir) below, because
|
|
|
|
* dir=="" means something different from dir==NULL.
|
|
|
|
*/
|
1999-04-28 17:35:40 +04:00
|
|
|
if (dir != NULL && !dirhasglob) {
|
|
|
|
char *nextpart;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are dealing with a classic `host:path' (urltype
|
|
|
|
* is CLASSIC_URL_T) then we have a raw directory
|
|
|
|
* name (not encoded in any way) and we can change
|
|
|
|
* directories in one step.
|
|
|
|
*
|
|
|
|
* If we are dealing with an `ftp://host/path' URL
|
|
|
|
* (urltype is FTP_URL_T), then RFC 1738 says we need to
|
|
|
|
* send a separate CWD command for each unescaped "/"
|
|
|
|
* in the path, and we have to interpret %hex escaping
|
|
|
|
* *after* we find the slashes. It's possible to get
|
|
|
|
* empty components here, (from multiple adjacent
|
|
|
|
* slashes in the path) and RFC 1738 says that we should
|
|
|
|
* still do `CWD ' (with a null argument) in such cases.
|
|
|
|
*
|
1999-07-12 17:20:34 +04:00
|
|
|
* Many ftp servers don't support `CWD ', so if there's an
|
|
|
|
* error performing that command, bail out with a descriptive
|
|
|
|
* message.
|
1999-04-28 17:35:40 +04:00
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
1999-07-12 17:20:34 +04:00
|
|
|
* host: dir="", urltype=CLASSIC_URL_T
|
|
|
|
* logged in (to default directory)
|
1999-04-28 17:35:40 +04:00
|
|
|
* host:file dir=NULL, urltype=CLASSIC_URL_T
|
|
|
|
* "RETR file"
|
1999-07-12 17:20:34 +04:00
|
|
|
* host:dir/ dir="dir", urltype=CLASSIC_URL_T
|
|
|
|
* "CWD dir", logged in
|
|
|
|
* ftp://host/ dir="", urltype=FTP_URL_T
|
|
|
|
* logged in (to default directory)
|
|
|
|
* ftp://host/dir/ dir="dir", urltype=FTP_URL_T
|
|
|
|
* "CWD dir", logged in
|
1999-04-28 17:35:40 +04:00
|
|
|
* ftp://host/file dir=NULL, urltype=FTP_URL_T
|
|
|
|
* "RETR file"
|
|
|
|
* ftp://host//file dir="", urltype=FTP_URL_T
|
1999-07-12 17:20:34 +04:00
|
|
|
* "CWD ", "RETR file"
|
1999-04-28 17:35:40 +04:00
|
|
|
* host:/file dir="/", urltype=CLASSIC_URL_T
|
|
|
|
* "CWD /", "RETR file"
|
|
|
|
* ftp://host///file dir="/", urltype=FTP_URL_T
|
1999-07-12 17:20:34 +04:00
|
|
|
* "CWD ", "CWD ", "RETR file"
|
1999-04-28 17:35:40 +04:00
|
|
|
* ftp://host/%2F/file dir="%2F", urltype=FTP_URL_T
|
|
|
|
* "CWD /", "RETR file"
|
|
|
|
* ftp://host/foo/file dir="foo", urltype=FTP_URL_T
|
|
|
|
* "CWD foo", "RETR file"
|
|
|
|
* ftp://host/foo/bar/file dir="foo/bar"
|
|
|
|
* "CWD foo", "CWD bar", "RETR file"
|
|
|
|
* ftp://host//foo/bar/file dir="/foo/bar"
|
1999-07-12 17:20:34 +04:00
|
|
|
* "CWD ", "CWD foo", "CWD bar", "RETR file"
|
1999-04-28 17:35:40 +04:00
|
|
|
* ftp://host/foo//bar/file dir="foo//bar"
|
1999-07-12 17:20:34 +04:00
|
|
|
* "CWD foo", "CWD ", "CWD bar", "RETR file"
|
1999-04-28 17:35:40 +04:00
|
|
|
* ftp://host/%2F/foo/bar/file dir="%2F/foo/bar"
|
|
|
|
* "CWD /", "CWD foo", "CWD bar", "RETR file"
|
|
|
|
* ftp://host/%2Ffoo/bar/file dir="%2Ffoo/bar"
|
|
|
|
* "CWD /foo", "CWD bar", "RETR file"
|
|
|
|
* ftp://host/%2Ffoo%2Fbar/file dir="%2Ffoo%2Fbar"
|
|
|
|
* "CWD /foo/bar", "RETR file"
|
|
|
|
* ftp://host/%2Ffoo%2Fbar%2Ffile dir=NULL
|
|
|
|
* "RETR /foo/bar/file"
|
|
|
|
*
|
|
|
|
* Note that we don't need `dir' after this point.
|
|
|
|
*/
|
|
|
|
do {
|
|
|
|
if (urltype == FTP_URL_T) {
|
|
|
|
nextpart = strchr(dir, '/');
|
|
|
|
if (nextpart) {
|
|
|
|
*nextpart = '\0';
|
|
|
|
nextpart++;
|
|
|
|
}
|
|
|
|
url_decode(dir);
|
|
|
|
} else
|
|
|
|
nextpart = NULL;
|
|
|
|
if (debug)
|
|
|
|
fprintf(ttyout, "dir `%s', nextpart `%s'\n",
|
|
|
|
dir ? dir : "<null>",
|
|
|
|
nextpart ? nextpart : "<null>");
|
1999-07-12 17:20:34 +04:00
|
|
|
if (urltype == FTP_URL_T || *dir != '\0') {
|
1999-04-28 17:35:40 +04:00
|
|
|
xargv[0] = "cd";
|
|
|
|
xargv[1] = dir;
|
|
|
|
xargv[2] = NULL;
|
|
|
|
dirchange = 0;
|
|
|
|
cd(2, xargv);
|
1999-07-12 17:20:34 +04:00
|
|
|
if (! dirchange) {
|
|
|
|
if (*dir == '\0' && code == 500)
|
|
|
|
fprintf(stderr,
|
|
|
|
"\n"
|
|
|
|
"ftp: The `CWD ' command (without a directory), which is required by\n"
|
|
|
|
" RFC 1738 to support the empty directory in the URL pathname (`//'),\n"
|
|
|
|
" conflicts with the server's conformance to RFC 959.\n"
|
|
|
|
" Try the same URL without the `//' in the URL pathname.\n"
|
|
|
|
"\n");
|
1999-04-28 17:35:40 +04:00
|
|
|
goto cleanup_fetch_ftp;
|
1999-07-12 17:20:34 +04:00
|
|
|
}
|
1999-04-28 17:35:40 +04:00
|
|
|
}
|
|
|
|
dir = nextpart;
|
|
|
|
} while (dir != NULL);
|
1998-12-29 17:59:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (EMPTYSTRING(file)) {
|
|
|
|
rval = -1;
|
|
|
|
goto cleanup_fetch_ftp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirhasglob) {
|
|
|
|
snprintf(rempath, sizeof(rempath), "%s/%s", dir, file);
|
|
|
|
file = rempath;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fetch the file(s). */
|
|
|
|
xargc = 2;
|
|
|
|
xargv[0] = "get";
|
|
|
|
xargv[1] = file;
|
|
|
|
xargv[2] = NULL;
|
|
|
|
if (dirhasglob || filehasglob) {
|
|
|
|
int ointeractive;
|
|
|
|
|
|
|
|
ointeractive = interactive;
|
|
|
|
interactive = 0;
|
|
|
|
xargv[0] = "mget";
|
|
|
|
mget(xargc, xargv);
|
|
|
|
interactive = ointeractive;
|
|
|
|
} else {
|
1999-04-28 17:35:40 +04:00
|
|
|
if (outfile == NULL) {
|
|
|
|
cp = strrchr(file, '/'); /* find savefile */
|
|
|
|
if (cp != NULL)
|
|
|
|
outfile = cp + 1;
|
|
|
|
else
|
|
|
|
outfile = file;
|
1998-12-29 17:59:04 +03:00
|
|
|
}
|
1999-04-28 17:35:40 +04:00
|
|
|
xargv[2] = (char *)outfile;
|
|
|
|
xargv[3] = NULL;
|
|
|
|
xargc++;
|
1999-03-22 10:36:40 +03:00
|
|
|
if (restartautofetch)
|
|
|
|
reget(xargc, xargv);
|
|
|
|
else
|
|
|
|
get(xargc, xargv);
|
1998-12-29 17:59:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((code / 100) == COMPLETE)
|
|
|
|
rval = 0;
|
|
|
|
|
|
|
|
cleanup_fetch_ftp:
|
|
|
|
FREEPTR(host);
|
|
|
|
FREEPTR(path);
|
|
|
|
FREEPTR(user);
|
|
|
|
FREEPTR(pass);
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve the given file to outfile.
|
|
|
|
* Supports arguments of the form:
|
|
|
|
* "host:path", "ftp://host/path" if $ftpproxy, call fetch_url() else
|
|
|
|
* call fetch_ftp()
|
1999-03-08 07:36:12 +03:00
|
|
|
* "http://host/path" call fetch_url() to use HTTP
|
1998-12-29 17:59:04 +03:00
|
|
|
* "file:///path" call fetch_url() to copy
|
|
|
|
* "about:..." print a message
|
|
|
|
*
|
|
|
|
* Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
|
|
|
|
* is still open (e.g, ftp xfer with trailing /)
|
|
|
|
*/
|
|
|
|
static int
|
1999-03-22 10:36:40 +03:00
|
|
|
go_fetch(url)
|
1998-12-29 17:59:04 +03:00
|
|
|
const char *url;
|
|
|
|
{
|
|
|
|
|
1999-06-21 02:07:28 +04:00
|
|
|
#ifndef NO_ABOUT
|
1998-12-29 17:59:04 +03:00
|
|
|
/*
|
|
|
|
* Check for about:*
|
|
|
|
*/
|
|
|
|
if (strncasecmp(url, ABOUT_URL, sizeof(ABOUT_URL) - 1) == 0) {
|
|
|
|
url += sizeof(ABOUT_URL) -1;
|
|
|
|
if (strcasecmp(url, "ftp") == 0) {
|
|
|
|
fprintf(ttyout, "%s\n%s\n",
|
|
|
|
"This version of ftp has been enhanced by Luke Mewburn <lukem@netbsd.org>.",
|
1999-09-21 16:57:51 +04:00
|
|
|
"Execute `man ftp' for more details.");
|
1998-12-29 17:59:04 +03:00
|
|
|
} else if (strcasecmp(url, "netbsd") == 0) {
|
|
|
|
fprintf(ttyout, "%s\n%s\n",
|
|
|
|
"NetBSD is a freely available and redistributable UNIX-like operating system.",
|
|
|
|
"For more information, see http://www.netbsd.org/index.html");
|
|
|
|
} else {
|
|
|
|
fprintf(ttyout, "`%s' is an interesting topic.\n", url);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
1999-06-21 02:07:28 +04:00
|
|
|
#endif /* NO_ABOUT */
|
1998-12-29 17:59:04 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for file:// and http:// URLs.
|
|
|
|
*/
|
|
|
|
if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||
|
|
|
|
strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0)
|
1999-03-22 10:36:40 +03:00
|
|
|
return (fetch_url(url, NULL, NULL, NULL));
|
1998-12-29 17:59:04 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try FTP URL-style and host:file arguments next.
|
|
|
|
* If ftpproxy is set with an FTP URL, use fetch_url()
|
|
|
|
* Othewise, use fetch_ftp().
|
|
|
|
*/
|
|
|
|
if (ftpproxy && strncasecmp(url, FTP_URL, sizeof(FTP_URL) - 1) == 0)
|
1999-03-22 10:36:40 +03:00
|
|
|
return (fetch_url(url, NULL, NULL, NULL));
|
1998-12-29 17:59:04 +03:00
|
|
|
|
1999-03-22 10:36:40 +03:00
|
|
|
return (fetch_ftp(url));
|
1998-12-29 17:59:04 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve multiple files from the command line,
|
|
|
|
* calling go_fetch() for each file.
|
|
|
|
*
|
|
|
|
* If an ftp path has a trailing "/", the path will be cd-ed into and
|
1998-12-27 08:49:53 +03:00
|
|
|
* the connection remains open, and the function will return -1
|
|
|
|
* (to indicate the connection is alive).
|
1997-01-19 17:19:02 +03:00
|
|
|
* If an error occurs the return value will be the offset+1 in
|
|
|
|
* argv[] of the file that caused a problem (i.e, argv[x]
|
|
|
|
* returns x+1)
|
|
|
|
* Otherwise, 0 is returned if all files retrieved successfully.
|
|
|
|
*/
|
|
|
|
int
|
1999-03-22 10:36:40 +03:00
|
|
|
auto_fetch(argc, argv)
|
1997-01-19 17:19:02 +03:00
|
|
|
int argc;
|
|
|
|
char *argv[];
|
|
|
|
{
|
1998-12-29 17:59:04 +03:00
|
|
|
volatile int argpos;
|
|
|
|
int rval;
|
1998-06-04 12:28:35 +04:00
|
|
|
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
argpos = 0;
|
1997-01-19 17:19:02 +03:00
|
|
|
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
if (setjmp(toplevel)) {
|
|
|
|
if (connected)
|
|
|
|
disconnect(0, NULL);
|
1997-03-13 09:23:11 +03:00
|
|
|
return (argpos + 1);
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
}
|
1997-03-13 09:23:11 +03:00
|
|
|
(void)signal(SIGINT, (sig_t)intr);
|
|
|
|
(void)signal(SIGPIPE, (sig_t)lostpeer);
|
1997-01-19 17:19:02 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop through as long as there's files to fetch.
|
|
|
|
*/
|
1998-08-03 05:49:25 +04:00
|
|
|
for (rval = 0; (rval == 0) && (argpos < argc); argpos++) {
|
1997-01-19 17:19:02 +03:00
|
|
|
if (strchr(argv[argpos], ':') == NULL)
|
|
|
|
break;
|
1998-12-29 17:59:04 +03:00
|
|
|
redirect_loop = 0;
|
1999-03-08 07:36:12 +03:00
|
|
|
anonftp = 1; /* Handle "automatic" transfers. */
|
1999-03-22 10:36:40 +03:00
|
|
|
rval = go_fetch(argv[argpos]);
|
|
|
|
if (outfile != NULL && strcmp(outfile, "-") != 0
|
|
|
|
&& outfile[0] != '|')
|
|
|
|
outfile = NULL;
|
1998-12-29 17:59:04 +03:00
|
|
|
if (rval > 0)
|
[Yet Another Huge Ftp Commit - hopefully the last for a while,
barring any more little things people want added ...]
New features:
* progressmeter is now asynchronous, so "stalled" transfers can be
detected. "- stalled -" is displayed instead of the ETA in this case.
When the xfer resumes, the time that the xfer was stalled for is
factored out of the ETA. It is debatable whether this is better than
not factoring it out, but I like it this way (I.e, if it stalls for 8
seconds and the ETA was 30 seconds, when it resumes the ETA will still
be 30 seconds).
* verbosity can be disabled on the command line (-V), so that in auto-fetch
mode the only lines displayed will be a description of the file, and
the progress bar (if possible)
* if the screen is resized (and detected via the SIGWINCH signal), the
progress bar will rescale automatically.
Bugs fixed:
* progress bar will not use the last character on the line, as this can
cause problems on some terminals
* screen dimensions (via ioctl(TIOCWINSZ)) should use stdout not stdin
* progressmeter() used some vars before initialising them
* ^D will quit now. [fixes bin/3162]
* use hstrerror() to generate error message for host name lookup failure.
* use getcwd instead of getwd (it should have been OK, but why tempt fate?)
* auto-fetch transfers will always return a positive exit value upon failure
or interruption, relative to the file's position in argv[].
* remote completion of / will work, without putting a leading "///".
This is actually a bug in ftpd(1), where "NLST /" prefixes all names
with "//", but fixing every ftpd(1) is not an option...
1997-02-01 13:44:54 +03:00
|
|
|
rval = argpos + 1;
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
|
1997-01-19 17:19:02 +03:00
|
|
|
if (connected && rval != -1)
|
|
|
|
disconnect(0, NULL);
|
|
|
|
return (rval);
|
|
|
|
}
|