version 1.39, 2002/05/30 06:51:46 |
version 1.40, 2002/11/08 03:30:17 |
|
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
|
#include <util.h> |
|
|
#include "ftp_var.h" |
#include "ftp_var.h" |
|
|
|
|
{ |
{ |
struct addrinfo hints, *res0, *res; |
struct addrinfo hints, *res0, *res; |
int error; |
int error; |
int i, isftpurl, isfileurl; |
int i, isftpurl, isfileurl, isredirect; |
volatile int s, out; |
volatile int s, out; |
size_t len; |
size_t len; |
char c, *cp, *ep, *portnum, *path, buf[4096]; |
char *cp, *ep, *portnum, *path; |
char pbuf[NI_MAXSERV]; |
char pbuf[NI_MAXSERV]; |
const char * volatile savefile; |
const char * volatile savefile; |
char *line, *host, *port; |
char *line, *host, *port, *buf; |
char * volatile proxy; |
char * volatile proxy; |
char *hosttail; |
char *hosttail; |
volatile sig_t oldintr; |
volatile sig_t oldintr; |
off_t hashbytes; |
off_t hashbytes; |
char *cause = "unknown"; |
char *cause = "unknown"; |
|
FILE *fin; |
|
int rval; |
|
|
s = -1; |
s = -1; |
proxy = NULL; |
proxy = NULL; |
|
fin = NULL; |
|
buf = NULL; |
isftpurl = 0; |
isftpurl = 0; |
isfileurl = 0; |
isfileurl = 0; |
|
isredirect = 0; |
|
rval = -1; |
|
|
line = strdup(origline); |
line = strdup(origline); |
if (line == NULL) |
if (line == NULL) |
|
|
bytes = 0; |
bytes = 0; |
hashbytes = mark; |
hashbytes = mark; |
progressmeter(-1); |
progressmeter(-1); |
|
|
|
if ((buf = malloc(4096)) == NULL) |
|
errx(1, "Can't allocate memory for transfer buffer\n"); |
|
|
/* Finally, suck down the file. */ |
/* Finally, suck down the file. */ |
i = 0; |
i = 0; |
while ((len = read(s, buf, sizeof(buf))) > 0) { |
while ((len = read(s, buf, 4096)) > 0) { |
bytes += len; |
bytes += len; |
for (cp = buf; len > 0; len -= i, cp += i) { |
for (cp = buf; len > 0; len -= i, cp += i) { |
if ((i = write(out, cp, len)) == -1) { |
if ((i = write(out, cp, len)) == -1) { |
|
|
fputs("Successfully retrieved file.\n", ttyout); |
fputs("Successfully retrieved file.\n", ttyout); |
(void)signal(SIGINT, oldintr); |
(void)signal(SIGINT, oldintr); |
|
|
close(s); |
rval = 0; |
if (out != fileno(stdout)) |
goto cleanup_url_get; |
close(out); |
|
if (proxy) |
|
free(proxy); |
|
free(line); |
|
return (0); |
|
} |
} |
|
|
if (*host == '[' && (hosttail = strrchr(host, ']')) != NULL && |
if (*host == '[' && (hosttail = strrchr(host, ']')) != NULL && |
|
|
* If the services file is corrupt/missing, fall back |
* If the services file is corrupt/missing, fall back |
* on our hard-coded defines. |
* on our hard-coded defines. |
*/ |
*/ |
char pbuf[NI_MAXSERV]; |
|
|
|
snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT); |
snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT); |
error = getaddrinfo(host, pbuf, &hints, &res0); |
error = getaddrinfo(host, pbuf, &hints, &res0); |
} |
} |
|
|
|
|
s = -1; |
s = -1; |
for (res = res0; res; res = res->ai_next) { |
for (res = res0; res; res = res->ai_next) { |
getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof(buf), |
getnameinfo(res->ai_addr, res->ai_addrlen, pbuf, sizeof(pbuf), |
NULL, 0, NI_NUMERICHOST); |
NULL, 0, NI_NUMERICHOST); |
fprintf(ttyout, "Trying %s...\n", buf); |
fprintf(ttyout, "Trying %s...\n", pbuf); |
|
|
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); |
s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); |
if (s == -1) { |
if (s == -1) { |
|
|
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
|
|
|
fin = fdopen(s, "r+"); |
|
|
/* |
/* |
* Construct and send the request. We're expecting a return |
* Construct and send the request. Proxy requests don't want leading /. |
* status of "200". Proxy requests don't want leading /. |
|
*/ |
*/ |
if (proxy) { |
if (proxy) { |
/* |
/* |
|
|
if (verbose) |
if (verbose) |
fprintf(ttyout, "Requesting %s (via %s)\n", |
fprintf(ttyout, "Requesting %s (via %s)\n", |
origline, proxyenv); |
origline, proxyenv); |
snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n%s\r\n\r\n", path, HTTP_USER_AGENT); |
fprintf(fin, "GET %s HTTP/1.0\r\n%s\r\n\r\n", path, HTTP_USER_AGENT); |
} else { |
} else { |
if (verbose) |
if (verbose) |
fprintf(ttyout, "Requesting %s\n", origline); |
fprintf(ttyout, "Requesting %s\n", origline); |
|
|
* send them the port number. |
* send them the port number. |
*/ |
*/ |
if (port && strcmp(port, "80") != 0) |
if (port && strcmp(port, "80") != 0) |
snprintf(buf, sizeof(buf), |
fprintf(fin, "GET /%s HTTP/1.0\r\nHost: [%s]:%s\r\n%s\r\n\r\n", |
"GET /%s HTTP/1.0\r\nHost: [%s]:%s\r\n%s\r\n\r\n", |
|
path, h, port, HTTP_USER_AGENT); |
path, h, port, HTTP_USER_AGENT); |
else |
else |
snprintf(buf, sizeof(buf), |
fprintf(fin, "GET /%s HTTP/1.0\r\nHost: [%s]\r\n%s\r\n\r\n", |
"GET /%s HTTP/1.0\r\nHost: [%s]\r\n%s\r\n\r\n", |
|
path, h, HTTP_USER_AGENT); |
path, h, HTTP_USER_AGENT); |
free(h); |
free(h); |
} else { |
} else { |
if (port && strcmp(port, "80") != 0) |
if (port && strcmp(port, "80") != 0) |
snprintf(buf, sizeof(buf), |
fprintf(fin, "GET /%s HTTP/1.0\r\nHost: %s:%s\r\n%s\r\n\r\n", |
"GET /%s HTTP/1.0\r\nHost: %s:%s\r\n%s\r\n\r\n", |
|
path, host, port, HTTP_USER_AGENT); |
path, host, port, HTTP_USER_AGENT); |
else |
else |
snprintf(buf, sizeof(buf), |
fprintf(fin, "GET /%s HTTP/1.0\r\nHost: %s\r\n%s\r\n\r\n", |
"GET /%s HTTP/1.0\r\nHost: %s\r\n%s\r\n\r\n", |
|
path, host, HTTP_USER_AGENT); |
path, host, HTTP_USER_AGENT); |
} |
} |
} |
} |
len = strlen(buf); |
if (fflush(fin) == EOF) { |
if (debug) |
|
fprintf(ttyout, "Sending request:\n%s", buf); |
|
if (write(s, buf, len) < len) { |
|
warn("Writing HTTP request"); |
warn("Writing HTTP request"); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
memset(buf, 0, sizeof(buf)); |
|
for (cp = buf; cp < buf + sizeof(buf); ) { |
if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) { |
if (read(s, cp, 1) != 1) |
warn("Receiving HTTP reply"); |
goto improper; |
goto cleanup_url_get; |
if (*cp == '\r') |
|
continue; |
|
if (*cp == '\n') |
|
break; |
|
cp++; |
|
} |
} |
buf[sizeof(buf) - 1] = '\0'; /* sanity */ |
|
|
while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n')) |
|
buf[--len] = '\0'; |
|
if (debug) |
|
fprintf(ttyout, "received '%s'\n", buf); |
|
|
cp = strchr(buf, ' '); |
cp = strchr(buf, ' '); |
if (cp == NULL) |
if (cp == NULL) |
goto improper; |
goto improper; |
else |
else |
cp++; |
cp++; |
if (strncmp(cp, "200", 3)) { |
if (strncmp(cp, "301", 3) == 0 || strncmp(cp, "302", 3) == 0) { |
|
isredirect++; |
|
} else if (strncmp(cp, "200", 3)) { |
warnx("Error retrieving file: %s", cp); |
warnx("Error retrieving file: %s", cp); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
|
|
/* |
/* |
* Read the rest of the header. |
* Read the rest of the header. |
*/ |
*/ |
memset(buf, 0, sizeof(buf)); |
free(buf); |
c = '\0'; |
filesize = -1; |
for (cp = buf; cp < buf + sizeof(buf); ) { |
|
if (read(s, cp, 1) != 1) |
while (1) { |
goto improper; |
if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) { |
if (*cp == '\r') |
warn("Receiving HTTP reply"); |
continue; |
goto cleanup_url_get; |
if (*cp == '\n' && c == '\n') |
} |
|
while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n')) |
|
buf[--len] = '\0'; |
|
if (len == 0) |
break; |
break; |
c = *cp; |
if (debug) |
cp++; |
fprintf(ttyout, "received '%s'\n", buf); |
} |
|
buf[sizeof(buf) - 1] = '\0'; /* sanity */ |
|
|
|
/* Look for the "Content-length: " header. */ |
/* Look for some headers */ |
|
cp = buf; |
#define CONTENTLEN "Content-Length: " |
#define CONTENTLEN "Content-Length: " |
for (cp = buf; *cp != '\0'; cp++) { |
if (strncasecmp(cp, CONTENTLEN, sizeof(CONTENTLEN) - 1) == 0) { |
if (tolower(*cp) == 'c' && |
cp += sizeof(CONTENTLEN) - 1; |
strncasecmp(cp, CONTENTLEN, sizeof(CONTENTLEN) - 1) == 0) |
filesize = strtol(cp, &ep, 10); |
break; |
if (filesize < 1 || *ep != '\0') |
|
goto improper; |
|
#define LOCATION "Location: " |
|
} else if (isredirect && |
|
strncasecmp(cp, LOCATION, sizeof(LOCATION) - 1) == 0) { |
|
cp += sizeof(LOCATION) - 1; |
|
if (verbose) |
|
fprintf(ttyout, "Redirected to %s\n", cp); |
|
if (fin != NULL) |
|
fclose(fin); |
|
else if (s != -1) |
|
close(s); |
|
if (proxy) |
|
free(proxy); |
|
free(line); |
|
rval = url_get(cp, proxyenv, outfile); |
|
if (buf) |
|
free(buf); |
|
return (rval); |
|
} |
} |
} |
if (*cp != '\0') { |
free(buf); |
cp += sizeof(CONTENTLEN) - 1; |
|
ep = strchr(cp, '\n'); |
|
if (ep == NULL) |
|
goto improper; |
|
else |
|
*ep = '\0'; |
|
filesize = strtol(cp, &ep, 10); |
|
if (filesize < 1 || *ep != '\0') |
|
goto improper; |
|
} else |
|
filesize = -1; |
|
|
|
/* Open the output file. */ |
/* Open the output file. */ |
if (strcmp(savefile, "-") != 0) { |
if (strcmp(savefile, "-") != 0) { |
|
|
progressmeter(-1); |
progressmeter(-1); |
|
|
/* Finally, suck down the file. */ |
/* Finally, suck down the file. */ |
|
if ((buf = malloc(4096)) == NULL) |
|
errx(1, "Can't allocate memory for transfer buffer\n"); |
i = 0; |
i = 0; |
while ((len = read(s, buf, sizeof(buf))) > 0) { |
while ((len = fread(buf, sizeof(char), 4096, fin)) > 0) { |
bytes += len; |
bytes += len; |
for (cp = buf; len > 0; len -= i, cp += i) { |
for (cp = buf; len > 0; len -= i, cp += i) { |
if ((i = write(out, cp, len)) == -1) { |
if ((i = write(out, cp, len)) == -1) { |
|
|
fputs("Successfully retrieved file.\n", ttyout); |
fputs("Successfully retrieved file.\n", ttyout); |
(void)signal(SIGINT, oldintr); |
(void)signal(SIGINT, oldintr); |
|
|
close(s); |
rval = 0; |
if (out != fileno(stdout)) |
goto cleanup_url_get; |
close(out); |
|
if (proxy) |
|
free(proxy); |
|
free(line); |
|
return (0); |
|
|
|
noftpautologin: |
noftpautologin: |
warnx( |
warnx( |
|
|
warnx("Improper response from %s", host); |
warnx("Improper response from %s", host); |
|
|
cleanup_url_get: |
cleanup_url_get: |
if (s != -1) |
if (fin != NULL) |
|
fclose(fin); |
|
else if (s != -1) |
close(s); |
close(s); |
|
if (buf) |
|
free(buf); |
if (proxy) |
if (proxy) |
free(proxy); |
free(proxy); |
free(line); |
free(line); |
return (-1); |
return (rval); |
} |
} |
|
|
/* |
/* |
|
|
setpeer(xargc, xargv); |
setpeer(xargc, xargv); |
autologin = oautologin; |
autologin = oautologin; |
if ((connected == 0) || |
if ((connected == 0) || |
((connected == 1) && !login(host, user, pass))) { |
((connected == 1) && !ftp_login(host, user, pass))) { |
warnx("Can't connect or login to host `%s'", |
warnx("Can't connect or login to host `%s'", |
host); |
host); |
rval = argpos + 1; |
rval = argpos + 1; |