*
*/
-#include <getopt.h> /* for struct option */
#include "libbb.h"
struct host_info {
// May be used if we ever will want to free() all xstrdup()s...
/* char *allocated; */
- char *path;
- char *user;
- char *host;
- int port;
- smallint is_ftp;
+ const char *path;
+ const char *user;
+ char *host;
+ int port;
+ smallint is_ftp;
};
};
#define G (*(struct globals*)&bb_common_bufsiz1)
struct BUG_G_too_big {
- char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
+ char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
};
#define content_len (G.content_len )
#define beg_range (G.beg_range )
STALLTIME = 5 /* Seconds when xfer considered "stalled" */
};
-static int getttywidth(void)
+static unsigned int getttywidth(void)
{
- int width;
+ unsigned width;
get_terminal_width_height(0, &width, NULL);
return width;
}
/* last call to progressmeter */
alarm(0);
transferred = 0;
- putc('\n', stderr);
+ fputc('\n', stderr);
} else {
- if (flag == -1) {
- /* first call to progressmeter */
- struct sigaction sa;
- sa.sa_handler = progressmeter;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sigaction(SIGALRM, &sa, NULL);
+ if (flag == -1) { /* first call to progressmeter */
+ signal_SA_RESTART_empty_mask(SIGALRM, progressmeter);
}
alarm(1);
}
*/
#else /* FEATURE_WGET_STATUSBAR */
-static ALWAYS_INLINE void progressmeter(int flag) { }
+static ALWAYS_INLINE void progressmeter(int flag ATTRIBUTE_UNUSED) { }
#endif
p = strchr(h->host, '?'); if (!sp || (p && sp > p)) sp = p;
p = strchr(h->host, '#'); if (!sp || (p && sp > p)) sp = p;
if (!sp) {
- /* must be writable because of bb_get_last_path_component() */
- static char nullstr[] ALIGN1 = "";
- h->path = nullstr;
+ h->path = "";
} else if (*sp == '/') {
*sp = '\0';
h->path = sp + 1;
// http://busybox.net?login=john@doe is a valid URL
// memmove converts to:
// http:/busybox.nett?login=john@doe...
- memmove(h->host-1, h->host, sp - h->host);
+ memmove(h->host - 1, h->host, sp - h->host);
h->host--;
sp[-1] = '\0';
h->path = sp;
}
-int wget_main(int argc, char **argv);
-int wget_main(int argc, char **argv)
+int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int wget_main(int argc ATTRIBUTE_UNUSED, char **argv)
{
char buf[512];
struct host_info server, target;
llist_t *headers_llist = NULL;
#endif
FILE *sfp = NULL; /* socket to web/ftp server */
- FILE *dfp = NULL; /* socket to ftp server (data) */
- char *fname_out = NULL; /* where to direct output (-O) */
+ FILE *dfp; /* socket to ftp server (data) */
+ char *fname_out; /* where to direct output (-O) */
bool got_clen = 0; /* got content-length: from server */
int output_fd = -1;
bool use_proxy = 1; /* Use proxies if env vars are set */
#endif
/* server.allocated = target.allocated = NULL; */
opt_complementary = "-1" USE_FEATURE_WGET_LONG_OPTIONS(":\xfe::");
- opt = getopt32(argv, "csqO:P:Y:U:",
+ opt = getopt32(argv, "csqO:P:Y:U:" /*ignored:*/ "t:T:",
&fname_out, &dir_prefix,
- &proxy_flag, &user_agent
+ &proxy_flag, &user_agent,
+ NULL, /* -t RETRIES */
+ NULL /* -T NETWORK_READ_TIMEOUT */
USE_FEATURE_WGET_LONG_OPTIONS(, &headers_llist)
);
if (strcmp(proxy_flag, "off") == 0) {
}
extra_headers = cp = xmalloc(size);
while (headers_llist) {
- cp += sprintf(cp, "%s\r\n", headers_llist->data);
- headers_llist = headers_llist->link;
+ cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist));
}
}
#endif
}
}
- /* Guess an output filename */
- if (!fname_out) {
- // Dirty hack. Needed because bb_get_last_path_component
- // will destroy trailing / by storing '\0' in last byte!
- if (!last_char_is(target.path, '/')) {
- fname_out = bb_get_last_path_component(target.path);
-#if ENABLE_FEATURE_WGET_STATUSBAR
- curfile = fname_out;
-#endif
- }
- if (!fname_out || !fname_out[0]) {
- /* bb_get_last_path_component writes
- * to last '/' only. We don't have one here... */
+ /* Guess an output filename, if there was no -O FILE */
+ if (!(opt & WGET_OPT_OUTNAME)) {
+ fname_out = bb_get_last_path_component_nostrip(target.path);
+ /* handle "wget http://kernel.org//" */
+ if (fname_out[0] == '/' || !fname_out[0])
fname_out = (char*)"index.html";
-#if ENABLE_FEATURE_WGET_STATUSBAR
- curfile = fname_out;
-#endif
- }
- if (dir_prefix != NULL)
+ /* -P DIR is considered only if there was no -O FILE */
+ if (dir_prefix)
fname_out = concat_path_file(dir_prefix, fname_out);
-#if ENABLE_FEATURE_WGET_STATUSBAR
} else {
- curfile = bb_get_last_path_component(fname_out);
-#endif
+ if (LONE_DASH(fname_out)) {
+ /* -O - */
+ output_fd = 1;
+ opt &= ~WGET_OPT_CONTINUE;
+ }
}
+#if ENABLE_FEATURE_WGET_STATUSBAR
+ curfile = bb_get_last_path_component_nostrip(fname_out);
+#endif
+
/* Impossible?
if ((opt & WGET_OPT_CONTINUE) && !fname_out)
bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)"); */
/* Determine where to start transfer */
- if (LONE_DASH(fname_out)) {
- output_fd = 1;
- opt &= ~WGET_OPT_CONTINUE;
- }
if (opt & WGET_OPT_CONTINUE) {
output_fd = open(fname_out, O_WRONLY);
if (output_fd >= 0) {
lsa = xhost2sockaddr(server.host, server.port);
if (!(opt & WGET_OPT_QUIET)) {
fprintf(stderr, "Connecting to %s (%s)\n", server.host,
- xmalloc_sockaddr2dotted(&lsa->sa));
+ xmalloc_sockaddr2dotted(&lsa->u.sa));
/* We leak result of xmalloc_sockaddr2dotted */
}
/* eat all remaining headers */;
goto read_response;
case 200:
+/*
+Response 204 doesn't say "null file", it says "metadata
+has changed but data didn't":
+
+"10.2.5 204 No Content
+The server has fulfilled the request but does not need to return
+an entity-body, and might want to return updated metainformation.
+The response MAY include new or updated metainformation in the form
+of entity-headers, which if present SHOULD be associated with
+the requested variant.
+
+If the client is a user agent, it SHOULD NOT change its document
+view from that which caused the request to be sent. This response
+is primarily intended to allow input for actions to take place
+without causing a change to the user agent's active document view,
+although any new or updated metainformation SHOULD be applied
+to the document currently in the user agent's active view.
+
+The 204 response MUST NOT include a message-body, and thus
+is always terminated by the first empty line after the header fields."
+
+However, in real world it was observed that some web servers
+(e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero.
+*/
+ case 204:
break;
case 300: /* redirection */
case 301:
case 206:
if (beg_range)
break;
- /*FALLTHRU*/
+ /* fall through */
default:
/* Show first line only and kill any ESC tricks */
buf[strcspn(buf, "\n\r\x1b")] = '\0';
case 331:
if (ftpcmd("PASS ", str, sfp, buf) == 230)
break;
- /* FALLTHRU (failed login) */
+ /* fall through (failed login) */
default:
bb_error_msg_and_die("ftp login: %s", buf+4);
}
*/
/* Do it before progressmeter (want to have nice error message) */
- if (output_fd < 0)
- output_fd = xopen(fname_out,
- O_WRONLY|O_CREAT|O_EXCL|O_TRUNC);
+ if (output_fd < 0) {
+ int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL;
+ /* compat with wget: -O FILE can overwrite */
+ if (opt & WGET_OPT_OUTNAME)
+ o_flags = O_WRONLY | O_CREAT | O_TRUNC;
+ output_fd = xopen(fname_out, o_flags);
+ }
if (!(opt & WGET_OPT_QUIET))
progressmeter(-1);