2013-02-23 17:47:36 +04:00
|
|
|
/* $NetBSD: fetch.c,v 1.202 2013/02/23 13:47:36 christos Exp $ */
|
1997-01-19 17:19:02 +03:00
|
|
|
|
|
|
|
/*-
|
2009-04-12 14:18:52 +04:00
|
|
|
* Copyright (c) 1997-2009 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
|
|
|
*
|
2000-05-31 18:23:57 +04:00
|
|
|
* This code is derived from software contributed to The NetBSD Foundation
|
|
|
|
* by Scott Aaron Bamford.
|
|
|
|
*
|
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.
|
|
|
|
*
|
|
|
|
* 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
|
2013-02-23 17:47:36 +04:00
|
|
|
__RCSID("$NetBSD: fetch.c,v 1.202 2013/02/23 13:47:36 christos 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>
|
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>
|
|
|
|
|
2011-12-10 09:53:58 +04:00
|
|
|
#include <assert.h>
|
1997-01-19 17:19:02 +03:00
|
|
|
#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>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
1999-06-24 18:48:35 +04:00
|
|
|
#include <time.h>
|
1997-01-19 17:19:02 +03:00
|
|
|
|
2012-12-21 22:07:36 +04:00
|
|
|
#include "ssl.h"
|
1997-01-19 17:19:02 +03:00
|
|
|
#include "ftp_var.h"
|
1999-12-06 01:54:35 +03:00
|
|
|
#include "version.h"
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
typedef enum {
|
|
|
|
UNKNOWN_URL_T=-1,
|
|
|
|
HTTP_URL_T,
|
2012-12-21 22:07:36 +04:00
|
|
|
#ifdef WITH_SSL
|
|
|
|
HTTPS_URL_T,
|
|
|
|
#endif
|
1998-08-03 05:49:25 +04:00
|
|
|
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;
|
|
|
|
|
2011-09-16 19:39:25 +04:00
|
|
|
__dead static void aborthttp(int);
|
2004-06-06 05:37:41 +04:00
|
|
|
#ifndef NO_AUTH
|
2000-05-01 14:35:16 +04:00
|
|
|
static int auth_url(const char *, char **, const char *, const char *);
|
2004-12-10 09:44:15 +03:00
|
|
|
static void base64_encode(const unsigned char *, size_t, unsigned char *);
|
2004-06-06 05:37:41 +04:00
|
|
|
#endif
|
2000-05-01 14:35:16 +04:00
|
|
|
static int go_fetch(const char *);
|
|
|
|
static int fetch_ftp(const char *);
|
|
|
|
static int fetch_url(const char *, const char *, char *, char *);
|
2004-12-10 09:44:15 +03:00
|
|
|
static const char *match_token(const char **, const char *);
|
2000-05-01 14:35:16 +04:00
|
|
|
static int parse_url(const char *, const char *, url_t *, char **,
|
|
|
|
char **, char **, char **, in_port_t *, char **);
|
|
|
|
static void url_decode(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
|
|
|
|
2004-07-20 16:46:51 +04:00
|
|
|
#define STRNEQUAL(a,b) (strncasecmp((a), (b), sizeof((b))-1) == 0)
|
|
|
|
#define ISLWS(x) ((x)=='\r' || (x)=='\n' || (x)==' ' || (x)=='\t')
|
|
|
|
#define SKIPLWS(x) do { while (ISLWS((*x))) x++; } while (0)
|
|
|
|
|
|
|
|
|
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 */
|
2012-12-21 22:07:36 +04:00
|
|
|
#ifdef WITH_SSL
|
|
|
|
#define HTTPS_URL "https://" /* https URL prefix */
|
1997-01-19 17:19:02 +03:00
|
|
|
|
2012-12-21 22:07:36 +04:00
|
|
|
#define IS_HTTP_TYPE(urltype) \
|
|
|
|
(((urltype) == HTTP_URL_T) || ((urltype) == HTTPS_URL_T))
|
|
|
|
#else
|
|
|
|
#define IS_HTTP_TYPE(urltype) \
|
|
|
|
((urltype) == HTTP_URL_T)
|
|
|
|
#endif
|
1997-01-19 17:19:02 +03:00
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
/*
|
|
|
|
* Determine if token is the next word in buf (case insensitive).
|
|
|
|
* If so, advance buf past the token and any trailing LWS, and
|
|
|
|
* return a pointer to the token (in buf). Otherwise, return NULL.
|
2006-11-25 19:48:31 +03:00
|
|
|
* token may be preceded by LWS.
|
2004-12-10 09:44:15 +03:00
|
|
|
* token must be followed by LWS or NUL. (I.e, don't partial match).
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
match_token(const char **buf, const char *token)
|
|
|
|
{
|
|
|
|
const char *p, *orig;
|
|
|
|
size_t tlen;
|
|
|
|
|
|
|
|
tlen = strlen(token);
|
|
|
|
p = *buf;
|
|
|
|
SKIPLWS(p);
|
|
|
|
orig = p;
|
|
|
|
if (strncasecmp(p, token, tlen) != 0)
|
|
|
|
return NULL;
|
|
|
|
p += tlen;
|
|
|
|
if (*p != '\0' && !ISLWS(*p))
|
|
|
|
return NULL;
|
|
|
|
SKIPLWS(p);
|
|
|
|
orig = *buf;
|
|
|
|
*buf = p;
|
|
|
|
return orig;
|
|
|
|
}
|
|
|
|
|
2004-06-06 05:37:41 +04:00
|
|
|
#ifndef NO_AUTH
|
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
|
2000-05-01 14:35:16 +04:00
|
|
|
auth_url(const char *challenge, char **response, const char *guser,
|
|
|
|
const char *gpass)
|
1999-01-01 13:00:46 +03:00
|
|
|
{
|
2005-06-10 04:18:46 +04:00
|
|
|
const char *cp, *scheme, *errormsg;
|
2004-12-10 09:44:15 +03:00
|
|
|
char *ep, *clear, *realm;
|
2009-04-12 14:18:52 +04:00
|
|
|
char uuser[BUFSIZ], *gotpass;
|
|
|
|
const char *upass;
|
1999-10-01 03:51:26 +04:00
|
|
|
int rval;
|
|
|
|
size_t len, clen, rlen;
|
1999-01-01 13:00:46 +03:00
|
|
|
|
|
|
|
*response = NULL;
|
2004-12-10 09:44:15 +03:00
|
|
|
clear = realm = NULL;
|
1999-01-01 13:00:46 +03:00
|
|
|
rval = -1;
|
2004-12-10 09:44:15 +03:00
|
|
|
cp = challenge;
|
|
|
|
scheme = "Basic"; /* only support Basic authentication */
|
2009-04-12 14:18:52 +04:00
|
|
|
gotpass = NULL;
|
1999-01-01 13:00:46 +03:00
|
|
|
|
2005-06-29 06:31:19 +04:00
|
|
|
DPRINTF("auth_url: challenge `%s'\n", challenge);
|
1999-01-01 13:00:46 +03:00
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
if (! match_token(&cp, scheme)) {
|
2007-04-17 09:52:03 +04:00
|
|
|
warnx("Unsupported authentication challenge `%s'",
|
1999-01-01 13:00:46 +03:00
|
|
|
challenge);
|
|
|
|
goto cleanup_auth_url;
|
|
|
|
}
|
|
|
|
|
1999-10-24 16:31:36 +04:00
|
|
|
#define REALM "realm=\""
|
2004-07-20 16:46:51 +04:00
|
|
|
if (STRNEQUAL(cp, REALM))
|
1999-01-01 13:00:46 +03:00
|
|
|
cp += sizeof(REALM) - 1;
|
|
|
|
else {
|
2007-04-17 09:52:03 +04:00
|
|
|
warnx("Unsupported authentication challenge `%s'",
|
1999-01-01 13:00:46 +03:00
|
|
|
challenge);
|
|
|
|
goto cleanup_auth_url;
|
|
|
|
}
|
2004-12-10 09:44:15 +03:00
|
|
|
/* XXX: need to improve quoted-string parsing to support \ quoting, etc. */
|
1999-01-01 13:00:46 +03:00
|
|
|
if ((ep = strchr(cp, '\"')) != NULL) {
|
2009-04-12 11:07:41 +04:00
|
|
|
len = ep - cp;
|
2006-01-31 23:01:23 +03:00
|
|
|
realm = (char *)ftp_malloc(len + 1);
|
1999-09-28 10:47:38 +04:00
|
|
|
(void)strlcpy(realm, cp, len + 1);
|
1999-01-01 13:00:46 +03:00
|
|
|
} else {
|
2007-04-17 09:52:03 +04:00
|
|
|
warnx("Unsupported authentication challenge `%s'",
|
1999-01-01 13:00:46 +03:00
|
|
|
challenge);
|
|
|
|
goto cleanup_auth_url;
|
|
|
|
}
|
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
fprintf(ttyout, "Username for `%s': ", realm);
|
|
|
|
if (guser != NULL) {
|
2009-04-12 11:07:41 +04:00
|
|
|
(void)strlcpy(uuser, guser, sizeof(uuser));
|
|
|
|
fprintf(ttyout, "%s\n", uuser);
|
2004-12-10 09:44:15 +03:00
|
|
|
} else {
|
1999-05-12 15:16:43 +04:00
|
|
|
(void)fflush(ttyout);
|
2009-07-13 23:05:39 +04:00
|
|
|
if (get_line(stdin, uuser, sizeof(uuser), &errormsg) < 0) {
|
2005-06-10 04:18:46 +04:00
|
|
|
warnx("%s; can't authenticate", errormsg);
|
1999-05-12 15:16:43 +04:00
|
|
|
goto cleanup_auth_url;
|
1999-10-12 10:04:59 +04:00
|
|
|
}
|
1999-05-12 15:16:43 +04:00
|
|
|
}
|
|
|
|
if (gpass != NULL)
|
2009-04-12 14:18:52 +04:00
|
|
|
upass = gpass;
|
2007-04-11 04:52:38 +04:00
|
|
|
else {
|
2009-04-12 14:18:52 +04:00
|
|
|
gotpass = getpass("Password: ");
|
|
|
|
if (gotpass == NULL) {
|
2007-04-11 04:52:38 +04:00
|
|
|
warnx("Can't read password");
|
|
|
|
goto cleanup_auth_url;
|
|
|
|
}
|
2009-04-12 14:18:52 +04:00
|
|
|
upass = gotpass;
|
2007-04-11 04:52:38 +04:00
|
|
|
}
|
1999-01-01 13:00:46 +03:00
|
|
|
|
2009-04-12 14:18:52 +04:00
|
|
|
clen = strlen(uuser) + strlen(upass) + 2; /* user + ":" + pass + "\0" */
|
2006-01-31 23:01:23 +03:00
|
|
|
clear = (char *)ftp_malloc(clen);
|
2009-04-12 11:07:41 +04:00
|
|
|
(void)strlcpy(clear, uuser, clen);
|
1999-09-28 10:47:38 +04:00
|
|
|
(void)strlcat(clear, ":", clen);
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcat(clear, upass, clen);
|
|
|
|
if (gotpass)
|
|
|
|
memset(gotpass, 0, strlen(gotpass));
|
1999-01-01 13:00:46 +03:00
|
|
|
|
1999-08-01 16:22:23 +04:00
|
|
|
/* scheme + " " + enc + "\0" */
|
1999-09-24 10:57:37 +04:00
|
|
|
rlen = strlen(scheme) + 1 + (clen + 2) * 4 / 3 + 1;
|
2006-01-31 23:01:23 +03:00
|
|
|
*response = (char *)ftp_malloc(rlen);
|
1999-09-28 10:47:38 +04:00
|
|
|
(void)strlcpy(*response, scheme, rlen);
|
1999-09-22 07:01:53 +04:00
|
|
|
len = strlcat(*response, " ", rlen);
|
2004-08-08 17:52:04 +04:00
|
|
|
/* use `clen - 1' to not encode the trailing NUL */
|
2005-05-14 19:26:43 +04:00
|
|
|
base64_encode((unsigned char *)clear, clen - 1,
|
|
|
|
(unsigned char *)*response + len);
|
1999-09-29 04:44:01 +04:00
|
|
|
memset(clear, 0, clen);
|
1999-01-01 13:00:46 +03:00
|
|
|
rval = 0;
|
|
|
|
|
2000-07-18 10:49:21 +04:00
|
|
|
cleanup_auth_url:
|
1999-01-01 13:00:46 +03:00
|
|
|
FREEPTR(clear);
|
|
|
|
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.
|
|
|
|
*/
|
2000-08-28 16:06:11 +04:00
|
|
|
static void
|
2004-12-10 09:44:15 +03:00
|
|
|
base64_encode(const unsigned char *clear, size_t len, unsigned char *encoded)
|
1999-01-01 13:00:46 +03:00
|
|
|
{
|
2004-12-10 09:44:15 +03:00
|
|
|
static const unsigned char enc[] =
|
1999-01-01 13:00:46 +03:00
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
2004-12-10 09:44:15 +03:00
|
|
|
unsigned char *cp;
|
2009-04-12 14:18:52 +04:00
|
|
|
size_t i;
|
1999-01-01 13:00:46 +03:00
|
|
|
|
|
|
|
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) = '=';
|
|
|
|
}
|
2004-06-06 05:37:41 +04:00
|
|
|
#endif
|
1999-01-01 13:00:46 +03:00
|
|
|
|
1999-03-08 07:36:12 +03:00
|
|
|
/*
|
|
|
|
* Decode %xx escapes in given string, `in-place'.
|
|
|
|
*/
|
|
|
|
static void
|
2000-05-01 14:35:16 +04:00
|
|
|
url_decode(char *url)
|
1999-03-08 07:36:12 +03:00
|
|
|
{
|
|
|
|
unsigned char *p, *q;
|
|
|
|
|
|
|
|
if (EMPTYSTRING(url))
|
|
|
|
return;
|
1999-09-24 18:28:14 +04:00
|
|
|
p = q = (unsigned char *)url;
|
1999-03-08 07:36:12 +03:00
|
|
|
|
1999-10-24 16:31:36 +04:00
|
|
|
#define HEXTOINT(x) (x - (isdigit(x) ? '0' : (islower(x) ? 'a' : 'A') - 10))
|
1999-03-08 07:36:12 +03:00
|
|
|
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
|
|
|
/*
|
2010-03-05 10:41:10 +03:00
|
|
|
* Parse URL of form (per RFC 3986):
|
2003-12-04 15:51:18 +03: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
|
|
|
*
|
2010-03-05 10:41:10 +03:00
|
|
|
* XXX: this is not totally RFC 3986 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
|
2007-05-16 03:54:18 +04:00
|
|
|
* for file:// and http:// URLs. ftp:// URLs have the `/' between the
|
2003-05-14 18:30:59 +04:00
|
|
|
* host and the URL-path removed, but any additional leading slashes
|
|
|
|
* in the URL-path are retained (because they imply that we should
|
1999-04-28 17:35:40 +04:00
|
|
|
* later do "CWD" with a null argument).
|
|
|
|
*
|
|
|
|
* Examples:
|
2003-05-14 18:30:59 +04:00
|
|
|
* input URL output path
|
1999-04-28 17:35:40 +04:00
|
|
|
* --------- -----------
|
2007-05-16 03:54:18 +04:00
|
|
|
* "http://host" "/"
|
|
|
|
* "http://host/" "/"
|
|
|
|
* "http://host/path" "/path"
|
1999-07-12 17:20:34 +04:00
|
|
|
* "file://host/dir/file" "dir/file"
|
2007-05-16 03:54:18 +04:00
|
|
|
* "ftp://host" ""
|
1999-07-12 17:20:34 +04:00
|
|
|
* "ftp://host/" ""
|
2007-05-16 03:54:18 +04:00
|
|
|
* "ftp://host//" "/"
|
|
|
|
* "ftp://host/dir/file" "dir/file"
|
1999-04-28 17:35:40 +04:00
|
|
|
* "ftp://host//dir/file" "/dir/file"
|
1998-08-03 05:49:25 +04:00
|
|
|
*/
|
|
|
|
static int
|
2009-04-12 11:07:41 +04:00
|
|
|
parse_url(const char *url, const char *desc, url_t *utype,
|
|
|
|
char **uuser, char **pass, char **host, char **port,
|
2000-05-01 14:35:16 +04:00
|
|
|
in_port_t *portnum, char **path)
|
1998-08-03 05:49:25 +04:00
|
|
|
{
|
2009-04-12 14:18:52 +04:00
|
|
|
const char *origurl, *tport;
|
|
|
|
char *cp, *ep, *thost;
|
1999-10-01 03:51:26 +04:00
|
|
|
size_t len;
|
1998-08-03 05:49:25 +04:00
|
|
|
|
2009-04-12 11:07:41 +04:00
|
|
|
if (url == NULL || desc == NULL || utype == NULL || uuser == NULL
|
1999-10-01 03:51:26 +04:00
|
|
|
|| pass == NULL || host == NULL || port == NULL || portnum == NULL
|
|
|
|
|| path == NULL)
|
1998-08-03 05:49:25 +04:00
|
|
|
errx(1, "parse_url: invoked with NULL argument!");
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("parse_url: %s `%s'\n", desc, url);
|
1998-08-03 05:49:25 +04:00
|
|
|
|
1999-10-01 03:51:26 +04:00
|
|
|
origurl = url;
|
2009-04-12 11:07:41 +04:00
|
|
|
*utype = UNKNOWN_URL_T;
|
|
|
|
*uuser = *pass = *host = *port = *path = NULL;
|
1999-10-01 03:51:26 +04:00
|
|
|
*portnum = 0;
|
1999-07-12 17:20:34 +04:00
|
|
|
tport = NULL;
|
1998-08-03 05:49:25 +04:00
|
|
|
|
2004-07-20 16:46:51 +04:00
|
|
|
if (STRNEQUAL(url, HTTP_URL)) {
|
1998-08-03 05:49:25 +04:00
|
|
|
url += sizeof(HTTP_URL) - 1;
|
2009-04-12 11:07:41 +04:00
|
|
|
*utype = HTTP_URL_T;
|
1999-10-01 03:51:26 +04:00
|
|
|
*portnum = HTTP_PORT;
|
1999-07-12 17:20:34 +04:00
|
|
|
tport = httpport;
|
2004-07-20 16:46:51 +04:00
|
|
|
} else if (STRNEQUAL(url, FTP_URL)) {
|
1998-08-03 05:49:25 +04:00
|
|
|
url += sizeof(FTP_URL) - 1;
|
2009-04-12 11:07:41 +04:00
|
|
|
*utype = FTP_URL_T;
|
1999-10-01 03:51:26 +04:00
|
|
|
*portnum = FTP_PORT;
|
1999-07-12 17:20:34 +04:00
|
|
|
tport = ftpport;
|
2004-07-20 16:46:51 +04:00
|
|
|
} else if (STRNEQUAL(url, FILE_URL)) {
|
1998-08-03 05:49:25 +04:00
|
|
|
url += sizeof(FILE_URL) - 1;
|
2009-04-12 11:07:41 +04:00
|
|
|
*utype = FILE_URL_T;
|
2012-12-21 22:07:36 +04:00
|
|
|
#ifdef WITH_SSL
|
|
|
|
} else if (STRNEQUAL(url, HTTPS_URL)) {
|
|
|
|
url += sizeof(HTTPS_URL) - 1;
|
|
|
|
*utype = HTTPS_URL_T;
|
|
|
|
*portnum = HTTPS_PORT;
|
|
|
|
tport = httpsport;
|
|
|
|
#endif
|
1998-08-03 05:49:25 +04:00
|
|
|
} else {
|
|
|
|
warnx("Invalid %s `%s'", desc, url);
|
2000-07-18 10:49:21 +04:00
|
|
|
cleanup_parse_url:
|
2009-04-12 11:07:41 +04:00
|
|
|
FREEPTR(*uuser);
|
2005-06-10 04:18:46 +04:00
|
|
|
if (*pass != NULL)
|
|
|
|
memset(*pass, 0, strlen(*pass));
|
1998-08-03 05:49:25 +04:00
|
|
|
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)
|
2006-01-31 23:01:23 +03:00
|
|
|
thost = ftp_strdup(url);
|
1998-08-03 05:49:25 +04:00
|
|
|
else {
|
1999-03-08 07:36:12 +03:00
|
|
|
len = ep - url;
|
2006-01-31 23:01:23 +03:00
|
|
|
thost = (char *)ftp_malloc(len + 1);
|
1999-09-28 10:47:38 +04:00
|
|
|
(void)strlcpy(thost, url, len + 1);
|
2009-04-12 11:07:41 +04:00
|
|
|
if (*utype == FTP_URL_T) /* skip first / for ftp URLs */
|
1999-04-28 17:35:40 +04:00
|
|
|
ep++;
|
2006-01-31 23:01:23 +03:00
|
|
|
*path = ftp_strdup(ep);
|
1998-08-03 05:49:25 +04:00
|
|
|
}
|
|
|
|
|
2009-08-17 13:08:16 +04:00
|
|
|
cp = strchr(thost, '@'); /* look for user[:pass]@ in URLs */
|
1999-05-12 15:16:43 +04:00
|
|
|
if (cp != NULL) {
|
2009-04-12 11:07:41 +04:00
|
|
|
if (*utype == FTP_URL_T)
|
1999-05-12 15:16:43 +04:00
|
|
|
anonftp = 0; /* disable anonftp */
|
2009-04-12 11:07:41 +04:00
|
|
|
*uuser = thost;
|
1998-08-03 05:49:25 +04:00
|
|
|
*cp = '\0';
|
2006-01-31 23:01:23 +03:00
|
|
|
thost = ftp_strdup(cp + 1);
|
2009-04-12 11:07:41 +04:00
|
|
|
cp = strchr(*uuser, ':');
|
1998-08-03 05:49:25 +04:00
|
|
|
if (cp != NULL) {
|
|
|
|
*cp = '\0';
|
2006-01-31 23:01:23 +03:00
|
|
|
*pass = ftp_strdup(cp + 1);
|
1998-08-03 05:49:25 +04:00
|
|
|
}
|
2009-04-12 11:07:41 +04:00
|
|
|
url_decode(*uuser);
|
2004-12-10 09:44:15 +03:00
|
|
|
if (*pass)
|
|
|
|
url_decode(*pass);
|
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
|
2010-03-05 10:41:10 +03:00
|
|
|
* RFC 3986:
|
1999-07-12 17:20:34 +04:00
|
|
|
* `[' ipv6-address ']'
|
|
|
|
*/
|
|
|
|
if (*thost == '[') {
|
|
|
|
cp = thost + 1;
|
|
|
|
if ((ep = strchr(cp, ']')) == NULL ||
|
2000-03-10 01:01:26 +03:00
|
|
|
(ep[1] != '\0' && ep[1] != ':')) {
|
1999-07-12 17:20:34 +04:00
|
|
|
warnx("Invalid address `%s' in %s `%s'",
|
1999-10-01 03:51:26 +04:00
|
|
|
thost, desc, origurl);
|
1999-07-12 17:20:34 +04:00
|
|
|
goto cleanup_parse_url;
|
|
|
|
}
|
2000-01-25 10:13:45 +03:00
|
|
|
len = ep - cp; /* change `[xyz]' -> `xyz' */
|
1999-07-12 17:20:34 +04:00
|
|
|
memmove(thost, thost + 1, len);
|
|
|
|
thost[len] = '\0';
|
|
|
|
if (! isipv6addr(thost)) {
|
|
|
|
warnx("Invalid IPv6 address `%s' in %s `%s'",
|
1999-10-01 03:51:26 +04:00
|
|
|
thost, desc, origurl);
|
1999-07-12 17:20:34 +04:00
|
|
|
goto cleanup_parse_url;
|
|
|
|
}
|
|
|
|
cp = ep + 1;
|
|
|
|
if (*cp == ':')
|
|
|
|
cp++;
|
|
|
|
else
|
|
|
|
cp = NULL;
|
|
|
|
} else
|
|
|
|
#endif /* INET6 */
|
2007-05-16 03:54:18 +04:00
|
|
|
if ((cp = strchr(thost, ':')) != NULL)
|
2008-04-22 16:59:33 +04:00
|
|
|
*cp++ = '\0';
|
1999-07-12 17:20:34 +04:00
|
|
|
*host = thost;
|
|
|
|
|
1998-08-03 05:49:25 +04:00
|
|
|
/* look for [:port] */
|
|
|
|
if (cp != NULL) {
|
2008-04-22 16:59:33 +04:00
|
|
|
unsigned long nport;
|
1998-08-03 05:49:25 +04:00
|
|
|
|
2008-04-22 16:59:33 +04:00
|
|
|
nport = strtoul(cp, &ep, 10);
|
|
|
|
if (*cp == '\0' || *ep != '\0' ||
|
|
|
|
nport < 1 || nport > MAX_IN_PORT_T) {
|
2000-08-06 12:51:22 +04:00
|
|
|
warnx("Unknown port `%s' in %s `%s'",
|
|
|
|
cp, desc, origurl);
|
1998-08-03 05:49:25 +04:00
|
|
|
goto cleanup_parse_url;
|
|
|
|
}
|
1999-10-01 03:51:26 +04:00
|
|
|
*portnum = nport;
|
1999-07-12 17:20:34 +04:00
|
|
|
tport = cp;
|
1998-08-03 05:49:25 +04:00
|
|
|
}
|
1999-10-01 03:51:26 +04:00
|
|
|
|
1999-11-10 10:34:41 +03:00
|
|
|
if (tport != NULL)
|
2006-01-31 23:01:23 +03:00
|
|
|
*port = ftp_strdup(tport);
|
2007-05-16 03:54:18 +04:00
|
|
|
if (*path == NULL) {
|
|
|
|
const char *emptypath = "/";
|
2009-04-12 11:07:41 +04:00
|
|
|
if (*utype == FTP_URL_T) /* skip first / for ftp URLs */
|
2007-05-16 03:54:18 +04:00
|
|
|
emptypath++;
|
|
|
|
*path = ftp_strdup(emptypath);
|
|
|
|
}
|
1998-08-03 05:49:25 +04:00
|
|
|
|
2005-06-29 06:31:19 +04:00
|
|
|
DPRINTF("parse_url: user `%s' pass `%s' host %s port %s(%d) "
|
|
|
|
"path `%s'\n",
|
2009-04-12 11:07:41 +04:00
|
|
|
STRorNULL(*uuser), STRorNULL(*pass),
|
2007-12-05 06:46:33 +03:00
|
|
|
STRorNULL(*host), STRorNULL(*port),
|
|
|
|
*portnum ? *portnum : -1, STRorNULL(*path));
|
1998-08-03 05:49:25 +04:00
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1999-10-11 02:33:54 +04:00
|
|
|
sigjmp_buf httpabort;
|
[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-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
|
2012-12-22 20:57:09 +04:00
|
|
|
* http_proxy/https_proxy as appropriate.
|
1999-03-08 07:36:12 +03:00
|
|
|
* Supports HTTP redirects.
|
2001-10-15 09:05:43 +04:00
|
|
|
* Returns 1 on failure, 0 on completed xfer, -1 if ftp connection
|
1998-12-27 08:49:53 +03:00
|
|
|
* 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
|
2000-05-01 14:35:16 +04:00
|
|
|
fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
|
1998-12-29 17:59:04 +03:00
|
|
|
{
|
1999-12-03 09:10:01 +03:00
|
|
|
struct addrinfo hints, *res, *res0 = NULL;
|
1999-08-30 02:21:57 +04:00
|
|
|
int error;
|
2006-12-13 21:04:08 +03:00
|
|
|
sigfunc volatile oldintr;
|
|
|
|
sigfunc volatile oldintp;
|
|
|
|
int volatile s;
|
1999-11-10 10:34:41 +03:00
|
|
|
struct stat sb;
|
2006-12-13 21:04:08 +03:00
|
|
|
int volatile ischunked;
|
|
|
|
int volatile isproxy;
|
|
|
|
int volatile rval;
|
|
|
|
int volatile hcode;
|
2009-04-12 14:18:52 +04:00
|
|
|
int len;
|
|
|
|
size_t flen;
|
1999-09-22 11:18:31 +04:00
|
|
|
static size_t bufsize;
|
|
|
|
static char *xferbuf;
|
2004-12-10 09:44:15 +03:00
|
|
|
const char *cp, *token;
|
2006-12-13 21:04:08 +03:00
|
|
|
char *ep;
|
2007-05-10 16:22:04 +04:00
|
|
|
char buf[FTPBUFLEN];
|
|
|
|
const char *errormsg;
|
2006-12-13 21:04:08 +03:00
|
|
|
char *volatile savefile;
|
|
|
|
char *volatile auth;
|
|
|
|
char *volatile location;
|
|
|
|
char *volatile message;
|
2009-04-12 11:07:41 +04:00
|
|
|
char *uuser, *pass, *host, *port, *path;
|
2006-12-13 21:04:08 +03:00
|
|
|
char *volatile decodedpath;
|
2003-07-31 09:23:59 +04:00
|
|
|
char *puser, *ppass, *useragent;
|
1999-11-10 10:34:41 +03:00
|
|
|
off_t hashbytes, rangestart, rangeend, entitylen;
|
2006-12-13 21:04:08 +03:00
|
|
|
int (*volatile closefunc)(FILE *);
|
2012-12-21 22:07:36 +04:00
|
|
|
FETCH *volatile fin;
|
2006-12-13 21:04:08 +03:00
|
|
|
FILE *volatile fout;
|
1998-12-29 17:59:04 +03:00
|
|
|
time_t mtime;
|
|
|
|
url_t urltype;
|
1999-07-02 12:07:40 +04:00
|
|
|
in_port_t portnum;
|
2012-12-21 22:07:36 +04:00
|
|
|
#ifdef WITH_SSL
|
|
|
|
void *ssl;
|
|
|
|
#endif
|
1997-01-19 17:19:02 +03:00
|
|
|
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: `%s' proxyenv `%s'\n", url, STRorNULL(proxyenv));
|
|
|
|
|
1999-10-06 02:12:34 +04:00
|
|
|
oldintr = oldintp = NULL;
|
1998-06-04 12:28:35 +04:00
|
|
|
closefunc = NULL;
|
2012-12-21 22:07:36 +04:00
|
|
|
fin = NULL;
|
|
|
|
fout = NULL;
|
1997-01-19 17:19:02 +03:00
|
|
|
s = -1;
|
2007-05-10 16:22:04 +04:00
|
|
|
savefile = NULL;
|
1999-01-01 13:00:46 +03:00
|
|
|
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;
|
2009-04-12 11:07:41 +04:00
|
|
|
uuser = pass = host = path = decodedpath = puser = ppass = NULL;
|
1997-01-19 17:19:02 +03:00
|
|
|
|
2009-04-12 11:07:41 +04:00
|
|
|
if (parse_url(url, "URL", &urltype, &uuser, &pass, &host, &port,
|
1999-10-01 03:51:26 +04:00
|
|
|
&portnum, &path) == -1)
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
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;
|
|
|
|
}
|
2012-12-21 22:07:36 +04:00
|
|
|
if (!IS_HTTP_TYPE(urltype) || outfile == NULL) {
|
1998-08-03 05:49:25 +04:00
|
|
|
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
|
|
|
|
2006-01-31 23:01:23 +03:00
|
|
|
decodedpath = ftp_strdup(path);
|
1999-03-08 07:36:12 +03:00
|
|
|
url_decode(decodedpath);
|
|
|
|
|
1998-06-04 12:28:35 +04:00
|
|
|
if (outfile)
|
2006-01-31 23:01:23 +03:00
|
|
|
savefile = ftp_strdup(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)
|
2006-01-31 23:01:23 +03:00
|
|
|
savefile = ftp_strdup(cp + 1);
|
1998-06-04 12:28:35 +04:00
|
|
|
else
|
2006-01-31 23:01:23 +03:00
|
|
|
savefile = ftp_strdup(decodedpath);
|
1998-06-04 12:28:35 +04:00
|
|
|
}
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: savefile `%s'\n", savefile);
|
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;
|
|
|
|
}
|
2007-04-17 09:52:03 +04:00
|
|
|
warnx("No file after directory (you must specify an "
|
2003-03-07 11:13:48 +03:00
|
|
|
"output file) `%s'", url);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1997-05-23 22:42:36 +04:00
|
|
|
}
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1999-11-10 10:34:41 +03:00
|
|
|
restart_point = 0;
|
1998-07-26 16:58:16 +04:00
|
|
|
filesize = -1;
|
1999-11-10 10:34:41 +03:00
|
|
|
rangestart = rangeend = entitylen = -1;
|
1998-07-26 16:58:16 +04:00
|
|
|
mtime = -1;
|
1999-11-10 10:34:41 +03:00
|
|
|
if (restartautofetch) {
|
|
|
|
if (strcmp(savefile, "-") != 0 && *savefile != '|' &&
|
|
|
|
stat(savefile, &sb) == 0)
|
|
|
|
restart_point = sb.st_size;
|
|
|
|
}
|
1998-07-26 16:58:16 +04:00
|
|
|
if (urltype == FILE_URL_T) { /* file:// URLs */
|
|
|
|
direction = "copied";
|
2012-12-21 22:07:36 +04:00
|
|
|
fin = fetch_open(decodedpath, "r");
|
1998-07-26 16:58:16 +04:00
|
|
|
if (fin == NULL) {
|
2007-04-17 09:52:03 +04:00
|
|
|
warn("Can't open `%s'", decodedpath);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1997-04-05 07:27:32 +04:00
|
|
|
}
|
2012-12-21 22:07:36 +04:00
|
|
|
if (fstat(fetch_fileno(fin), &sb) == 0) {
|
1998-07-26 16:58:16 +04:00
|
|
|
mtime = sb.st_mtime;
|
|
|
|
filesize = sb.st_size;
|
|
|
|
}
|
1999-11-10 10:34:41 +03:00
|
|
|
if (restart_point) {
|
2012-12-21 22:07:36 +04:00
|
|
|
if (lseek(fetch_fileno(fin), restart_point, SEEK_SET) < 0) {
|
2007-04-17 09:52:03 +04:00
|
|
|
warn("Can't seek to restart `%s'",
|
1999-11-10 10:34:41 +03:00
|
|
|
decodedpath);
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (verbose) {
|
|
|
|
fprintf(ttyout, "Copying %s", decodedpath);
|
|
|
|
if (restart_point)
|
2000-08-02 02:47:25 +04:00
|
|
|
fprintf(ttyout, " (restarting at " LLF ")",
|
|
|
|
(LLT)restart_point);
|
1999-11-10 10:34:41 +03:00
|
|
|
fputs("\n", ttyout);
|
|
|
|
}
|
2012-12-21 22:07:36 +04:00
|
|
|
if (0 == rcvbuf_size) {
|
|
|
|
rcvbuf_size = 8 * 1024; /* XXX */
|
|
|
|
}
|
1998-07-26 16:58:16 +04:00
|
|
|
} else { /* ftp:// or http:// URLs */
|
2009-04-12 14:18:52 +04:00
|
|
|
const char *leading;
|
1999-08-22 16:49:00 +04:00
|
|
|
int hasleading;
|
|
|
|
|
1998-12-29 17:59:04 +03:00
|
|
|
if (proxyenv == NULL) {
|
2012-12-22 20:58:51 +04:00
|
|
|
#ifdef WITH_SSL
|
2012-12-22 20:57:09 +04:00
|
|
|
if (urltype == HTTPS_URL_T)
|
|
|
|
proxyenv = getoptionvalue("https_proxy");
|
2012-12-22 20:58:51 +04:00
|
|
|
#endif
|
2012-12-22 20:57:09 +04:00
|
|
|
if (proxyenv == NULL && IS_HTTP_TYPE(urltype))
|
1999-10-24 16:31:36 +04:00
|
|
|
proxyenv = getoptionvalue("http_proxy");
|
1998-12-29 17:59:04 +03:00
|
|
|
else if (urltype == FTP_URL_T)
|
1999-10-24 16:31:36 +04:00
|
|
|
proxyenv = getoptionvalue("ftp_proxy");
|
1998-12-29 17:59:04 +03:00
|
|
|
}
|
1998-07-26 16:58:16 +04:00
|
|
|
direction = "retrieved";
|
1999-10-24 16:31:36 +04:00
|
|
|
if (! EMPTYSTRING(proxyenv)) { /* 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-10-24 16:31:36 +04:00
|
|
|
char *pport, *no_proxy;
|
2008-04-22 16:59:33 +04:00
|
|
|
in_port_t pportnum;
|
1998-08-03 05:49:25 +04:00
|
|
|
|
|
|
|
isproxy = 1;
|
|
|
|
|
|
|
|
/* check URL against list of no_proxied sites */
|
1999-10-24 16:31:36 +04:00
|
|
|
no_proxy = getoptionvalue("no_proxy");
|
|
|
|
if (! EMPTYSTRING(no_proxy)) {
|
2006-09-23 02:29:25 +04:00
|
|
|
char *np, *np_copy, *np_iter;
|
2008-04-22 16:59:33 +04:00
|
|
|
unsigned long np_port;
|
1998-08-03 05:49:25 +04:00
|
|
|
size_t hlen, plen;
|
|
|
|
|
2006-09-23 02:29:25 +04:00
|
|
|
np_iter = np_copy = ftp_strdup(no_proxy);
|
1998-08-03 05:49:25 +04:00
|
|
|
hlen = strlen(host);
|
2006-09-23 02:29:25 +04:00
|
|
|
while ((cp = strsep(&np_iter, " ,")) != NULL) {
|
1998-08-03 05:49:25 +04:00
|
|
|
if (*cp == '\0')
|
|
|
|
continue;
|
1999-07-02 12:07:40 +04:00
|
|
|
if ((np = strrchr(cp, ':')) != NULL) {
|
2008-04-22 16:59:33 +04:00
|
|
|
*np++ = '\0';
|
|
|
|
np_port = strtoul(np, &ep, 10);
|
|
|
|
if (*np == '\0' || *ep != '\0')
|
1998-08-03 05:49:25 +04:00
|
|
|
continue;
|
1999-10-01 03:51:26 +04:00
|
|
|
if (np_port != portnum)
|
1998-08-03 05:49:25 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
plen = strlen(cp);
|
2000-04-13 12:17:56 +04:00
|
|
|
if (hlen < plen)
|
|
|
|
continue;
|
1998-08-03 05:49:25 +04:00
|
|
|
if (strncasecmp(host + hlen - plen,
|
|
|
|
cp, plen) == 0) {
|
|
|
|
isproxy = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FREEPTR(np_copy);
|
2001-10-15 09:05:43 +04:00
|
|
|
if (isproxy == 0 && urltype == FTP_URL_T) {
|
|
|
|
rval = fetch_ftp(url);
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
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) {
|
2007-06-05 04:31:20 +04:00
|
|
|
if (restart_point) {
|
|
|
|
warnx("Can't restart via proxy URL `%s'",
|
|
|
|
proxyenv);
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1998-08-03 05:49:25 +04:00
|
|
|
if (parse_url(proxyenv, "proxy URL", &purltype,
|
2008-04-22 16:59:33 +04:00
|
|
|
&puser, &ppass, &phost, &pport, &pportnum,
|
1999-10-01 03:51:26 +04:00
|
|
|
&ppath) == -1)
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1997-01-19 17:19:02 +03:00
|
|
|
|
2012-12-21 22:07:36 +04:00
|
|
|
if ((!IS_HTTP_TYPE(purltype)
|
1998-08-03 05:49:25 +04:00
|
|
|
&& 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
|
|
|
}
|
2000-05-25 19:35:51 +04:00
|
|
|
if (isipv6addr(host) &&
|
|
|
|
strchr(host, '%') != NULL) {
|
|
|
|
warnx(
|
|
|
|
"Scoped address notation `%s' disallowed via web proxy",
|
|
|
|
host);
|
|
|
|
FREEPTR(phost);
|
|
|
|
FREEPTR(pport);
|
|
|
|
FREEPTR(ppath);
|
|
|
|
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);
|
2006-01-31 23:01:23 +03:00
|
|
|
path = ftp_strdup(url);
|
1999-05-12 15:16:43 +04:00
|
|
|
FREEPTR(ppath);
|
2012-12-21 22:07:36 +04:00
|
|
|
urltype = purltype;
|
1998-08-03 05:49:25 +04:00
|
|
|
}
|
1999-10-24 16:31:36 +04:00
|
|
|
} /* ! EMPTYSTRING(proxyenv) */
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1999-07-02 12:07:40 +04:00
|
|
|
memset(&hints, 0, sizeof(hints));
|
1999-08-22 16:49:00 +04:00
|
|
|
hints.ai_flags = 0;
|
2001-12-23 15:23:01 +03:00
|
|
|
hints.ai_family = family;
|
1999-07-02 12:07:40 +04:00
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_protocol = 0;
|
2008-04-22 16:59:33 +04:00
|
|
|
error = getaddrinfo(host, port, &hints, &res0);
|
1999-07-02 12:07:40 +04:00
|
|
|
if (error) {
|
2012-02-24 23:40:49 +04:00
|
|
|
warnx("Can't LOOKUP `%s:%s': %s", host, port,
|
2007-04-17 09:52:03 +04:00
|
|
|
(error == EAI_SYSTEM) ? strerror(errno)
|
|
|
|
: gai_strerror(error));
|
1999-07-02 12:07:40 +04:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1999-12-03 09:10:01 +03:00
|
|
|
if (res0->ai_canonname)
|
|
|
|
host = res0->ai_canonname;
|
1999-07-02 12:07:40 +04:00
|
|
|
|
1999-12-03 09:10:01 +03:00
|
|
|
s = -1;
|
2012-12-21 22:07:36 +04:00
|
|
|
#ifdef WITH_SSL
|
|
|
|
ssl = NULL;
|
|
|
|
#endif
|
1999-12-03 09:10:01 +03:00
|
|
|
for (res = res0; res; res = res->ai_next) {
|
2008-04-22 16:59:33 +04:00
|
|
|
char hname[NI_MAXHOST], sname[NI_MAXSERV];
|
|
|
|
|
2000-05-29 18:57:27 +04:00
|
|
|
ai_unmapped(res);
|
1999-12-03 09:10:01 +03:00
|
|
|
if (getnameinfo(res->ai_addr, res->ai_addrlen,
|
2008-04-22 16:59:33 +04:00
|
|
|
hname, sizeof(hname), sname, sizeof(sname),
|
|
|
|
NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
|
|
|
|
strlcpy(hname, "?", sizeof(hname));
|
|
|
|
strlcpy(sname, "?", sizeof(sname));
|
|
|
|
}
|
1999-12-03 09:10:01 +03:00
|
|
|
|
2005-06-01 16:10:14 +04:00
|
|
|
if (verbose && res0->ai_next) {
|
2008-04-22 16:59:33 +04:00
|
|
|
fprintf(ttyout, "Trying %s:%s ...\n",
|
|
|
|
hname, sname);
|
2005-06-01 16:10:14 +04:00
|
|
|
}
|
1999-12-03 09:10:01 +03:00
|
|
|
|
2000-09-28 16:29:23 +04:00
|
|
|
s = socket(res->ai_family, SOCK_STREAM,
|
|
|
|
res->ai_protocol);
|
1999-07-02 12:07:40 +04:00
|
|
|
if (s < 0) {
|
2007-04-17 09:52:03 +04:00
|
|
|
warn(
|
2008-04-22 16:59:33 +04:00
|
|
|
"Can't create socket for connection to "
|
|
|
|
"`%s:%s'", hname, sname);
|
1999-12-03 09:10:01 +03:00
|
|
|
continue;
|
1999-07-02 12:07:40 +04:00
|
|
|
}
|
|
|
|
|
2012-07-04 10:09:37 +04:00
|
|
|
if (ftp_connect(s, res->ai_addr, res->ai_addrlen,
|
|
|
|
verbose || !res->ai_next) < 0) {
|
1999-07-02 12:07:40 +04:00
|
|
|
close(s);
|
1999-12-03 09:10:01 +03:00
|
|
|
s = -1;
|
|
|
|
continue;
|
1999-07-02 12:07:40 +04:00
|
|
|
}
|
1999-12-03 09:10:01 +03:00
|
|
|
|
2012-12-21 22:07:36 +04:00
|
|
|
#ifdef WITH_SSL
|
|
|
|
if (urltype == HTTPS_URL_T) {
|
|
|
|
if ((ssl = fetch_start_ssl(s)) == NULL) {
|
|
|
|
close(s);
|
|
|
|
s = -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-12-03 09:10:01 +03:00
|
|
|
/* success */
|
1999-07-02 12:07:40 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1999-12-03 09:10:01 +03:00
|
|
|
if (s < 0) {
|
2008-04-22 16:59:33 +04:00
|
|
|
warnx("Can't connect to `%s:%s'", host, port);
|
1999-12-03 09:10:01 +03:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1997-01-19 17:19:02 +03:00
|
|
|
|
2012-12-21 22:07:36 +04:00
|
|
|
fin = fetch_fdopen(s, "r+");
|
|
|
|
fetch_set_ssl(fin, ssl);
|
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
/*
|
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++;
|
|
|
|
}
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "GET %s HTTP/1.0\r\n", path);
|
1999-01-23 18:46:24 +03:00
|
|
|
if (flushcache)
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "Pragma: no-cache\r\n");
|
1998-08-03 05:49:25 +04:00
|
|
|
} else {
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "GET %s HTTP/1.1\r\n", path);
|
2000-03-10 01:01:26 +03:00
|
|
|
if (strchr(host, ':')) {
|
2000-05-25 19:35:51 +04:00
|
|
|
char *h, *p;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* strip off IPv6 scope identifier, since it is
|
|
|
|
* local to the node
|
|
|
|
*/
|
2006-01-31 23:01:23 +03:00
|
|
|
h = ftp_strdup(host);
|
2000-05-25 19:35:51 +04:00
|
|
|
if (isipv6addr(h) &&
|
|
|
|
(p = strchr(h, '%')) != NULL) {
|
|
|
|
*p = '\0';
|
|
|
|
}
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "Host: [%s]", h);
|
2000-05-25 19:35:51 +04:00
|
|
|
free(h);
|
2000-03-10 01:01:26 +03:00
|
|
|
} else
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "Host: %s", host);
|
|
|
|
#ifdef WITH_SSL
|
|
|
|
if ((urltype == HTTP_URL_T && portnum != HTTP_PORT) ||
|
|
|
|
(urltype == HTTPS_URL_T && portnum != HTTPS_PORT))
|
|
|
|
#else
|
2002-05-06 18:36:41 +04:00
|
|
|
if (portnum != HTTP_PORT)
|
2012-12-21 22:07:36 +04:00
|
|
|
#endif
|
|
|
|
fetch_printf(fin, ":%u", portnum);
|
|
|
|
fetch_printf(fin, "\r\n");
|
|
|
|
fetch_printf(fin, "Accept: */*\r\n");
|
|
|
|
fetch_printf(fin, "Connection: close\r\n");
|
1999-11-10 10:34:41 +03:00
|
|
|
if (restart_point) {
|
|
|
|
fputs(leading, ttyout);
|
2013-02-23 17:47:36 +04:00
|
|
|
fetch_printf(fin, "Range: bytes=" LLF "-\r\n",
|
2000-08-02 02:47:25 +04:00
|
|
|
(LLT)restart_point);
|
|
|
|
fprintf(ttyout, "restarting at " LLF,
|
|
|
|
(LLT)restart_point);
|
1999-11-10 10:34:41 +03:00
|
|
|
leading = ", ";
|
|
|
|
hasleading++;
|
|
|
|
}
|
1999-01-23 18:46:24 +03:00
|
|
|
if (flushcache)
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "Cache-Control: no-cache\r\n");
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
2003-07-31 09:23:59 +04:00
|
|
|
if ((useragent=getenv("FTPUSERAGENT")) != NULL) {
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "User-Agent: %s\r\n", useragent);
|
2003-07-31 09:23:59 +04:00
|
|
|
} else {
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "User-Agent: %s/%s\r\n",
|
2003-07-31 09:23:59 +04:00
|
|
|
FTP_PRODUCT, FTP_VERSION);
|
|
|
|
}
|
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++;
|
|
|
|
}
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "Authorization: %s\r\n", wwwauth);
|
1999-01-01 13:00:46 +03:00
|
|
|
}
|
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++;
|
|
|
|
}
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(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);
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_printf(fin, "\r\n");
|
|
|
|
if (fetch_flush(fin) == EOF) {
|
1998-07-26 16:58:16 +04:00
|
|
|
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 */
|
2012-12-21 22:07:36 +04:00
|
|
|
len = fetch_getline(fin, buf, sizeof(buf), &errormsg);
|
2007-05-10 16:22:04 +04:00
|
|
|
if (len < 0) {
|
|
|
|
if (*errormsg == '\n')
|
|
|
|
errormsg++;
|
|
|
|
warnx("Receiving HTTP reply: %s", errormsg);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-22 20:06:27 +04:00
|
|
|
}
|
2004-07-20 16:46:51 +04:00
|
|
|
while (len > 0 && (ISLWS(buf[len-1])))
|
1998-07-22 20:06:27 +04:00
|
|
|
buf[--len] = '\0';
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: 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;
|
2006-01-31 23:01:23 +03:00
|
|
|
message = ftp_strdup(cp);
|
1998-07-26 16:58:16 +04:00
|
|
|
|
|
|
|
/* Read the rest of the header. */
|
|
|
|
while (1) {
|
2012-12-21 22:07:36 +04:00
|
|
|
len = fetch_getline(fin, buf, sizeof(buf), &errormsg);
|
2007-05-10 16:22:04 +04:00
|
|
|
if (len < 0) {
|
|
|
|
if (*errormsg == '\n')
|
|
|
|
errormsg++;
|
|
|
|
warnx("Receiving HTTP reply: %s", errormsg);
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
2004-07-20 16:46:51 +04:00
|
|
|
while (len > 0 && (ISLWS(buf[len-1])))
|
1998-07-26 16:58:16 +04:00
|
|
|
buf[--len] = '\0';
|
|
|
|
if (len == 0)
|
|
|
|
break;
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: received `%s'\n", buf);
|
1998-07-26 16:58:16 +04:00
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
/*
|
|
|
|
* Look for some headers
|
|
|
|
*/
|
|
|
|
|
1998-07-26 16:58:16 +04:00
|
|
|
cp = buf;
|
1998-12-29 17:59:04 +03:00
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
if (match_token(&cp, "Content-Length:")) {
|
2000-07-30 08:42:37 +04:00
|
|
|
filesize = STRTOLL(cp, &ep, 10);
|
1999-11-10 10:34:41 +03:00
|
|
|
if (filesize < 0 || *ep != '\0')
|
1998-07-26 16:58:16 +04:00
|
|
|
goto improper;
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: parsed len as: " LLF "\n",
|
2005-06-29 06:31:19 +04:00
|
|
|
(LLT)filesize);
|
1998-12-29 17:59:04 +03:00
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
} else if (match_token(&cp, "Content-Range:")) {
|
|
|
|
if (! match_token(&cp, "bytes"))
|
2004-07-20 16:46:51 +04:00
|
|
|
goto improper;
|
2004-12-10 09:44:15 +03:00
|
|
|
|
|
|
|
if (*cp == '*')
|
|
|
|
cp++;
|
2001-11-25 14:24:45 +03:00
|
|
|
else {
|
|
|
|
rangestart = STRTOLL(cp, &ep, 10);
|
|
|
|
if (rangestart < 0 || *ep != '-')
|
|
|
|
goto improper;
|
|
|
|
cp = ep + 1;
|
|
|
|
rangeend = STRTOLL(cp, &ep, 10);
|
|
|
|
if (rangeend < 0 || rangeend < rangestart)
|
|
|
|
goto improper;
|
2004-12-10 09:44:15 +03:00
|
|
|
cp = ep;
|
2001-11-25 14:24:45 +03:00
|
|
|
}
|
2004-12-10 09:44:15 +03:00
|
|
|
if (*cp != '/')
|
1999-11-10 10:34:41 +03:00
|
|
|
goto improper;
|
2004-12-10 09:44:15 +03:00
|
|
|
cp++;
|
|
|
|
if (*cp == '*')
|
|
|
|
cp++;
|
2001-11-25 14:24:45 +03:00
|
|
|
else {
|
|
|
|
entitylen = STRTOLL(cp, &ep, 10);
|
|
|
|
if (entitylen < 0)
|
|
|
|
goto improper;
|
2004-12-10 09:44:15 +03:00
|
|
|
cp = ep;
|
2001-11-25 14:24:45 +03:00
|
|
|
}
|
2004-12-10 09:44:15 +03:00
|
|
|
if (*cp != '\0')
|
1999-11-10 10:34:41 +03:00
|
|
|
goto improper;
|
|
|
|
|
2005-06-29 06:31:19 +04:00
|
|
|
#ifndef NO_DEBUG
|
2006-01-31 23:05:35 +03:00
|
|
|
if (ftp_debug) {
|
2001-11-25 14:24:45 +03:00
|
|
|
fprintf(ttyout, "parsed range as: ");
|
|
|
|
if (rangestart == -1)
|
|
|
|
fprintf(ttyout, "*");
|
|
|
|
else
|
|
|
|
fprintf(ttyout, LLF "-" LLF,
|
|
|
|
(LLT)rangestart,
|
|
|
|
(LLT)rangeend);
|
|
|
|
fprintf(ttyout, "/" LLF "\n", (LLT)entitylen);
|
|
|
|
}
|
2005-06-29 06:31:19 +04:00
|
|
|
#endif
|
1999-11-10 10:34:41 +03:00
|
|
|
if (! restart_point) {
|
|
|
|
warnx(
|
|
|
|
"Received unexpected Content-Range header");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
} else if (match_token(&cp, "Last-Modified:")) {
|
1998-07-26 16:58:16 +04:00
|
|
|
struct tm parsed;
|
2010-03-05 00:40:53 +03:00
|
|
|
const char *t;
|
1998-07-26 16:58:16 +04:00
|
|
|
|
2007-05-22 09:16:48 +04:00
|
|
|
memset(&parsed, 0, sizeof(parsed));
|
2010-03-05 00:40:53 +03:00
|
|
|
t = parse_rfc2616time(&parsed, cp);
|
|
|
|
if (t != NULL) {
|
1998-11-13 01:27:17 +03:00
|
|
|
parsed.tm_isdst = -1;
|
1998-07-26 16:58:16 +04:00
|
|
|
if (*t == '\0')
|
1999-09-26 06:00:12 +04:00
|
|
|
mtime = timegm(&parsed);
|
2005-06-29 06:31:19 +04:00
|
|
|
#ifndef NO_DEBUG
|
2006-01-31 23:05:35 +03:00
|
|
|
if (ftp_debug && mtime != -1) {
|
1998-07-26 16:58:16 +04:00
|
|
|
fprintf(ttyout,
|
2010-03-05 00:40:53 +03:00
|
|
|
"parsed time as: %s",
|
2007-05-24 09:05:18 +04:00
|
|
|
rfc2822time(localtime(&mtime)));
|
1998-11-13 01:27:17 +03:00
|
|
|
}
|
2005-06-29 06:31:19 +04:00
|
|
|
#endif
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
} else if (match_token(&cp, "Location:")) {
|
2006-01-31 23:01:23 +03:00
|
|
|
location = ftp_strdup(cp);
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: parsed location as `%s'\n",
|
|
|
|
cp);
|
1999-01-01 13:00:46 +03:00
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
} else if (match_token(&cp, "Transfer-Encoding:")) {
|
|
|
|
if (match_token(&cp, "binary")) {
|
2000-04-13 12:17:56 +04:00
|
|
|
warnx(
|
2007-04-17 09:52:03 +04:00
|
|
|
"Bogus transfer encoding `binary' (fetching anyway)");
|
2000-04-13 12:17:56 +04:00
|
|
|
continue;
|
|
|
|
}
|
2004-12-10 09:44:15 +03:00
|
|
|
if (! (token = match_token(&cp, "chunked"))) {
|
1999-01-01 16:26:31 +03:00
|
|
|
warnx(
|
2007-04-17 09:52:03 +04:00
|
|
|
"Unsupported transfer encoding `%s'",
|
2004-12-10 09:44:15 +03:00
|
|
|
token);
|
1999-01-01 16:26:31 +03:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
ischunked++;
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: using chunked encoding\n");
|
1999-01-01 16:26:31 +03:00
|
|
|
|
2004-12-10 09:44:15 +03:00
|
|
|
} else if (match_token(&cp, "Proxy-Authenticate:")
|
|
|
|
|| match_token(&cp, "WWW-Authenticate:")) {
|
|
|
|
if (! (token = match_token(&cp, "Basic"))) {
|
2005-06-29 06:31:19 +04:00
|
|
|
DPRINTF(
|
2007-12-05 06:46:33 +03:00
|
|
|
"fetch_url: skipping unknown auth scheme `%s'\n",
|
2004-12-10 09:44:15 +03:00
|
|
|
token);
|
|
|
|
continue;
|
|
|
|
}
|
1999-01-01 13:00:46 +03:00
|
|
|
FREEPTR(auth);
|
2006-01-31 23:01:23 +03:00
|
|
|
auth = ftp_strdup(token);
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: parsed 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 */
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1999-03-22 10:36:40 +03:00
|
|
|
switch (hcode) {
|
|
|
|
case 200:
|
|
|
|
break;
|
1999-11-10 10:34:41 +03:00
|
|
|
case 206:
|
|
|
|
if (! restart_point) {
|
|
|
|
warnx("Not expecting partial content header");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
break;
|
1999-03-22 10:36:40 +03:00
|
|
|
case 300:
|
|
|
|
case 301:
|
|
|
|
case 302:
|
|
|
|
case 303:
|
|
|
|
case 305:
|
2006-01-02 15:30:01 +03:00
|
|
|
case 307:
|
1999-03-22 10:36:40 +03:00
|
|
|
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;
|
2004-06-06 05:37:41 +04:00
|
|
|
#ifndef NO_AUTH
|
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
|
|
|
|
1999-05-12 15:16:43 +04:00
|
|
|
if (hcode == 401) {
|
|
|
|
authp = &wwwauth;
|
2009-04-12 11:07:41 +04:00
|
|
|
auser = uuser;
|
1999-05-12 15:16:43 +04:00
|
|
|
apass = pass;
|
|
|
|
} else {
|
|
|
|
authp = &proxyauth;
|
|
|
|
auser = puser;
|
|
|
|
apass = ppass;
|
|
|
|
}
|
2004-07-20 15:22:27 +04:00
|
|
|
if (verbose || *authp == NULL ||
|
|
|
|
auser == NULL || apass == NULL)
|
|
|
|
fprintf(ttyout, "%s\n", message);
|
|
|
|
if (EMPTYSTRING(auth)) {
|
|
|
|
warnx(
|
|
|
|
"No authentication challenge provided by server");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1999-03-22 10:36:40 +03:00
|
|
|
if (*authp != NULL) {
|
|
|
|
char reply[10];
|
|
|
|
|
|
|
|
fprintf(ttyout,
|
|
|
|
"Authorization failed. Retry (y/n)? ");
|
2009-07-13 23:05:39 +04:00
|
|
|
if (get_line(stdin, reply, sizeof(reply), NULL)
|
2005-06-10 04:18:46 +04:00
|
|
|
< 0) {
|
1999-03-22 10:36:40 +03:00
|
|
|
goto cleanup_fetch_url;
|
1999-10-12 10:04:59 +04:00
|
|
|
}
|
2004-10-30 21:29:47 +04:00
|
|
|
if (tolower((unsigned char)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);
|
1999-09-29 04:44:01 +04:00
|
|
|
memset(*authp, 0, strlen(*authp));
|
1999-03-22 10:36:40 +03:00
|
|
|
FREEPTR(*authp);
|
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1999-03-22 10:36:40 +03:00
|
|
|
}
|
2004-06-06 05:37:41 +04:00
|
|
|
#endif
|
1999-03-22 10:36:40 +03:00
|
|
|
default:
|
|
|
|
if (message)
|
2007-04-17 09:52:03 +04:00
|
|
|
warnx("Error retrieving file `%s'", message);
|
1999-03-22 10:36:40 +03:00
|
|
|
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
|
|
|
/* Open the output file. */
|
|
|
|
if (strcmp(savefile, "-") == 0) {
|
|
|
|
fout = stdout;
|
|
|
|
} else if (*savefile == '|') {
|
1999-09-28 03:09:42 +04:00
|
|
|
oldintp = xsignal(SIGPIPE, SIG_IGN);
|
1998-06-04 12:28:35 +04:00
|
|
|
fout = popen(savefile + 1, "w");
|
|
|
|
if (fout == NULL) {
|
2007-04-17 09:52:03 +04:00
|
|
|
warn("Can't execute `%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 {
|
2001-11-25 14:41:09 +03:00
|
|
|
if ((rangeend != -1 && rangeend <= restart_point) ||
|
|
|
|
(rangestart == -1 && filesize != -1 && filesize <= restart_point)) {
|
|
|
|
/* already done */
|
|
|
|
if (verbose)
|
|
|
|
fprintf(ttyout, "already done\n");
|
|
|
|
rval = 0;
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
if (restart_point && rangestart != -1) {
|
1999-11-10 10:34:41 +03:00
|
|
|
if (entitylen != -1)
|
|
|
|
filesize = entitylen;
|
2001-11-25 14:41:09 +03:00
|
|
|
if (rangestart != restart_point) {
|
1999-11-10 10:34:41 +03:00
|
|
|
warnx(
|
|
|
|
"Size of `%s' differs from save file `%s'",
|
|
|
|
url, savefile);
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
fout = fopen(savefile, "a");
|
|
|
|
} else
|
|
|
|
fout = fopen(savefile, "w");
|
1998-06-04 12:28:35 +04:00
|
|
|
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 */
|
1999-10-09 07:00:55 +04:00
|
|
|
if (sigsetjmp(httpabort, 1))
|
1998-12-29 17:59:04 +03:00
|
|
|
goto cleanup_fetch_url;
|
1999-10-06 02:12:34 +04:00
|
|
|
(void)xsignal(SIGQUIT, psummary);
|
1999-09-28 03:09:42 +04:00
|
|
|
oldintr = xsignal(SIGINT, aborthttp);
|
[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
|
|
|
|
2011-12-10 09:53:58 +04:00
|
|
|
assert(rcvbuf_size > 0);
|
2009-04-12 14:18:52 +04:00
|
|
|
if ((size_t)rcvbuf_size > bufsize) {
|
1999-09-22 11:18:31 +04:00
|
|
|
if (xferbuf)
|
|
|
|
(void)free(xferbuf);
|
|
|
|
bufsize = rcvbuf_size;
|
2006-01-31 23:01:23 +03:00
|
|
|
xferbuf = ftp_malloc(bufsize);
|
1999-09-22 11:18:31 +04:00
|
|
|
}
|
|
|
|
|
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
|
|
|
do {
|
1999-09-28 03:09:42 +04:00
|
|
|
long chunksize;
|
2007-08-22 10:51:41 +04:00
|
|
|
short lastchunk;
|
1999-01-01 16:26:31 +03:00
|
|
|
|
|
|
|
chunksize = 0;
|
2007-08-22 10:51:41 +04:00
|
|
|
lastchunk = 0;
|
|
|
|
/* read chunk-size */
|
1999-01-01 16:26:31 +03:00
|
|
|
if (ischunked) {
|
2012-12-21 22:07:36 +04:00
|
|
|
if (fetch_getln(xferbuf, bufsize, fin) == NULL) {
|
2007-08-22 10:51:41 +04:00
|
|
|
warnx("Unexpected EOF reading chunk-size");
|
1999-01-01 16:26:31 +03:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
2007-08-22 10:51:41 +04:00
|
|
|
errno = 0;
|
1999-09-22 11:18:31 +04:00
|
|
|
chunksize = strtol(xferbuf, &ep, 16);
|
2007-08-22 10:51:41 +04:00
|
|
|
if (ep == xferbuf) {
|
|
|
|
warnx("Invalid chunk-size");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
|
|
|
if (errno == ERANGE || chunksize < 0) {
|
|
|
|
errno = ERANGE;
|
|
|
|
warn("Chunk-size `%.*s'",
|
2007-08-23 03:47:13 +04:00
|
|
|
(int)(ep-xferbuf), xferbuf);
|
2007-08-22 10:51:41 +04:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
2000-01-25 10:13:45 +03:00
|
|
|
|
|
|
|
/*
|
2000-08-27 10:39:25 +04:00
|
|
|
* XXX: Work around bug in Apache 1.3.9 and
|
|
|
|
* 1.3.11, which incorrectly put trailing
|
2007-08-22 10:51:41 +04:00
|
|
|
* space after the chunk-size.
|
2000-01-25 10:13:45 +03:00
|
|
|
*/
|
2000-08-27 10:39:25 +04:00
|
|
|
while (*ep == ' ')
|
2000-01-25 10:13:45 +03:00
|
|
|
ep++;
|
|
|
|
|
2007-08-22 10:51:41 +04:00
|
|
|
/* skip [ chunk-ext ] */
|
|
|
|
if (*ep == ';') {
|
|
|
|
while (*ep && *ep != '\r')
|
|
|
|
ep++;
|
|
|
|
}
|
|
|
|
|
1999-01-01 16:26:31 +03:00
|
|
|
if (strcmp(ep, "\r\n") != 0) {
|
2007-08-22 10:51:41 +04:00
|
|
|
warnx("Unexpected data following chunk-size");
|
1999-01-01 16:26:31 +03:00
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_url: got chunk-size of " LLF "\n",
|
|
|
|
(LLT)chunksize);
|
2007-08-22 10:51:41 +04:00
|
|
|
if (chunksize == 0) {
|
|
|
|
lastchunk = 1;
|
|
|
|
goto chunkdone;
|
|
|
|
}
|
1999-01-01 16:26:31 +03:00
|
|
|
}
|
[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;
|
|
|
|
|
1999-09-21 17:17:22 +04:00
|
|
|
if (rate_get)
|
|
|
|
(void)gettimeofday(&then, NULL);
|
2009-04-12 14:18:52 +04:00
|
|
|
bufrem = rate_get ? rate_get : (off_t)bufsize;
|
1999-12-11 03:56:13 +03:00
|
|
|
if (ischunked)
|
|
|
|
bufrem = MIN(chunksize, bufrem);
|
[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
|
|
|
while (bufrem > 0) {
|
2012-12-21 22:07:36 +04:00
|
|
|
flen = fetch_read(xferbuf, sizeof(char),
|
2009-04-12 14:18:52 +04:00
|
|
|
MIN((off_t)bufsize, bufrem), fin);
|
|
|
|
if (flen <= 0)
|
[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
|
|
|
goto chunkdone;
|
2009-04-12 14:18:52 +04:00
|
|
|
bytes += flen;
|
|
|
|
bufrem -= flen;
|
|
|
|
if (fwrite(xferbuf, sizeof(char), flen, fout)
|
|
|
|
!= flen) {
|
[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
|
|
|
warn("Writing `%s'", savefile);
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1999-12-11 03:56:13 +03:00
|
|
|
if (hash && !progress) {
|
|
|
|
while (bytes >= hashbytes) {
|
|
|
|
(void)putc('#', ttyout);
|
|
|
|
hashbytes += mark;
|
|
|
|
}
|
|
|
|
(void)fflush(ttyout);
|
|
|
|
}
|
|
|
|
if (ischunked) {
|
2009-04-12 14:18:52 +04:00
|
|
|
chunksize -= flen;
|
1999-12-11 03:56:13 +03:00
|
|
|
if (chunksize <= 0)
|
|
|
|
break;
|
1999-01-01 16:26:31 +03:00
|
|
|
}
|
[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 (rate_get) {
|
|
|
|
while (1) {
|
|
|
|
(void)gettimeofday(&now, NULL);
|
|
|
|
timersub(&now, &then, &td);
|
|
|
|
if (td.tv_sec > 0)
|
|
|
|
break;
|
|
|
|
usleep(1000000 - td.tv_usec);
|
|
|
|
}
|
|
|
|
}
|
1999-12-11 03:56:13 +03:00
|
|
|
if (ischunked && chunksize <= 0)
|
|
|
|
break;
|
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) {
|
2012-12-21 22:07:36 +04:00
|
|
|
if (fetch_getln(xferbuf, bufsize, fin) == NULL) {
|
2007-08-22 10:51:41 +04:00
|
|
|
warnx("Unexpected EOF reading chunk CRLF");
|
|
|
|
goto cleanup_fetch_url;
|
|
|
|
}
|
1999-09-22 11:18:31 +04:00
|
|
|
if (strcmp(xferbuf, "\r\n") != 0) {
|
1999-01-01 16:26:31 +03:00
|
|
|
warnx("Unexpected data following chunk");
|
|
|
|
goto cleanup_fetch_url;
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
2007-08-22 10:51:41 +04:00
|
|
|
if (lastchunk)
|
|
|
|
break;
|
1997-01-19 17:19:02 +03:00
|
|
|
}
|
1999-01-01 16:26:31 +03:00
|
|
|
} while (ischunked);
|
2007-08-22 10:51:41 +04:00
|
|
|
|
|
|
|
/* XXX: deal with optional trailer & CRLF here? */
|
|
|
|
|
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
|
|
|
}
|
2012-12-21 22:07:36 +04:00
|
|
|
if (fetch_error(fin)) {
|
1998-07-26 16:58:16 +04:00
|
|
|
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);
|
|
|
|
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",
|
2007-05-24 09:05:18 +04:00
|
|
|
rfc2822time(localtime(&mtime)));
|
1998-07-26 16:58:16 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bytes > 0)
|
|
|
|
ptransfer(0);
|
2002-06-05 14:20:46 +04:00
|
|
|
bytes = 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
|
|
|
|
2000-07-18 10:49:21 +04:00
|
|
|
improper:
|
2008-04-22 16:59:33 +04:00
|
|
|
warnx("Improper response from `%s:%s'", host, port);
|
1997-06-29 10:34:50 +04:00
|
|
|
|
2000-07-18 10:49:21 +04:00
|
|
|
cleanup_fetch_url:
|
1999-10-06 02:12:34 +04:00
|
|
|
if (oldintr)
|
|
|
|
(void)xsignal(SIGINT, oldintr);
|
|
|
|
if (oldintp)
|
|
|
|
(void)xsignal(SIGPIPE, oldintp);
|
1998-07-22 20:06:27 +04:00
|
|
|
if (fin != NULL)
|
2012-12-21 22:07:36 +04:00
|
|
|
fetch_close(fin);
|
1998-07-22 20:06:27 +04:00
|
|
|
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);
|
2005-04-10 07:13:23 +04:00
|
|
|
if (res0)
|
|
|
|
freeaddrinfo(res0);
|
1998-08-04 07:35:24 +04:00
|
|
|
FREEPTR(savefile);
|
2009-04-12 11:07:41 +04:00
|
|
|
FREEPTR(uuser);
|
2005-06-10 04:18:46 +04:00
|
|
|
if (pass != NULL)
|
|
|
|
memset(pass, 0, strlen(pass));
|
1998-08-03 05:49:25 +04:00
|
|
|
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);
|
2005-06-10 04:18:46 +04:00
|
|
|
if (ppass != NULL)
|
|
|
|
memset(ppass, 0, strlen(ppass));
|
1999-05-12 15:16:43 +04:00
|
|
|
FREEPTR(ppass);
|
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
|
|
|
*/
|
2011-09-16 19:39:25 +04:00
|
|
|
static void
|
2000-05-01 14:35:16 +04:00
|
|
|
aborthttp(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
|
|
|
{
|
1999-10-09 07:00:55 +04:00
|
|
|
char msgbuf[100];
|
2005-05-19 07:05:04 +04:00
|
|
|
size_t len;
|
[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
|
|
|
|
2004-07-20 14:40:21 +04:00
|
|
|
sigint_raised = 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
|
|
|
alarmtimer(0);
|
1999-10-09 07:00:55 +04:00
|
|
|
len = strlcpy(msgbuf, "\nHTTP fetch aborted.\n", sizeof(msgbuf));
|
|
|
|
write(fileno(ttyout), msgbuf, len);
|
|
|
|
siglongjmp(httpabort, 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-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
|
2000-05-01 14:35:16 +04:00
|
|
|
fetch_ftp(const char *url)
|
1998-12-29 17:59:04 +03:00
|
|
|
{
|
|
|
|
char *cp, *xargv[5], rempath[MAXPATHLEN];
|
2009-04-12 11:07:41 +04:00
|
|
|
char *host, *path, *dir, *file, *uuser, *pass;
|
1999-07-02 12:07:40 +04:00
|
|
|
char *port;
|
2009-04-12 14:18:52 +04:00
|
|
|
char cmdbuf[MAXPATHLEN];
|
|
|
|
char dirbuf[4];
|
2009-04-12 11:07:41 +04:00
|
|
|
int dirhasglob, filehasglob, rval, transtype, xargc;
|
2005-05-29 09:56:56 +04:00
|
|
|
int oanonftp, oautologin;
|
1999-10-01 03:51:26 +04:00
|
|
|
in_port_t portnum;
|
|
|
|
url_t urltype;
|
1998-12-29 17:59:04 +03:00
|
|
|
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_ftp: `%s'\n", url);
|
2009-04-12 11:07:41 +04:00
|
|
|
host = path = dir = file = uuser = pass = NULL;
|
1999-07-02 12:07:40 +04:00
|
|
|
port = NULL;
|
1998-12-29 17:59:04 +03:00
|
|
|
rval = 1;
|
2009-04-12 11:07:41 +04:00
|
|
|
transtype = TYPE_I;
|
1998-12-29 17:59:04 +03:00
|
|
|
|
2004-07-20 16:46:51 +04:00
|
|
|
if (STRNEQUAL(url, FTP_URL)) {
|
2009-04-12 11:07:41 +04:00
|
|
|
if ((parse_url(url, "URL", &urltype, &uuser, &pass,
|
1999-10-01 03:51:26 +04:00
|
|
|
&host, &port, &portnum, &path) == -1) ||
|
2009-04-12 11:07:41 +04:00
|
|
|
(uuser != NULL && *uuser == '\0') ||
|
1998-12-29 17:59:04 +03:00
|
|
|
EMPTYSTRING(host)) {
|
|
|
|
warnx("Invalid URL `%s'", url);
|
|
|
|
goto cleanup_fetch_ftp;
|
|
|
|
}
|
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)
|
2009-04-12 11:07:41 +04:00
|
|
|
transtype = TYPE_A;
|
1999-04-28 17:35:40 +04:00
|
|
|
else if (strcasecmp(cp, ";type=i") == 0)
|
2009-04-12 11:07:41 +04:00
|
|
|
transtype = TYPE_I;
|
1999-04-28 17:35:40 +04:00
|
|
|
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;
|
|
|
|
}
|
1999-11-27 00:41:55 +03:00
|
|
|
} else { /* classic style `[user@]host:[file]' */
|
1999-04-28 17:35:40 +04:00
|
|
|
urltype = CLASSIC_URL_T;
|
2006-01-31 23:01:23 +03:00
|
|
|
host = ftp_strdup(url);
|
1999-11-27 00:41:55 +03:00
|
|
|
cp = strchr(host, '@');
|
|
|
|
if (cp != NULL) {
|
|
|
|
*cp = '\0';
|
2009-04-12 11:07:41 +04:00
|
|
|
uuser = host;
|
1999-11-27 00:41:55 +03:00
|
|
|
anonftp = 0; /* disable anonftp */
|
2006-01-31 23:01:23 +03:00
|
|
|
host = ftp_strdup(cp + 1);
|
1999-11-27 00:41:55 +03:00
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
cp = strchr(host, ':');
|
|
|
|
if (cp != NULL) {
|
|
|
|
*cp = '\0';
|
2006-01-31 23:01:23 +03:00
|
|
|
path = ftp_strdup(cp + 1);
|
1998-12-29 17:59:04 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
|
|
/*
|
1999-11-27 00:41:55 +03:00
|
|
|
* If we are dealing with classic `[user@]host:[path]' syntax,
|
|
|
|
* then a path of the form `/file' (resulting from input of the
|
|
|
|
* form `host:/file') means that we should do "CWD /" before
|
|
|
|
* retrieving the file. So we set dir="/" and file="file".
|
1999-04-28 17:35:40 +04:00
|
|
|
*
|
1999-11-27 00:41:55 +03:00
|
|
|
* 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
|
1999-04-28 17:35:40 +04:00
|
|
|
* dir="" and file="file".
|
|
|
|
*
|
1999-11-27 00:41:55 +03:00
|
|
|
* 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 `[user@]host:[file]' or URL `ftp://host/file'.)
|
1999-04-28 17:35:40 +04:00
|
|
|
*
|
1999-11-27 00:41:55 +03:00
|
|
|
* 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'.)
|
1999-04-28 17:35:40 +04:00
|
|
|
*/
|
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;
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcpy(dirbuf, "/", sizeof(dirbuf));
|
|
|
|
dir = dirbuf;
|
1999-03-08 07:36:12 +03:00
|
|
|
} 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) {
|
2005-04-11 05:49:31 +04:00
|
|
|
url_decode(file);
|
1999-04-28 17:35:40 +04:00
|
|
|
/* but still don't url_decode(dir) */
|
|
|
|
}
|
2005-06-29 06:31:19 +04:00
|
|
|
DPRINTF("fetch_ftp: user `%s' pass `%s' host %s port %s "
|
|
|
|
"path `%s' dir `%s' file `%s'\n",
|
2009-04-12 11:07:41 +04:00
|
|
|
STRorNULL(uuser), STRorNULL(pass),
|
2007-12-05 06:46:33 +03:00
|
|
|
STRorNULL(host), STRorNULL(port),
|
|
|
|
STRorNULL(path), STRorNULL(dir), STRorNULL(file));
|
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 */
|
2005-05-29 09:56:56 +04:00
|
|
|
oanonftp = anonftp;
|
1999-03-08 07:36:12 +03:00
|
|
|
if (connected)
|
|
|
|
disconnect(0, NULL);
|
2005-05-29 09:56:56 +04:00
|
|
|
anonftp = oanonftp;
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcpy(cmdbuf, getprogname(), sizeof(cmdbuf));
|
|
|
|
xargv[0] = cmdbuf;
|
1999-03-08 07:36:12 +03:00
|
|
|
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;
|
2000-06-15 17:08:23 +04:00
|
|
|
/* don't autologin in setpeer(), use ftp_login() below */
|
|
|
|
autologin = 0;
|
1999-03-08 07:36:12 +03:00
|
|
|
setpeer(xargc, xargv);
|
|
|
|
autologin = oautologin;
|
2000-06-15 17:08:23 +04:00
|
|
|
if ((connected == 0) ||
|
2009-04-12 11:07:41 +04:00
|
|
|
(connected == 1 && !ftp_login(host, uuser, pass))) {
|
2009-08-13 21:55:18 +04:00
|
|
|
warnx("Can't connect or login to host `%s:%s'",
|
|
|
|
host, port ? port : "?");
|
1999-03-08 07:36:12 +03:00
|
|
|
goto cleanup_fetch_ftp;
|
|
|
|
}
|
1998-12-29 17:59:04 +03:00
|
|
|
|
2009-04-12 11:07:41 +04:00
|
|
|
switch (transtype) {
|
1999-04-28 17:35:40 +04:00
|
|
|
case TYPE_A:
|
2000-07-18 10:49:21 +04:00
|
|
|
setascii(1, xargv);
|
1999-04-28 17:35:40 +04:00
|
|
|
break;
|
|
|
|
case TYPE_I:
|
2000-07-18 10:49:21 +04:00
|
|
|
setbinary(1, xargv);
|
1999-04-28 17:35:40 +04:00
|
|
|
break;
|
|
|
|
default:
|
2009-04-12 11:07:41 +04:00
|
|
|
errx(1, "fetch_ftp: unknown transfer type %d", transtype);
|
1999-04-28 17:35:40 +04:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
/*
|
1999-11-27 00:41:55 +03:00
|
|
|
* If we are dealing with a classic `[user@]host:[path]'
|
|
|
|
* (urltype is CLASSIC_URL_T) then we have a raw directory
|
1999-04-28 17:35:40 +04:00
|
|
|
* name (not encoded in any way) and we can change
|
|
|
|
* directories in one step.
|
|
|
|
*
|
|
|
|
* If we are dealing with an `ftp://host/path' URL
|
2010-03-05 10:41:10 +03:00
|
|
|
* (urltype is FTP_URL_T), then RFC 3986 says we need to
|
1999-04-28 17:35:40 +04:00
|
|
|
* 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
|
2010-03-05 10:41:10 +03:00
|
|
|
* slashes in the path) and RFC 3986 says that we should
|
1999-04-28 17:35:40 +04:00
|
|
|
* 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;
|
2007-12-05 06:46:33 +03:00
|
|
|
DPRINTF("fetch_ftp: dir `%s', nextpart `%s'\n",
|
|
|
|
STRorNULL(dir), STRorNULL(nextpart));
|
1999-07-12 17:20:34 +04:00
|
|
|
if (urltype == FTP_URL_T || *dir != '\0') {
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcpy(cmdbuf, "cd", sizeof(cmdbuf));
|
|
|
|
xargv[0] = cmdbuf;
|
1999-04-28 17:35:40 +04:00
|
|
|
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"
|
2010-03-05 10:41:10 +03:00
|
|
|
" RFC 3986 to support the empty directory in the URL pathname (`//'),\n"
|
|
|
|
" conflicts with the server's conformance to RFC 959.\n"
|
1999-07-12 17:20:34 +04:00
|
|
|
" 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) {
|
1999-09-28 10:47:38 +04:00
|
|
|
(void)strlcpy(rempath, dir, sizeof(rempath));
|
|
|
|
(void)strlcat(rempath, "/", sizeof(rempath));
|
|
|
|
(void)strlcat(rempath, file, sizeof(rempath));
|
1998-12-29 17:59:04 +03:00
|
|
|
file = rempath;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Fetch the file(s). */
|
|
|
|
xargc = 2;
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcpy(cmdbuf, "get", sizeof(cmdbuf));
|
|
|
|
xargv[0] = cmdbuf;
|
1998-12-29 17:59:04 +03:00
|
|
|
xargv[1] = file;
|
|
|
|
xargv[2] = NULL;
|
|
|
|
if (dirhasglob || filehasglob) {
|
|
|
|
int ointeractive;
|
|
|
|
|
|
|
|
ointeractive = interactive;
|
|
|
|
interactive = 0;
|
2005-01-13 01:37:41 +03:00
|
|
|
if (restartautofetch)
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcpy(cmdbuf, "mreget", sizeof(cmdbuf));
|
2005-01-13 01:37:41 +03:00
|
|
|
else
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcpy(cmdbuf, "mget", sizeof(cmdbuf));
|
|
|
|
xargv[0] = cmdbuf;
|
1998-12-29 17:59:04 +03:00
|
|
|
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;
|
|
|
|
|
2000-07-18 10:49:21 +04:00
|
|
|
cleanup_fetch_ftp:
|
2006-04-29 00:02:07 +04:00
|
|
|
FREEPTR(port);
|
1998-12-29 17:59:04 +03:00
|
|
|
FREEPTR(host);
|
|
|
|
FREEPTR(path);
|
2009-04-12 11:07:41 +04:00
|
|
|
FREEPTR(uuser);
|
2005-06-10 04:18:46 +04:00
|
|
|
if (pass)
|
|
|
|
memset(pass, 0, strlen(pass));
|
1998-12-29 17:59:04 +03:00
|
|
|
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
|
2000-05-01 14:35:16 +04:00
|
|
|
go_fetch(const char *url)
|
1998-12-29 17:59:04 +03:00
|
|
|
{
|
2009-04-12 11:07:41 +04:00
|
|
|
char *proxyenv;
|
2012-02-24 23:40:49 +04:00
|
|
|
char *p;
|
1998-12-29 17:59:04 +03:00
|
|
|
|
2004-06-06 05:37:41 +04:00
|
|
|
#ifndef NO_ABOUT
|
1998-12-29 17:59:04 +03:00
|
|
|
/*
|
|
|
|
* Check for about:*
|
|
|
|
*/
|
2004-07-20 16:46:51 +04:00
|
|
|
if (STRNEQUAL(url, ABOUT_URL)) {
|
1998-12-29 17:59:04 +03:00
|
|
|
url += sizeof(ABOUT_URL) -1;
|
2003-07-31 09:23:59 +04:00
|
|
|
if (strcasecmp(url, "ftp") == 0 ||
|
|
|
|
strcasecmp(url, "tnftp") == 0) {
|
1999-10-06 12:57:46 +04:00
|
|
|
fputs(
|
2003-07-27 00:34:11 +04:00
|
|
|
"This version of ftp has been enhanced by Luke Mewburn <lukem@NetBSD.org>\n"
|
1999-10-06 12:57:46 +04:00
|
|
|
"for the NetBSD project. Execute `man ftp' for more details.\n", ttyout);
|
|
|
|
} else if (strcasecmp(url, "lukem") == 0) {
|
|
|
|
fputs(
|
|
|
|
"Luke Mewburn is the author of most of the enhancements in this ftp client.\n"
|
2003-07-27 00:34:11 +04:00
|
|
|
"Please email feedback to <lukem@NetBSD.org>.\n", ttyout);
|
1998-12-29 17:59:04 +03:00
|
|
|
} else if (strcasecmp(url, "netbsd") == 0) {
|
1999-10-06 12:57:46 +04:00
|
|
|
fputs(
|
|
|
|
"NetBSD is a freely available and redistributable UNIX-like operating system.\n"
|
2003-07-31 09:23:59 +04:00
|
|
|
"For more information, see http://www.NetBSD.org/\n", ttyout);
|
1999-11-03 10:42:01 +03:00
|
|
|
} else if (strcasecmp(url, "version") == 0) {
|
2000-06-05 13:22:52 +04:00
|
|
|
fprintf(ttyout, "Version: %s %s%s\n",
|
|
|
|
FTP_PRODUCT, FTP_VERSION,
|
|
|
|
#ifdef INET6
|
|
|
|
""
|
|
|
|
#else
|
|
|
|
" (-IPv6)"
|
|
|
|
#endif
|
|
|
|
);
|
1998-12-29 17:59:04 +03:00
|
|
|
} else {
|
|
|
|
fprintf(ttyout, "`%s' is an interesting topic.\n", url);
|
|
|
|
}
|
1999-11-03 10:42:01 +03:00
|
|
|
fputs("\n", ttyout);
|
1998-12-29 17:59:04 +03:00
|
|
|
return (0);
|
|
|
|
}
|
2004-06-06 05:37:41 +04:00
|
|
|
#endif
|
1998-12-29 17:59:04 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for file:// and http:// URLs.
|
|
|
|
*/
|
2012-12-21 22:07:36 +04:00
|
|
|
if (STRNEQUAL(url, HTTP_URL)
|
|
|
|
#ifdef WITH_SSL
|
|
|
|
|| STRNEQUAL(url, HTTPS_URL)
|
|
|
|
#endif
|
|
|
|
|| STRNEQUAL(url, FILE_URL))
|
1999-03-22 10:36:40 +03:00
|
|
|
return (fetch_url(url, NULL, NULL, NULL));
|
1998-12-29 17:59:04 +03:00
|
|
|
|
2012-02-24 23:40:49 +04:00
|
|
|
/*
|
|
|
|
* If it contains "://" but does not begin with ftp://
|
|
|
|
* or something that was already handled, then it's
|
|
|
|
* unsupported.
|
|
|
|
*
|
|
|
|
* If it contains ":" but not "://" then we assume the
|
|
|
|
* part before the colon is a host name, not an URL scheme,
|
|
|
|
* so we don't try to match that here.
|
|
|
|
*/
|
|
|
|
if ((p = strstr(url, "://")) != NULL && ! STRNEQUAL(url, FTP_URL))
|
2012-02-24 23:53:31 +04:00
|
|
|
errx(1, "Unsupported URL scheme `%.*s'", (int)(p - url), url);
|
2012-02-24 23:40:49 +04:00
|
|
|
|
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().
|
|
|
|
*/
|
2009-04-12 11:07:41 +04:00
|
|
|
proxyenv = getoptionvalue("ftp_proxy");
|
|
|
|
if (!EMPTYSTRING(proxyenv) && STRNEQUAL(url, FTP_URL))
|
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
|
2000-05-01 14:35:16 +04:00
|
|
|
auto_fetch(int argc, char *argv[])
|
1997-01-19 17:19:02 +03:00
|
|
|
{
|
2005-05-29 09:56:56 +04:00
|
|
|
volatile int argpos, rval;
|
1998-06-04 12:28:35 +04:00
|
|
|
|
2005-05-29 09:56:56 +04:00
|
|
|
argpos = rval = 0;
|
1997-01-19 17:19:02 +03:00
|
|
|
|
1999-10-09 07:00:55 +04:00
|
|
|
if (sigsetjmp(toplevel, 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
|
|
|
if (connected)
|
|
|
|
disconnect(0, NULL);
|
2004-07-20 14:40:21 +04:00
|
|
|
if (rval > 0)
|
|
|
|
rval = argpos + 1;
|
|
|
|
return (rval);
|
[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-10-09 07:00:55 +04:00
|
|
|
(void)xsignal(SIGINT, intr);
|
1999-10-24 16:31:36 +04:00
|
|
|
(void)xsignal(SIGPIPE, lostpeer);
|
1997-01-19 17:19:02 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop through as long as there's files to fetch.
|
|
|
|
*/
|
2005-05-29 09:56:56 +04:00
|
|
|
for (; (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-10-12 10:04:59 +04:00
|
|
|
if (!anonftp)
|
|
|
|
anonftp = 2; /* 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);
|
|
|
|
}
|
2000-05-31 18:23:57 +04:00
|
|
|
|
|
|
|
|
2006-07-26 18:28:11 +04:00
|
|
|
/*
|
|
|
|
* Upload multiple files from the command line.
|
|
|
|
*
|
|
|
|
* 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 uploaded successfully.
|
|
|
|
*/
|
2000-05-31 18:23:57 +04:00
|
|
|
int
|
|
|
|
auto_put(int argc, char **argv, const char *uploadserver)
|
|
|
|
{
|
|
|
|
char *uargv[4], *path, *pathsep;
|
2006-07-26 18:28:11 +04:00
|
|
|
int uargc, rval, argpos;
|
2005-05-19 07:05:04 +04:00
|
|
|
size_t len;
|
2009-04-12 14:18:52 +04:00
|
|
|
char cmdbuf[MAX_C_NAME];
|
2000-05-31 18:23:57 +04:00
|
|
|
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcpy(cmdbuf, "mput", sizeof(cmdbuf));
|
|
|
|
uargv[0] = cmdbuf;
|
|
|
|
uargv[1] = argv[0];
|
|
|
|
uargc = 2;
|
2000-05-31 18:23:57 +04:00
|
|
|
uargv[2] = uargv[3] = NULL;
|
|
|
|
pathsep = NULL;
|
|
|
|
rval = 1;
|
|
|
|
|
2005-06-29 06:31:19 +04:00
|
|
|
DPRINTF("auto_put: target `%s'\n", uploadserver);
|
2000-05-31 18:23:57 +04:00
|
|
|
|
2006-01-31 23:01:23 +03:00
|
|
|
path = ftp_strdup(uploadserver);
|
2000-05-31 18:23:57 +04:00
|
|
|
len = strlen(path);
|
|
|
|
if (path[len - 1] != '/' && path[len - 1] != ':') {
|
|
|
|
/*
|
|
|
|
* make sure we always pass a directory to auto_fetch
|
|
|
|
*/
|
|
|
|
if (argc > 1) { /* more than one file to upload */
|
|
|
|
len = strlen(uploadserver) + 2; /* path + "/" + "\0" */
|
|
|
|
free(path);
|
2006-01-31 23:01:23 +03:00
|
|
|
path = (char *)ftp_malloc(len);
|
2000-05-31 18:23:57 +04:00
|
|
|
(void)strlcpy(path, uploadserver, len);
|
|
|
|
(void)strlcat(path, "/", len);
|
|
|
|
} else { /* single file to upload */
|
2009-04-12 14:18:52 +04:00
|
|
|
(void)strlcpy(cmdbuf, "put", sizeof(cmdbuf));
|
|
|
|
uargv[0] = cmdbuf;
|
2000-05-31 18:23:57 +04:00
|
|
|
pathsep = strrchr(path, '/');
|
|
|
|
if (pathsep == NULL) {
|
|
|
|
pathsep = strrchr(path, ':');
|
|
|
|
if (pathsep == NULL) {
|
|
|
|
warnx("Invalid URL `%s'", path);
|
|
|
|
goto cleanup_auto_put;
|
|
|
|
}
|
|
|
|
pathsep++;
|
2006-01-31 23:01:23 +03:00
|
|
|
uargv[2] = ftp_strdup(pathsep);
|
2000-05-31 18:23:57 +04:00
|
|
|
pathsep[0] = '/';
|
2005-04-11 05:49:31 +04:00
|
|
|
} else
|
2006-01-31 23:01:23 +03:00
|
|
|
uargv[2] = ftp_strdup(pathsep + 1);
|
2000-05-31 18:23:57 +04:00
|
|
|
pathsep[1] = '\0';
|
|
|
|
uargc++;
|
|
|
|
}
|
|
|
|
}
|
2005-06-29 06:31:19 +04:00
|
|
|
DPRINTF("auto_put: URL `%s' argv[2] `%s'\n",
|
2007-12-05 06:46:33 +03:00
|
|
|
path, STRorNULL(uargv[2]));
|
2005-04-11 05:49:31 +04:00
|
|
|
|
|
|
|
/* connect and cwd */
|
2000-05-31 18:23:57 +04:00
|
|
|
rval = auto_fetch(1, &path);
|
|
|
|
if(rval >= 0)
|
|
|
|
goto cleanup_auto_put;
|
|
|
|
|
2006-07-26 18:28:11 +04:00
|
|
|
rval = 0;
|
|
|
|
|
|
|
|
/* target filename provided; upload 1 file */
|
2000-05-31 18:23:57 +04:00
|
|
|
/* XXX : is this the best way? */
|
|
|
|
if (uargc == 3) {
|
|
|
|
uargv[1] = argv[0];
|
|
|
|
put(uargc, uargv);
|
2006-07-26 18:28:11 +04:00
|
|
|
if ((code / 100) != COMPLETE)
|
|
|
|
rval = 1;
|
|
|
|
} else { /* otherwise a target dir: upload all files to it */
|
|
|
|
for(argpos = 0; argv[argpos] != NULL; argpos++) {
|
|
|
|
uargv[1] = argv[argpos];
|
|
|
|
mput(uargc, uargv);
|
|
|
|
if ((code / 100) != COMPLETE) {
|
|
|
|
rval = argpos + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2000-05-31 18:23:57 +04:00
|
|
|
}
|
|
|
|
|
2000-07-18 10:49:21 +04:00
|
|
|
cleanup_auto_put:
|
2006-04-28 23:59:44 +04:00
|
|
|
free(path);
|
2000-05-31 18:23:57 +04:00
|
|
|
FREEPTR(uargv[2]);
|
|
|
|
return (rval);
|
|
|
|
}
|