last_patch95 from vodz:
[oweals/busybox.git] / networking / wget.c
index 5fa918a19fb046bf9dccb851b6b057b45076d898..a9ead7fc21cd7fe9752fb8b5aa8ddab6de51d1a5 100644 (file)
 
 #include "busybox.h"
 
-/* Stupid libc5 doesn't define this... */
-#ifndef timersub
-#define        timersub(a, b, result)                                                \
-  do {                                                                       \
-    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                            \
-    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                         \
-    if ((result)->tv_usec < 0) {                                             \
-      --(result)->tv_sec;                                                    \
-      (result)->tv_usec += 1000000;                                          \
-    }                                                                        \
-  } while (0)
-#endif 
-
 struct host_info {
        char *host;
        int port;
@@ -56,12 +43,12 @@ static void parse_url(char *url, struct host_info *h);
 static FILE *open_socket(char *host, int port);
 static char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc);
 static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf);
-static void progressmeter(int flag);
 
 /* Globals (can be accessed from signal handlers */
 static off_t filesize = 0;             /* content-length of the file */
 static int chunked = 0;                        /* chunked transfer encoding */
-#ifdef BB_FEATURE_WGET_STATUSBAR
+#ifdef CONFIG_FEATURE_WGET_STATUSBAR
+static void progressmeter(int flag);
 static char *curfile;                  /* Name of current file being transferred. */
 static struct timeval start;   /* Time a transfer started. */
 static volatile unsigned long statbytes = 0; /* Number of bytes transferred so far. */
@@ -123,10 +110,10 @@ static char *safe_fgets(char *s, int size, FILE *stream)
 
 #define close_delete_and_die(s...) { \
        close_and_delete_outfile(output, fname_out, do_continue); \
-       error_msg_and_die(s); }
+       bb_error_msg_and_die(s); }
 
 
-#ifdef BB_FEATURE_WGET_AUTHENTICATION
+#ifdef CONFIG_FEATURE_WGET_AUTHENTICATION
 /*
  *  Base64-encode character string
  *  oops... isn't something similar in uuencode.c?
@@ -140,7 +127,7 @@ char *base64enc(char *p, char *buf, int len) {
 
         while(*p) {
                                if (s >= buf+len-4)
-                                       error_msg_and_die("buffer overflow");
+                                       bb_error_msg_and_die("buffer overflow");
                 *(s++) = al[(*p >> 2) & 0x3F];
                 *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)];
                 *s = *(s+1) = '=';
@@ -159,7 +146,8 @@ int wget_main(int argc, char **argv)
 {
        int n, try=5, status;
        int port;
-       char *proxy;
+       char *proxy = 0;
+       char *dir_prefix=NULL;
        char *s, buf[512];
        struct stat sbuf;
        char extra_headers[1024];
@@ -176,23 +164,31 @@ int wget_main(int argc, char **argv)
        int got_clen = 0;                       /* got content-length: from server      */
        FILE *output;                           /* socket to web server                         */
        int quiet_flag = FALSE;         /* Be verry, verry quiet...                     */
+       int noproxy = 0;            /* Use proxies if env vars are set  */
+
+#define LONG_HEADER    1
+#define LONG_PASSIVE   2
 
-#define LONG_HEADER    1
        struct option long_options[] = {
-               { "continue",           0, NULL, 'c' },
-               { "quiet",              0, NULL, 'q' },
-               { "output-document",    1, NULL, 'O' },
-               { "header",             1, &which_long_opt, LONG_HEADER },
-               { 0,                    0, 0, 0 }
+               { "continue",        0, NULL, 'c' },
+               { "quiet",           0, NULL, 'q' },
+               { "output-document", 1, NULL, 'O' },
+               { "header",              1, &which_long_opt, LONG_HEADER },
+               { "proxy",           1, NULL, 'Y' },
+               { "passive-ftp",     0, &which_long_opt, LONG_PASSIVE },
+               { 0,                 0, 0, 0 }
        };
        /*
         * Crack command line.
         */
-       while ((n = getopt_long(argc, argv, "cqO:", long_options, &option_index)) != EOF) {
+       while ((n = getopt_long(argc, argv, "cqO:P:Y:", long_options, &option_index)) != EOF) {
                switch (n) {
                case 'c':
                        ++do_continue;
                        break;
+               case 'P':
+                       dir_prefix = optarg;
+                       break;
                case 'q':
                        quiet_flag = TRUE;
                        break;
@@ -203,12 +199,16 @@ int wget_main(int argc, char **argv)
                         */
                        fname_out = optarg;
                        break;
+               case 'Y':
+                       if (strcmp(optarg, "off") == 0)
+                               noproxy=1;      
+                       break;
                case 0:
                        switch (which_long_opt) {
                                case LONG_HEADER: {
                                        int arglen = strlen(optarg);
                                        if(extra_headers_left - arglen - 2 <= 0)
-                                               error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen);
+                                               bb_error_msg_and_die("extra_headers buffer too small(need %i)", extra_headers_left - arglen);
                                        strcpy(extra_headers_ptr, optarg);
                                        extra_headers_ptr += arglen;
                                        extra_headers_left -= ( arglen + 2 );
@@ -217,16 +217,18 @@ int wget_main(int argc, char **argv)
                                        *(extra_headers_ptr + 1) = 0;
                                        break;
                                }
+                               case LONG_PASSIVE:
+                                       // ignore -- we always use passive mode
+                                       break;
                        }
                        break;
                default:
-                       show_usage();
+                       bb_show_usage();
                }
        }
 
-       fprintf(stderr, "extra_headers='%s'\n", extra_headers);
        if (argc - optind != 1)
-                       show_usage();
+                       bb_show_usage();
 
        parse_url(argv[optind], &target);
        server.host = target.host;
@@ -235,31 +237,35 @@ int wget_main(int argc, char **argv)
        /*
         * Use the proxy if necessary.
         */
-       proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
-       if (proxy)
-               parse_url(xstrdup(proxy), &server);
+       if (!noproxy) {
+               proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy");
+               if (proxy)
+                       parse_url(bb_xstrdup(proxy), &server);
+       }
        
        /* Guess an output filename */
        if (!fname_out) {
                fname_out = 
-#ifdef BB_FEATURE_WGET_STATUSBAR
+#ifdef CONFIG_FEATURE_WGET_STATUSBAR
                        curfile = 
 #endif
-                       get_last_path_component(target.path);
+                       bb_get_last_path_component(target.path);
                if (fname_out==NULL || strlen(fname_out)<1) {
                        fname_out = 
-#ifdef BB_FEATURE_WGET_STATUSBAR
+#ifdef CONFIG_FEATURE_WGET_STATUSBAR
                                curfile = 
 #endif
                                "index.html";
                }
-#ifdef BB_FEATURE_WGET_STATUSBAR
+               if (dir_prefix != NULL)
+                       fname_out = concat_path_file(dir_prefix, fname_out);
+#ifdef CONFIG_FEATURE_WGET_STATUSBAR
        } else {
-               curfile = get_last_path_component(fname_out);
+               curfile = bb_get_last_path_component(fname_out);
 #endif
        }
        if (do_continue && !fname_out)
-               error_msg_and_die("cannot specify continue (-c) without a filename (-O)");
+               bb_error_msg_and_die("cannot specify continue (-c) without a filename (-O)");
 
 
        /*
@@ -269,7 +275,7 @@ int wget_main(int argc, char **argv)
                output = stdout;
                quiet_flag = TRUE;
        } else {
-               output = xfopen(fname_out, (do_continue ? "a" : "w"));
+               output = bb_xfopen(fname_out, (do_continue ? "a" : "w"));
        }
 
        /*
@@ -277,7 +283,7 @@ int wget_main(int argc, char **argv)
         */
        if (do_continue) {
                if (fstat(fileno(output), &sbuf) < 0)
-                       perror_msg_and_die("fstat()");
+                       bb_perror_msg_and_die("fstat()");
                if (sbuf.st_size > 0)
                        beg_range = sbuf.st_size;
                else
@@ -311,7 +317,7 @@ int wget_main(int argc, char **argv)
 
                        fprintf(sfp, "Host: %s\r\nUser-Agent: Wget\r\n", target.host);
 
-#ifdef BB_FEATURE_WGET_AUTHENTICATION
+#ifdef CONFIG_FEATURE_WGET_AUTHENTICATION
                        if (target.user) {
                                fprintf(sfp, "Authorization: Basic %s\r\n",
                                        base64enc(target.user, buf, sizeof(buf)));
@@ -380,9 +386,9 @@ read_response:              if (fgets(buf, sizeof(buf), sfp) == NULL)
                                }
                                if (strcasecmp(buf, "location") == 0) {
                                        if (s[0] == '/')
-                                               target.path = xstrdup(s+1);
+                                               target.path = bb_xstrdup(s+1);
                                        else {
-                                               parse_url(xstrdup(s), &target);
+                                               parse_url(bb_xstrdup(s), &target);
                                                if (!proxy) {
                                                        server.host = target.host;
                                                        server.port = target.port;
@@ -400,7 +406,7 @@ read_response:              if (fgets(buf, sizeof(buf), sfp) == NULL)
                 *  FTP session
                 */
                if (! target.user)
-                       target.user = xstrdup("anonymous:busybox@");
+                       target.user = bb_xstrdup("anonymous:busybox@");
 
                sfp = open_socket(server.host, server.port);
                if (ftpcmd(NULL, NULL, sfp, buf) != 220)
@@ -470,14 +476,15 @@ read_response:            if (fgets(buf, sizeof(buf), sfp) == NULL)
                fgets(buf, sizeof(buf), dfp);
                filesize = strtol(buf, (char **) NULL, 16);
        }
-#ifdef BB_FEATURE_WGET_STATUSBAR
+#ifdef CONFIG_FEATURE_WGET_STATUSBAR
        if (quiet_flag==FALSE)
                progressmeter(-1);
 #endif
        do {
                while ((filesize > 0 || !got_clen) && (n = safe_fread(buf, 1, chunked ? (filesize > sizeof(buf) ? sizeof(buf) : filesize) : sizeof(buf), dfp)) > 0) {
-               safe_fwrite(buf, 1, n, output);
-#ifdef BB_FEATURE_WGET_STATUSBAR
+                       if (safe_fwrite(buf, 1, n, output) != n)
+                               bb_perror_msg_and_die("write error");
+#ifdef CONFIG_FEATURE_WGET_STATUSBAR
                statbytes+=n;
 #endif
                if (got_clen)
@@ -492,16 +499,16 @@ read_response:            if (fgets(buf, sizeof(buf), sfp) == NULL)
                }
 
        if (n == 0 && ferror(dfp))
-               perror_msg_and_die("network read error");
+               bb_perror_msg_and_die("network read error");
        } while (chunked);
-#ifdef BB_FEATURE_WGET_STATUSBAR
+#ifdef CONFIG_FEATURE_WGET_STATUSBAR
        if (quiet_flag==FALSE)
                progressmeter(1);
 #endif
        if (!proxy && target.is_ftp) {
                fclose(dfp);
                if (ftpcmd(NULL, NULL, sfp, buf) != 226)
-                       error_msg_and_die("ftp error: %s", buf+4);
+                       bb_error_msg_and_die("ftp error: %s", buf+4);
                ftpcmd("QUIT", NULL, sfp, buf);
        }
        exit(EXIT_SUCCESS);
@@ -521,14 +528,14 @@ void parse_url(char *url, struct host_info *h)
                h->host = url + 6;
                h->is_ftp = 1;
        } else
-               error_msg_and_die("not an http or ftp url: %s", url);
+               bb_error_msg_and_die("not an http or ftp url: %s", url);
 
        sp = strchr(h->host, '/');
        if (sp != NULL) {
                *sp++ = '\0';
                h->path = sp;
        } else
-               h->path = "";
+               h->path = bb_xstrdup("");
 
        up = strrchr(h->host, '@');
        if (up != NULL) {
@@ -549,27 +556,18 @@ void parse_url(char *url, struct host_info *h)
 
 FILE *open_socket(char *host, int port)
 {
-       struct sockaddr_in s_in;
-       struct hostent *hp;
        int fd;
        FILE *fp;
+       char port_str[10];
 
-       memset(&s_in, 0, sizeof(s_in));
-       s_in.sin_family = AF_INET;
-       if ((hp = (struct hostent *) gethostbyname(host)) == NULL)
-               error_msg_and_die("cannot resolve %s", host);
-       memcpy(&s_in.sin_addr, hp->h_addr_list[0], hp->h_length);
-       s_in.sin_port = htons(port);
+       snprintf(port_str, sizeof(port_str), "%d", port);
+       fd=xconnect(host, port_str);
 
        /*
         * Get the server onto a stdio stream.
         */
-       if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-               perror_msg_and_die("socket()");
-       if (connect(fd, (struct sockaddr *) &s_in, sizeof(s_in)) < 0)
-               perror_msg_and_die("connect(%s)", host);
        if ((fp = fdopen(fd, "r+")) == NULL)
-               perror_msg_and_die("fdopen()");
+               bb_perror_msg_and_die("fdopen()");
 
        return fp;
 }
@@ -598,7 +596,7 @@ char *gethdr(char *buf, size_t bufsiz, FILE *fp, int *istrunc)
 
        /* verify we are at the end of the header name */
        if (*s != ':')
-               error_msg_and_die("bad header line: %s", buf);
+               bb_error_msg_and_die("bad header line: %s", buf);
 
        /* locate the start of the header value */
        for (*s++ = '\0' ; *s == ' ' || *s == '\t' ; ++s)
@@ -628,20 +626,20 @@ static int ftpcmd(char *s1, char *s2, FILE *fp, char *buf)
        
        if (s1) {
                if (!s2) s2="";
-               fprintf(fp, "%s%s\n", s1, s2);
+               fprintf(fp, "%s%s\r\n", s1, s2);
                fflush(fp);
        }
        
        do {
                p = fgets(buf, 510, fp);
                if (!p)
-                       perror_msg_and_die("fgets()");
+                       bb_perror_msg_and_die("fgets()");
        } while (! isdigit(buf[0]) || buf[3] != ' ');
        
        return atoi(buf);
 }
 
-#ifdef BB_FEATURE_WGET_STATUSBAR
+#ifdef CONFIG_FEATURE_WGET_STATUSBAR
 /* Stuff below is from BSD rcp util.c, as added to openshh. 
  * Original copyright notice is retained at the end of this file.
  * 
@@ -778,7 +776,7 @@ progressmeter(int flag)
 }
 #endif
 
-/* Original copyright notice which applies to the BB_FEATURE_WGET_STATUSBAR stuff,
+/* Original copyright notice which applies to the CONFIG_FEATURE_WGET_STATUSBAR stuff,
  * much of which was blatently stolen from openssh.  */
  
 /*-
@@ -813,7 +811,7 @@ progressmeter(int flag)
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *     $Id: wget.c,v 1.40 2001/05/15 20:11:49 andersen Exp $
+ *     $Id: wget.c,v 1.54 2003/07/22 08:56:51 andersen Exp $
  */