diff -ur wget-1.8.1.orig/src/connect.c wget-1.8.1/src/connect.c --- wget-1.8.1.orig/src/connect.c Tue Nov 27 23:55:40 2001 +++ wget-1.8.1/src/connect.c Tue Feb 19 03:02:05 2002 @@ -78,17 +78,49 @@ int connect_to_one (const unsigned char *addr, unsigned short port, int silent) { +#ifdef INET6 + struct addrinfo hints, *res; + struct sockaddr_storage sock_name; + char portstr[NI_MAXSERV]; + int err; +#else struct sockaddr_in sock_name; - int sock, save_errno; +#endif + int sock, save_errno, salen; /* Set port and protocol */ +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + snprintf(portstr, sizeof(portstr), "%d", port); + err = getaddrinfo(addr, portstr, &hints, &res); + if (err) + { + if (!silent) + logprintf (LOG_VERBOSE, "getaddrinfo: %s.\n", gai_strerror (err)); + return -1; + } + memset (&sock_name, 0, sizeof (sock_name)); + memcpy (&sock_name, res->ai_addr, res->ai_addrlen); + salen = res->ai_addrlen; + freeaddrinfo (res); +#else sock_name.sin_family = AF_INET; sock_name.sin_port = htons (port); memcpy ((unsigned char *)&sock_name.sin_addr, addr, 4); + salen = sizeof (sock_name); +#endif if (!silent) { +#ifdef INET6 + char pretty_addr[INET6_ADDRSTRLEN]; + pretty_print_address_sa (&sock_name, salen, pretty_addr); +#else char *pretty_addr = pretty_print_address (addr); +#endif if (connection_host_name && 0 != strcmp (connection_host_name, pretty_addr)) logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "), @@ -99,26 +131,29 @@ } /* Make an internet socket, stream type. */ - sock = socket (AF_INET, SOCK_STREAM, 0); + sock = socket (((struct sockaddr *)&sock_name)->sa_family, SOCK_STREAM, 0); if (sock < 0) goto out; if (opt.bind_address) { /* Bind the client side to the requested address. */ - if (bind (sock, (struct sockaddr *)opt.bind_address, - sizeof (*opt.bind_address))) + if (bind (sock, (struct sockaddr *)opt.bind_address, salen)) { - close (sock); + save_errno = errno; + CLOSE (sock); + errno = save_errno; sock = -1; goto out; } } /* Connect the socket to the remote host. */ - if (connect (sock, (struct sockaddr *)&sock_name, sizeof (sock_name)) < 0) + if (connect (sock, (struct sockaddr *)&sock_name, salen) < 0) { - close (sock); + save_errno = errno; + CLOSE (sock); + errno = save_errno; sock = -1; goto out; } @@ -130,6 +165,10 @@ if (!silent) logprintf (LOG_VERBOSE, _("connected.\n")); DEBUGP (("Created socket %d.\n", sock)); +#ifdef INET6 + opt.conn_inet6 = ((struct sockaddr *)&sock_name)->sa_family == AF_INET6 ? + 1 : 0; +#endif } else { @@ -151,10 +190,28 @@ address_list_get_bounds (al, &start, &end); for (i = start; i < end; i++) { +#ifdef INET6 + struct addrinfo ai; + unsigned char *addr = (unsigned char *)&ai; + char hbuf[INET6_ADDRSTRLEN]; + int err; +#else unsigned char addr[4]; +#endif int sock; address_list_copy_one (al, i, addr); +#ifdef INET6 + err = getnameinfo(ai.ai_addr, ai.ai_addrlen, hbuf, sizeof (hbuf), + NULL, 0, NI_NUMERICHOST); + if (err) + { + if (!silent) + logprintf (LOG_VERBOSE, "getnameinfo: %s.\n", gai_strerror (err)); + continue; + } + addr = (unsigned char *)hbuf; +#endif sock = connect_to_one (addr, port, silent); if (sock >= 0) /* Success. */ @@ -207,14 +264,27 @@ internal variable MPORT is set to the value of the ensuing master socket. Call acceptport() to block for and accept a connection. */ uerr_t -bindport (unsigned short *port) +bindport_af (unsigned short *port, int af) { int optval = 1; +#ifdef INET6 + static struct sockaddr_storage srv; +#else static struct sockaddr_in srv; +#endif + int alen; msock = -1; addr = (struct sockaddr *) &srv; - if ((msock = socket (AF_INET, SOCK_STREAM, 0)) < 0) + if (af == AF_INET) + alen = sizeof (struct sockaddr_in); +#ifdef INET6 + else if (af == AF_INET6) + alen = sizeof (struct sockaddr_in6); +#endif + else + return CONSOCKERR; + if ((msock = socket (af, SOCK_STREAM, 0)) < 0) return CONSOCKERR; if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof (optval)) < 0) @@ -222,14 +292,18 @@ if (opt.bind_address == NULL) { - srv.sin_family = AF_INET; + memset (&srv, 0, sizeof (srv)); + ((struct sockaddr *)&srv)->sa_family = af; + /* in6addr_any : all 0 */ +#ifndef INET6 srv.sin_addr.s_addr = htonl (INADDR_ANY); +#endif } else srv = *opt.bind_address; - srv.sin_port = htons (*port); - if (bind (msock, addr, sizeof (struct sockaddr_in)) < 0) + ((struct sockaddr_in *)&srv)->sin_port = htons (*port); /* same sin6 */ + if (bind (msock, addr, alen) < 0) { CLOSE (msock); msock = -1; @@ -241,14 +315,14 @@ /* #### addrlen should be a 32-bit type, which int is not guaranteed to be. Oh, and don't try to make it a size_t, because that can be 64-bit. */ - int addrlen = sizeof (struct sockaddr_in); + int addrlen = sizeof (srv); if (getsockname (msock, addr, &addrlen) < 0) { CLOSE (msock); msock = -1; return CONPORTERR; } - *port = ntohs (srv.sin_port); + *port = ntohs (((struct sockaddr_in *)addr)->sin_port); /* same sin6 */ } if (listen (msock, 1) < 0) { @@ -257,6 +331,12 @@ return LISTENERR; } return BINDOK; +} + +uerr_t +bindport (unsigned short *port) +{ + return bindport_af (port, AF_INET); } #ifdef HAVE_SELECT diff -ur wget-1.8.1.orig/src/connect.h wget-1.8.1/src/connect.h --- wget-1.8.1.orig/src/connect.h Fri Nov 30 03:22:18 2001 +++ wget-1.8.1/src/connect.h Mon Feb 11 23:53:31 2002 @@ -30,6 +30,7 @@ int test_socket_open PARAMS ((int)); int select_fd PARAMS ((int, int, int)); +uerr_t bindport_af PARAMS ((unsigned short *, int)); uerr_t bindport PARAMS ((unsigned short *)); uerr_t acceptport PARAMS ((int *)); void closeport PARAMS ((int)); diff -ur wget-1.8.1.orig/src/ftp-basic.c wget-1.8.1/src/ftp-basic.c --- wget-1.8.1.orig/src/ftp-basic.c Mon Dec 10 11:29:11 2001 +++ wget-1.8.1/src/ftp-basic.c Tue Feb 19 00:29:13 2002 @@ -35,7 +35,12 @@ #ifdef WINDOWS # include +#else +#include +#include +#include #endif +#include #include "wget.h" #include "utils.h" @@ -340,6 +345,137 @@ xfree (respline); return FTPOK; } + +#ifdef INET6 +/* Bind a port and send the appropriate EPRT command to the FTP + server. Use acceptport after RETR, to get the socket of data + connection. */ +uerr_t +ftp_eprt (struct rbuf *rbuf) +{ + uerr_t err; + char *request, *respline, *bytes; + int nwritten; + unsigned short port; + struct sockaddr_storage ss; + int sslen; + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; + int af; + + /* Get the address of this side of the connection. */ + sslen = sizeof(ss); + if (getsockname(RBUF_FD (rbuf), (struct sockaddr *)&ss, &sslen) < 0) + return HOSTERR; + /* Construct the argument of EPRT. */ + if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), + NULL, 0, NI_NUMERICHOST) != 0) + return HOSTERR; + /* Setting port to 0 lets the system choose a free port. */ + port = 0; + /* Bind the port. */ + err = bindport_af (&port, ((struct sockaddr *)&ss)->sa_family); + if (err != BINDOK) + return err; + sprintf(pbuf, "%u", port); + af = ((struct sockaddr *)&ss)->sa_family == AF_INET6 ? 2 : 1; + bytes = (char *)alloca (1 + strlen(hbuf) + strlen(pbuf) + 4 + 1); + sprintf (bytes, "|%d|%s|%s|", af, hbuf, pbuf); + /* Send EPRT request. */ + request = ftp_request ("EPRT", bytes); + nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); + if (nwritten < 0) + { + free (request); + return WRITEFAILED; + } + free (request); + /* Get appropriate response. */ + err = ftp_response (rbuf, &respline); + if (err != FTPOK) + { + free (respline); + return err; + } + if (*respline != '2') + { + free (respline); + return FTPPORTERR; + } + free (respline); + return FTPOK; +} + +/* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP + transfer. Reads the response from server and parses it. Reads the + host and port addresses and returns them. */ +uerr_t +ftp_epsv (struct rbuf *rbuf, char *hbuf, unsigned short *pport) +{ + char *request, *respline, *s, *ep, delim; + long rcv; + int nwritten; + uerr_t err; + struct sockaddr_storage ss; + int sslen = sizeof(ss); + + if (getpeername(RBUF_FD (rbuf), (struct sockaddr *)&ss, &sslen) < 0) + return HOSTERR; + if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, INET6_ADDRSTRLEN, + NULL, 0, NI_NUMERICHOST) != 0) + return HOSTERR; + + /* Form the request. */ + request = ftp_request ("EPSV", NULL); + /* And send it. */ + nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); + if (nwritten < 0) + { + free (request); + return WRITEFAILED; + } + free (request); + /* Get the server response. */ + err = ftp_response (rbuf, &respline); + if (err != FTPOK) + goto fin; + if (strncmp(respline, "229", 3) != 0) + { + err = FTPNOPASV; + goto fin; + } + /* Parse the request. */ + s = respline; + for (s += 4; *s && *s != '('; s++); + if (!*s) + { + err = FTPINVPASV; + goto fin; + } + s++; + if (s[0] && s[0] == s[1] && s[0] == s[2]) + { + delim = s[0]; + s += 3; + } + else + { + err = FTPINVPASV; + goto fin; + } + rcv = strtol (s, &ep, 10); + if (rcv <= 0 || rcv > USHRT_MAX || *ep != delim) + { + err = FTPINVPASV; + goto fin; + } + *pport = (unsigned short)rcv; + err = FTPOK; + +fin: + free (respline); + return err; +} +#endif /* Sends the TYPE request to the server. */ uerr_t diff -ur wget-1.8.1.orig/src/ftp.c wget-1.8.1/src/ftp.c --- wget-1.8.1.orig/src/ftp.c Tue Dec 4 02:22:05 2001 +++ wget-1.8.1/src/ftp.c Tue Feb 19 03:35:12 2002 @@ -33,6 +33,9 @@ #include #include #include +#include +#include +#include #include "wget.h" #include "utils.h" @@ -489,6 +492,54 @@ { if (opt.ftp_pasv > 0) { + unsigned short tport; +#ifdef INET6 + char thost[64]; + + if (!opt.conn_inet6) + goto noepsv; + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> EPSV ... "); + err = ftp_epsv (&con->rbuf, thost, &tport); + /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV, HOSTERR */ + switch (err) + { + case FTPRERR: + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, _("\ +Error in server response, closing control connection.\n")); + break; + case WRITEFAILED: + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, + _("Write failed, closing control connection.\n")); + break; + case FTPNOPASV: + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, _("Cannot initiate EPSV transfer.\n")); + goto tryeprt; + case FTPINVPASV: + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, _("Cannot parse EPSV response.\n")); + goto tryeprt; + case HOSTERR: + logputs (LOG_VERBOSE, "\n"); + logprintf (LOG_NOTQUIET, "%s: error\n", u->host); + break; + case FTPOK: + /* fine and dandy */ + inet_aton(thost, (struct in_addr *)pasv_addr); + goto pasvok; + default: + abort (); + break; + } + CLOSE (csock); + rbuf_uninitialize (&con->rbuf); + return err; + + noepsv: +#endif if (!opt.server_response) logputs (LOG_VERBOSE, "==> PASV ... "); err = ftp_pasv (&con->rbuf, pasv_addr); @@ -528,10 +579,17 @@ } if (err==FTPOK) { - unsigned short tport; - +#ifdef INET6 + inet_ntop (AF_INET, pasv_addr, thost, sizeof (thost)); +#endif tport = (pasv_addr[4] << 8) + pasv_addr[5]; + +#ifdef INET6 + pasvok: + dtsock = connect_to_one (thost, tport, 1); +#else dtsock = connect_to_one (pasv_addr, tport, 1); +#endif if (dtsock < 0) { @@ -539,7 +597,11 @@ CLOSE (csock); rbuf_uninitialize (&con->rbuf); logprintf (LOG_VERBOSE, _("couldn't connect to %s:%hu: %s\n"), +#ifdef INET6 + thost, tport, +#else pretty_print_address (pasv_addr), tport, +#endif strerror (save_errno)); return save_errno == ECONNREFUSED ? CONREFUSED : CONERROR; } @@ -552,6 +614,61 @@ if (!passive_mode_open) /* Try to use a port command if PASV failed */ { +#ifdef INET6 + if (!opt.conn_inet6) + goto noeprt; + tryeprt: + if (!opt.server_response) + logputs (LOG_VERBOSE, "==> EPRT ... "); + err = ftp_eprt (&con->rbuf); + /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR, + LISTENERR), HOSTERR, FTPPORTERR */ + switch (err) + { + case FTPRERR: + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, _("\ +Error in server response, closing control connection.\n")); + break; + case WRITEFAILED: + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, + _("Write failed, closing control connection.\n")); + break; + case CONSOCKERR: + logputs (LOG_VERBOSE, "\n"); + logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno)); + break; + case CONPORTERR: case BINDERR: case LISTENERR: + /* What now? These problems are local... */ + logputs (LOG_VERBOSE, "\n"); + logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"), + strerror (errno)); + closeport (dtsock); + return err; + break; + case HOSTERR: + logputs (LOG_VERBOSE, "\n"); + logprintf (LOG_NOTQUIET, "%s: error\n", u->host); + break; + case FTPPORTERR: + logputs (LOG_VERBOSE, "\n"); + logputs (LOG_NOTQUIET, _("Invalid EPRT.\n")); + break; + case FTPOK: + /* fine and dandy */ + goto portok; + default: + abort (); + break; + } /* eprt switch */ + CLOSE (csock); + closeport (dtsock); + rbuf_uninitialize (&con->rbuf); + return err; + + noeprt: +#endif if (!opt.server_response) logputs (LOG_VERBOSE, "==> PORT ... "); err = ftp_port (&con->rbuf); @@ -608,6 +725,9 @@ abort (); break; } /* port switch */ +#ifdef INET6 + portok: +#endif if (!opt.server_response) logputs (LOG_VERBOSE, _("done. ")); } /* dtsock == -1 */ diff -ur wget-1.8.1.orig/src/ftp.h wget-1.8.1/src/ftp.h --- wget-1.8.1.orig/src/ftp.h Thu Nov 22 09:24:27 2001 +++ wget-1.8.1/src/ftp.h Tue Feb 19 00:32:35 2002 @@ -37,6 +37,10 @@ uerr_t ftp_login PARAMS ((struct rbuf *, const char *, const char *)); uerr_t ftp_port PARAMS ((struct rbuf *)); uerr_t ftp_pasv PARAMS ((struct rbuf *, unsigned char *)); +#ifdef INET6 +uerr_t ftp_eprt PARAMS ((struct rbuf *)); +uerr_t ftp_epsv PARAMS ((struct rbuf *, char *, unsigned short *)); +#endif uerr_t ftp_type PARAMS ((struct rbuf *, int)); uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *)); uerr_t ftp_retr PARAMS ((struct rbuf *, const char *)); diff -ur wget-1.8.1.orig/src/host.c wget-1.8.1/src/host.c --- wget-1.8.1.orig/src/host.c Tue Dec 11 17:32:57 2001 +++ wget-1.8.1/src/host.c Wed Feb 13 04:14:11 2002 @@ -77,7 +77,11 @@ struct address_list { int count; /* number of adrresses */ +#ifdef INET6 + struct addrinfo *addresses; +#else ipv4_address *addresses; /* pointer to the string of addresses */ +#endif int faulty; /* number of addresses known not to work. */ @@ -100,8 +104,17 @@ address_list_copy_one (struct address_list *al, int index, unsigned char *ip_store) { +#ifdef INET6 + struct addrinfo *ai; + assert (index >= al->faulty && index < al->count); + for (ai = al->addresses; ai; ai = ai->ai_next, index--) + if (index <= 0) + break; + memcpy (ip_store, ai, sizeof (*ai)); +#else assert (index >= al->faulty && index < al->count); memcpy (ip_store, al->addresses + index, sizeof (ipv4_address)); +#endif } /* Check whether two address lists have all their IPs in common. */ @@ -109,12 +122,27 @@ int address_list_match_all (struct address_list *al1, struct address_list *al2) { +#ifdef INET6 + struct addrinfo *ai1, *ai2; +#endif if (al1 == al2) return 1; if (al1->count != al2->count) return 0; +#ifdef INET6 + for (ai1 = al1->addresses, ai2 = al2->addresses; ai1; + ai1 = ai1->ai_next, ai2 = ai2->ai_next) + { + if (ai1->ai_addrlen != ai2->ai_addrlen) + return 0; + if (memcmp (ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen)) + return 0; + } + return 1; +#else return 0 == memcmp (al1->addresses, al2->addresses, al1->count * sizeof (ipv4_address)); +#endif } /* Mark the INDEXth element of AL as faulty, so that the next time @@ -141,26 +169,44 @@ as returned by gethostbyname. */ static struct address_list * +#ifdef INET6 +address_list_new (struct addrinfo *ai) +{ + struct addrinfo *res; +#else address_list_new (char **h_addr_list) { - int count = 0, i; + int i; +#endif + int count = 0; struct address_list *al = xmalloc (sizeof (struct address_list)); +#ifdef INET6 + for (res = ai; res; res = res->ai_next) +#else while (h_addr_list[count]) +#endif ++count; assert (count > 0); al->count = count; al->faulty = 0; +#ifdef INET6 + al->addresses = ai; +#else al->addresses = xmalloc (count * sizeof (ipv4_address)); +#endif al->refcount = 1; +#ifndef INET6 for (i = 0; i < count; i++) memcpy (al->addresses + i, h_addr_list[i], sizeof (ipv4_address)); +#endif return al; } +#ifndef INET6 /* Like address_list_new, but initialized with only one address. */ static struct address_list * @@ -175,11 +221,16 @@ return al; } +#endif static void address_list_delete (struct address_list *al) { +#ifdef INET6 + freeaddrinfo (al->addresses); +#else xfree (al->addresses); +#endif xfree (al); } @@ -203,6 +254,17 @@ { return inet_ntoa (*(struct in_addr *)addr); } +#ifdef INET6 +int +pretty_print_address_sa (const void *addr, int alen, char *abuf) +{ + int err = getnameinfo((struct sockaddr *)addr, alen, abuf, INET6_ADDRSTRLEN, + NULL, 0, NI_NUMERICHOST); + if (err) + strcpy (abuf, "???"); + return err; +} +#endif /* Add host name HOST with the address ADDR_TEXT to the cache. ADDR_LIST is a NULL-terminated list of addresses, as in struct @@ -220,10 +282,23 @@ #ifdef DEBUG if (opt.debug) { +#ifdef INET6 + struct addrinfo *ai; +#else int i; +#endif debug_logprintf ("Caching %s =>", host); +#ifdef INET6 + for (ai = al->addresses; ai; ai = ai->ai_next) + { + char hbuf[INET6_ADDRSTRLEN]; + pretty_print_address_sa (ai->ai_addr, ai->ai_addrlen, hbuf); + debug_logprintf (" %s", hbuf); + } +#else for (i = 0; i < al->count; i++) debug_logprintf (" %s", pretty_print_address (al->addresses + i)); +#endif debug_logprintf ("\n"); } #endif @@ -233,6 +308,24 @@ lookup_host (const char *host, int silent) { struct address_list *al = NULL; +#ifdef INET6 + struct addrinfo hints, *res; + int error; + + memset(&hints, 0, sizeof(hints)); + if (opt.inet) + hints.ai_family = AF_INET; + else if (opt.inet6) + hints.ai_family = AF_INET6; + else + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + /* check `N.N.N.N' or 'X:X:X:X:X:X:X:X'. */ + if (!getaddrinfo(host, NULL, &hints, &res)) + return address_list_new (res); + +#else unsigned long addr; struct hostent *hptr; @@ -254,6 +347,7 @@ #endif return address_list_new_one ((char *)&addr + offset); } +#endif /* INET6 */ /* By now we know that the host name we got is not of the form d.d.d.d. Try to find it in our cache of host names. */ @@ -270,12 +364,29 @@ if (!silent) logprintf (LOG_VERBOSE, _("Resolving %s... "), host); +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + if (opt.inet) + hints.ai_family = AF_INET; + else if (opt.inet6) + hints.ai_family = AF_INET6; + else + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, NULL, &hints, &res); + if (error) +#else /* Look up the host using gethostbyname(). */ hptr = gethostbyname (host); if (!hptr) +#endif { if (!silent) +#ifdef INET6 + logprintf (LOG_VERBOSE, _("failed: %s.\n"), gai_strerror(error)); +#else logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno)); +#endif return NULL; } @@ -284,7 +395,11 @@ /* Do all systems have h_addr_list, or is it a newer thing? If the latter, use address_list_new_one. */ +#ifdef INET6 + al = address_list_new (res); +#else al = address_list_new (hptr->h_addr_list); +#endif /* Cache the lookup information. */ cache_host_lookup (host, al); diff -ur wget-1.8.1.orig/src/host.h wget-1.8.1/src/host.h --- wget-1.8.1.orig/src/host.h Tue Dec 11 17:32:58 2001 +++ wget-1.8.1/src/host.h Wed Feb 13 00:14:42 2002 @@ -38,6 +38,9 @@ /* This was originally going to be a macro, but then every caller would have to #include the netinet stuff. */ char *pretty_print_address PARAMS ((const void *)); +#ifdef INET6 +int pretty_print_address_sa PARAMS ((const void *, int, char *)); +#endif int accept_domain PARAMS ((struct url *)); int sufmatch PARAMS ((const char **, const char *)); diff -ur wget-1.8.1.orig/src/http.c wget-1.8.1/src/http.c --- wget-1.8.1.orig/src/http.c Fri Dec 14 01:46:56 2001 +++ wget-1.8.1/src/http.c Sun Jan 27 08:19:10 2002 @@ -559,6 +559,11 @@ /* Whether keep-alive should be inhibited. */ int inhibit_keep_alive; + /* Whether we need to print the host header with braces around host, + e.g. "Host: [3ffe:8100:200:2::2]:1234" instead of the usual + "Host: symbolic-name:1234". */ + int squares_around_host = 0; + #ifdef HAVE_SSL /* initialize ssl_ctx on first run */ if (!ssl_ctx) @@ -811,6 +816,9 @@ "param=value", full_path will be "/foo/bar?param=value". */ full_path = url_full_path (u); + if (strchr (u->host, ':')) + squares_around_host = 1; + /* Allocate the memory for the request. */ request = (char *)alloca (strlen (command) + strlen (full_path) @@ -832,11 +840,12 @@ sprintf (request, "\ %s %s HTTP/1.0\r\n\ User-Agent: %s\r\n\ -Host: %s%s\r\n\ +Host: %s%s%s%s\r\n\ Accept: %s\r\n\ %s%s%s%s%s%s%s%s\r\n", command, full_path, - useragent, u->host, + useragent, + squares_around_host ? "[" : "", u->host, squares_around_host ? "]" : "", port_maybe ? port_maybe : "", HTTP_ACCEPT, request_keep_alive ? request_keep_alive : "", diff -ur wget-1.8.1.orig/src/init.c wget-1.8.1/src/init.c --- wget-1.8.1.orig/src/init.c Fri Dec 14 04:19:03 2001 +++ wget-1.8.1/src/init.c Tue Feb 19 02:45:18 2002 @@ -38,6 +38,7 @@ #else # include # include +# include #ifndef __BEOS__ # include #endif @@ -142,6 +143,10 @@ { "ignorelength", &opt.ignore_length, cmd_boolean }, { "ignoretags", &opt.ignore_tags, cmd_vector }, { "includedirectories", &opt.includes, cmd_directory_vector }, +#ifdef INET6 + { "inet", &opt.inet, cmd_boolean }, + { "inet6", &opt.inet6, cmd_boolean }, +#endif { "input", &opt.input_filename, cmd_file }, { "killlonger", &opt.kill_longer, cmd_boolean }, { "limitrate", &opt.limit_rate, cmd_bytes }, @@ -526,10 +531,18 @@ cmd_address (const char *com, const char *val, void *closure) { struct address_list *al; +#ifdef INET6 + struct addrinfo ai; + struct sockaddr_storage ss; + int slen; +#else struct sockaddr_in sin; +#endif struct sockaddr_in **target = (struct sockaddr_in **)closure; +#ifndef INET6 memset (&sin, '\0', sizeof (sin)); +#endif al = lookup_host (val, 1); if (!al) @@ -538,16 +551,29 @@ exec_name, com, val); return 0; } +#ifdef INET6 + address_list_copy_one (al, 0, (unsigned char *)&ai); + slen = ai.ai_addrlen; + memcpy (&ss, ai.ai_addr, slen); +#else address_list_copy_one (al, 0, (unsigned char *)&sin.sin_addr); +#endif address_list_release (al); +#ifndef INET6 sin.sin_family = AF_INET; sin.sin_port = 0; +#endif FREE_MAYBE (*target); +#ifdef INET6 + *target = xmalloc (sizeof (ss)); + memcpy (*target, &ss, slen); +#else *target = xmalloc (sizeof (sin)); memcpy (*target, &sin, sizeof (sin)); +#endif return 1; } diff -ur wget-1.8.1.orig/src/main.c wget-1.8.1/src/main.c --- wget-1.8.1.orig/src/main.c Mon Dec 10 14:31:44 2001 +++ wget-1.8.1/src/main.c Tue Feb 19 02:41:12 2002 @@ -171,6 +171,12 @@ -Q, --quota=NUMBER set retrieval quota to NUMBER.\n\ --limit-rate=RATE limit download rate to RATE.\n\ \n"), stdout); +#ifdef INET6 + fputs (_("\ + --inet use IP version 4 socket.\n\ + --inet6 use IP version 6 socket.\n\ +\n"), stdout); +#endif /* INET6 */ fputs (_("\ Directories:\n\ -nd --no-directories don\'t create directories.\n\ @@ -256,6 +262,10 @@ { "help", no_argument, NULL, 'h' }, { "html-extension", no_argument, NULL, 'E' }, { "ignore-length", no_argument, NULL, 138 }, +#ifdef INET6 + { "inet", no_argument, NULL, '4' }, + { "inet6", no_argument, NULL, '6' }, +#endif { "mirror", no_argument, NULL, 'm' }, { "no-clobber", no_argument, NULL, 141 }, { "no-directories", no_argument, NULL, 147 }, @@ -407,6 +417,16 @@ case 165: setval ("randomwait", "on"); break; +#ifdef INET6 + case '4': + setval ("inet", "on"); + setval ("inet6", "off"); + break; + case '6': + setval ("inet6", "on"); + setval ("inet", "off"); + break; +#endif case 'b': setval ("background", "on"); break; @@ -703,6 +723,14 @@ print_usage (); exit (1); } +#ifdef INET6 + if (opt.inet && opt.inet6) + { + printf (_("Can't inet and inet6 be specified at the same time.\n")); + print_usage (); + exit (1); + } +#endif if (opt.timestamping && opt.noclobber) { printf (_("\ diff -ur wget-1.8.1.orig/src/options.h wget-1.8.1/src/options.h --- wget-1.8.1.orig/src/options.h Fri Nov 30 16:39:08 2001 +++ wget-1.8.1/src/options.h Tue Feb 19 02:49:40 2002 @@ -153,7 +153,14 @@ int page_requisites; /* Whether we need to download all files necessary to display a page properly. */ +#ifdef INET6 + int inet; + int inet6; + int conn_inet6; /* connect IPv6? */ + struct sockaddr_storage *bind_address; +#else struct sockaddr_in *bind_address; /* What local IP address to bind to. */ +#endif #ifdef HAVE_SSL char *sslcertfile; /* external client cert to use. */ diff -ur wget-1.8.1.orig/src/url.c wget-1.8.1/src/url.c --- wget-1.8.1.orig/src/url.c Sat Dec 15 00:45:59 2001 +++ wget-1.8.1/src/url.c Sun Jan 27 05:43:17 2002 @@ -111,7 +111,7 @@ RU, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */ 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */ 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */ - 0, 0, 0, U, U, U, U, 0, /* X Y Z [ \ ] ^ _ */ + 0, 0, 0, RU, U, RU, U, 0, /* X Y Z [ \ ] ^ _ */ U, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */ 0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */ 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */ @@ -528,6 +528,11 @@ memcpy (*user, str, len); (*user)[len] = '\0'; + if (*user) + decode_string (*user); + if (*passwd) + decode_string (*passwd); + return 1; } @@ -617,16 +622,20 @@ } static char *parse_errors[] = { -#define PE_NO_ERROR 0 +#define PE_NO_ERROR 0 "No error", -#define PE_UNSUPPORTED_SCHEME 1 +#define PE_UNSUPPORTED_SCHEME 1 "Unsupported scheme", -#define PE_EMPTY_HOST 2 +#define PE_EMPTY_HOST 2 "Empty host", -#define PE_BAD_PORT_NUMBER 3 +#define PE_BAD_PORT_NUMBER 3 "Bad port number", -#define PE_INVALID_USER_NAME 4 - "Invalid user name" +#define PE_INVALID_USER_NAME 4 + "Invalid user name", +#define PE_UNTERMINATED_IPV6_ADDRESS 5 + "Unterminated IPv6 numeric address", +#define PE_INVALID_IPV6_ADDRESS 6 + "Invalid char in IPv6 numeric address" }; #define SETERR(p, v) do { \ @@ -688,8 +697,45 @@ fragment_b = fragment_e = NULL; host_b = p; - p = strpbrk_or_eos (p, ":/;?#"); - host_e = p; + + if (*p == '[') + { + /* Support http://[::1]/ used by IPv6. */ + int invalid = 0; + ++p; + while (1) + { + char c = *p++; + switch (c) + { + case ']': + goto out; + case '\0': + SETERR (error, PE_UNTERMINATED_IPV6_ADDRESS); + return NULL; + case ':': case '.': + break; + default: + if (ISXDIGIT (c)) + break; + invalid = 1; + } + } + out: + if (invalid) + { + SETERR (error, PE_INVALID_IPV6_ADDRESS); + return NULL; + } + /* Don't include brackets in [host_b, host_p). */ + ++host_b; + host_e = p - 1; + } + else + { + p = strpbrk_or_eos (p, ":/;?#"); + host_e = p; + } if (host_b == host_e) { @@ -1575,6 +1621,37 @@ memcpy (constr + baselength, link, linklength); constr[baselength + linklength] = '\0'; } + else if (linklength > 1 && *link == '/' && *(link + 1) == '/') + { + /* LINK begins with "//" and so is a net path: we need to + replace everything after (and including) the double slash + with LINK. */ + + /* uri_merge("foo", "//new/bar") -> "//new/bar" */ + /* uri_merge("//old/foo", "//new/bar") -> "//new/bar" */ + /* uri_merge("http://old/foo", "//new/bar") -> "http://new/bar" */ + + int span; + const char *slash; + const char *start_insert; + + /* Look for first slash. */ + slash = memchr (base, '/', end - base); + /* If found slash and it is a double slash, then replace + from this point, else default to replacing from the + beginning. */ + if (slash && *(slash + 1) == '/') + start_insert = slash; + else + start_insert = base; + + span = start_insert - base; + constr = (char *)xmalloc (span + linklength + 1); + if (span) + memcpy (constr, base, span); + memcpy (constr + span, link, linklength); + constr[span + linklength] = '\0'; + } else if (*link == '/') { /* LINK is an absolute path: we need to replace everything @@ -1734,6 +1811,8 @@ char *scheme_str = supported_schemes[url->scheme].leading_string; int fplen = full_path_length (url); + int brackets_around_host = 0; + assert (scheme_str != NULL); /* Make sure the user name and password are quoted. */ @@ -1749,8 +1828,12 @@ } } + if (strchr (url->host, ':')) + brackets_around_host = 1; + size = (strlen (scheme_str) + strlen (url->host) + + (brackets_around_host ? 2 : 0) + fplen + 1); if (url->port != scheme_port) @@ -1776,7 +1859,11 @@ *p++ = '@'; } + if (brackets_around_host) + *p++ = '['; APPEND (p, url->host); + if (brackets_around_host) + *p++ = ']'; if (url->port != scheme_port) { *p++ = ':'; --- wget-1.8.2/configure.in.orig Wed Jun 5 20:57:48 2002 +++ wget-1.8.2/configure.in Wed Jun 5 21:02:38 2002 @@ -74,6 +74,11 @@ DEBUG=$enableval, DEBUG=yes) test x"${DEBUG}" = xyes && AC_DEFINE(DEBUG,,[Support for debugging output]) +AC_ARG_ENABLE(ipv6, +[ --enable-ipv6 enable IPv6 support], +INET6=$enableval, INET6=yes) +test x"${INET6}" = xyes && AC_DEFINE(INET6,,[IPv6 support]) + wget_need_md5=no case "${USE_OPIE}${USE_DIGEST}" in --- wget-1.8.2/po/pl.po.orig Sun May 19 05:18:59 2002 +++ wget-1.8.2/po/pl.po Wed Jun 5 21:07:23 2002 @@ -1227,3 +1227,29 @@ #, c-format msgid "Failed to unlink symlink `%s': %s\n" msgstr "Nie udało się usun±ć dowi±zania symbolicznego `%s': %s\n" + +#: src/ftp.c:529 +msgid "Cannot initiate EPSV transfer.\n" +msgstr "Nie można rozpocz±ć transferu EPSV.\n" + +#: src/ftp.c:533 +msgid "Cannot parse EPSV response.\n" +msgstr "Nie powiodła się analiza odpowiedzi EPSV.\n" + +#: src/ftp.c:666 +msgid "Invalid EPRT.\n" +msgstr "Błędny EPRT.\n" + +#: src/main.c:185 +msgid "" +" --inet use IP version 4 socket.\n" +" --inet6 use IP version 6 socket.\n" +"\n" +msgstr "" +" --inet używa gniazd IP w wersji 4.\n" +" --inet6 używa gniazd IP w wersji 6.\n" +"\n" + +#: src/main.c:739 +msgid "Can't inet and inet6 be specified at the same time.\n" +msgstr "Opcje inet i inet6 nie mog± być podane jednocze¶nie.\n"