]> git.pld-linux.org Git - packages/wget.git/blame - wget-ipv6.patch
- real update for 1.10.1
[packages/wget.git] / wget-ipv6.patch
CommitLineData
65f0aada
JB
1diff -ur wget-1.8.1.orig/src/connect.c wget-1.8.1/src/connect.c
2--- wget-1.8.1.orig/src/connect.c Tue Nov 27 23:55:40 2001
3+++ wget-1.8.1/src/connect.c Tue Feb 19 03:02:05 2002
4@@ -78,17 +78,49 @@
5 int
6 connect_to_one (const unsigned char *addr, unsigned short port, int silent)
7 {
8+#ifdef INET6
9+ struct addrinfo hints, *res;
10+ struct sockaddr_storage sock_name;
11+ char portstr[NI_MAXSERV];
12+ int err;
13+#else
14 struct sockaddr_in sock_name;
15- int sock, save_errno;
16+#endif
17+ int sock, save_errno, salen;
18
19 /* Set port and protocol */
20+#ifdef INET6
21+ memset(&hints, 0, sizeof(hints));
22+ hints.ai_family = PF_UNSPEC;
23+ hints.ai_socktype = SOCK_STREAM;
24+ hints.ai_flags = AI_NUMERICHOST;
25+ snprintf(portstr, sizeof(portstr), "%d", port);
26+ err = getaddrinfo(addr, portstr, &hints, &res);
27+ if (err)
28+ {
29+ if (!silent)
30+ logprintf (LOG_VERBOSE, "getaddrinfo: %s.\n", gai_strerror (err));
31+ return -1;
32+ }
33+ memset (&sock_name, 0, sizeof (sock_name));
34+ memcpy (&sock_name, res->ai_addr, res->ai_addrlen);
35+ salen = res->ai_addrlen;
36+ freeaddrinfo (res);
37+#else
38 sock_name.sin_family = AF_INET;
39 sock_name.sin_port = htons (port);
40 memcpy ((unsigned char *)&sock_name.sin_addr, addr, 4);
41+ salen = sizeof (sock_name);
42+#endif
43
44 if (!silent)
45 {
46+#ifdef INET6
47+ char pretty_addr[INET6_ADDRSTRLEN];
48+ pretty_print_address_sa (&sock_name, salen, pretty_addr);
49+#else
50 char *pretty_addr = pretty_print_address (addr);
51+#endif
52 if (connection_host_name
53 && 0 != strcmp (connection_host_name, pretty_addr))
54 logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "),
55@@ -99,26 +131,29 @@
56 }
57
58 /* Make an internet socket, stream type. */
59- sock = socket (AF_INET, SOCK_STREAM, 0);
60+ sock = socket (((struct sockaddr *)&sock_name)->sa_family, SOCK_STREAM, 0);
61 if (sock < 0)
62 goto out;
63
64 if (opt.bind_address)
65 {
66 /* Bind the client side to the requested address. */
67- if (bind (sock, (struct sockaddr *)opt.bind_address,
68- sizeof (*opt.bind_address)))
69+ if (bind (sock, (struct sockaddr *)opt.bind_address, salen))
70 {
71- close (sock);
72+ save_errno = errno;
73+ CLOSE (sock);
74+ errno = save_errno;
75 sock = -1;
76 goto out;
77 }
78 }
79
80 /* Connect the socket to the remote host. */
81- if (connect (sock, (struct sockaddr *)&sock_name, sizeof (sock_name)) < 0)
82+ if (connect (sock, (struct sockaddr *)&sock_name, salen) < 0)
83 {
84- close (sock);
85+ save_errno = errno;
86+ CLOSE (sock);
87+ errno = save_errno;
88 sock = -1;
89 goto out;
90 }
91@@ -130,6 +165,10 @@
92 if (!silent)
93 logprintf (LOG_VERBOSE, _("connected.\n"));
94 DEBUGP (("Created socket %d.\n", sock));
95+#ifdef INET6
96+ opt.conn_inet6 = ((struct sockaddr *)&sock_name)->sa_family == AF_INET6 ?
97+ 1 : 0;
98+#endif
99 }
100 else
101 {
102@@ -151,10 +190,28 @@
103 address_list_get_bounds (al, &start, &end);
104 for (i = start; i < end; i++)
105 {
106+#ifdef INET6
107+ struct addrinfo ai;
108+ unsigned char *addr = (unsigned char *)&ai;
109+ char hbuf[INET6_ADDRSTRLEN];
110+ int err;
111+#else
112 unsigned char addr[4];
113+#endif
114 int sock;
115 address_list_copy_one (al, i, addr);
116
117+#ifdef INET6
118+ err = getnameinfo(ai.ai_addr, ai.ai_addrlen, hbuf, sizeof (hbuf),
119+ NULL, 0, NI_NUMERICHOST);
120+ if (err)
121+ {
122+ if (!silent)
123+ logprintf (LOG_VERBOSE, "getnameinfo: %s.\n", gai_strerror (err));
124+ continue;
125+ }
126+ addr = (unsigned char *)hbuf;
127+#endif
128 sock = connect_to_one (addr, port, silent);
129 if (sock >= 0)
130 /* Success. */
131@@ -207,14 +264,27 @@
132 internal variable MPORT is set to the value of the ensuing master
133 socket. Call acceptport() to block for and accept a connection. */
134 uerr_t
135-bindport (unsigned short *port)
136+bindport_af (unsigned short *port, int af)
137 {
138 int optval = 1;
139+#ifdef INET6
140+ static struct sockaddr_storage srv;
141+#else
142 static struct sockaddr_in srv;
143+#endif
144+ int alen;
145
146 msock = -1;
147 addr = (struct sockaddr *) &srv;
148- if ((msock = socket (AF_INET, SOCK_STREAM, 0)) < 0)
149+ if (af == AF_INET)
150+ alen = sizeof (struct sockaddr_in);
151+#ifdef INET6
152+ else if (af == AF_INET6)
153+ alen = sizeof (struct sockaddr_in6);
154+#endif
155+ else
156+ return CONSOCKERR;
157+ if ((msock = socket (af, SOCK_STREAM, 0)) < 0)
158 return CONSOCKERR;
159 if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR,
160 (char *)&optval, sizeof (optval)) < 0)
161@@ -222,14 +292,18 @@
162
163 if (opt.bind_address == NULL)
164 {
165- srv.sin_family = AF_INET;
166+ memset (&srv, 0, sizeof (srv));
167+ ((struct sockaddr *)&srv)->sa_family = af;
168+ /* in6addr_any : all 0 */
169+#ifndef INET6
170 srv.sin_addr.s_addr = htonl (INADDR_ANY);
171+#endif
172 }
173 else
174 srv = *opt.bind_address;
175
176- srv.sin_port = htons (*port);
177- if (bind (msock, addr, sizeof (struct sockaddr_in)) < 0)
178+ ((struct sockaddr_in *)&srv)->sin_port = htons (*port); /* same sin6 */
179+ if (bind (msock, addr, alen) < 0)
180 {
181 CLOSE (msock);
182 msock = -1;
183@@ -241,14 +315,14 @@
184 /* #### addrlen should be a 32-bit type, which int is not
185 guaranteed to be. Oh, and don't try to make it a size_t,
186 because that can be 64-bit. */
187- int addrlen = sizeof (struct sockaddr_in);
188+ int addrlen = sizeof (srv);
189 if (getsockname (msock, addr, &addrlen) < 0)
190 {
191 CLOSE (msock);
192 msock = -1;
193 return CONPORTERR;
194 }
195- *port = ntohs (srv.sin_port);
196+ *port = ntohs (((struct sockaddr_in *)addr)->sin_port); /* same sin6 */
197 }
198 if (listen (msock, 1) < 0)
199 {
200@@ -257,6 +331,12 @@
201 return LISTENERR;
202 }
203 return BINDOK;
204+}
205+
206+uerr_t
207+bindport (unsigned short *port)
208+{
209+ return bindport_af (port, AF_INET);
210 }
211
212 #ifdef HAVE_SELECT
213diff -ur wget-1.8.1.orig/src/connect.h wget-1.8.1/src/connect.h
214--- wget-1.8.1.orig/src/connect.h Fri Nov 30 03:22:18 2001
215+++ wget-1.8.1/src/connect.h Mon Feb 11 23:53:31 2002
216@@ -30,6 +30,7 @@
217
218 int test_socket_open PARAMS ((int));
219 int select_fd PARAMS ((int, int, int));
220+uerr_t bindport_af PARAMS ((unsigned short *, int));
221 uerr_t bindport PARAMS ((unsigned short *));
222 uerr_t acceptport PARAMS ((int *));
223 void closeport PARAMS ((int));
224diff -ur wget-1.8.1.orig/src/ftp-basic.c wget-1.8.1/src/ftp-basic.c
225--- wget-1.8.1.orig/src/ftp-basic.c Mon Dec 10 11:29:11 2001
226+++ wget-1.8.1/src/ftp-basic.c Tue Feb 19 00:29:13 2002
227@@ -35,7 +35,12 @@
228
229 #ifdef WINDOWS
230 # include <winsock.h>
231+#else
232+#include <sys/socket.h>
233+#include <netinet/in.h>
234+#include <netdb.h>
235 #endif
236+#include <limits.h>
237
238 #include "wget.h"
239 #include "utils.h"
240@@ -340,6 +345,137 @@
241 xfree (respline);
242 return FTPOK;
243 }
244+
245+#ifdef INET6
246+/* Bind a port and send the appropriate EPRT command to the FTP
247+ server. Use acceptport after RETR, to get the socket of data
248+ connection. */
249+uerr_t
250+ftp_eprt (struct rbuf *rbuf)
251+{
252+ uerr_t err;
253+ char *request, *respline, *bytes;
254+ int nwritten;
255+ unsigned short port;
256+ struct sockaddr_storage ss;
257+ int sslen;
258+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
259+ int af;
260+
261+ /* Get the address of this side of the connection. */
262+ sslen = sizeof(ss);
263+ if (getsockname(RBUF_FD (rbuf), (struct sockaddr *)&ss, &sslen) < 0)
264+ return HOSTERR;
265+ /* Construct the argument of EPRT. */
266+ if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf),
267+ NULL, 0, NI_NUMERICHOST) != 0)
268+ return HOSTERR;
269+ /* Setting port to 0 lets the system choose a free port. */
270+ port = 0;
271+ /* Bind the port. */
272+ err = bindport_af (&port, ((struct sockaddr *)&ss)->sa_family);
273+ if (err != BINDOK)
274+ return err;
275+ sprintf(pbuf, "%u", port);
276+ af = ((struct sockaddr *)&ss)->sa_family == AF_INET6 ? 2 : 1;
277+ bytes = (char *)alloca (1 + strlen(hbuf) + strlen(pbuf) + 4 + 1);
278+ sprintf (bytes, "|%d|%s|%s|", af, hbuf, pbuf);
279+ /* Send EPRT request. */
280+ request = ftp_request ("EPRT", bytes);
281+ nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
282+ if (nwritten < 0)
283+ {
284+ free (request);
285+ return WRITEFAILED;
286+ }
287+ free (request);
288+ /* Get appropriate response. */
289+ err = ftp_response (rbuf, &respline);
290+ if (err != FTPOK)
291+ {
292+ free (respline);
293+ return err;
294+ }
295+ if (*respline != '2')
296+ {
297+ free (respline);
298+ return FTPPORTERR;
299+ }
300+ free (respline);
301+ return FTPOK;
302+}
303+
304+/* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
305+ transfer. Reads the response from server and parses it. Reads the
306+ host and port addresses and returns them. */
307+uerr_t
308+ftp_epsv (struct rbuf *rbuf, char *hbuf, unsigned short *pport)
309+{
310+ char *request, *respline, *s, *ep, delim;
311+ long rcv;
312+ int nwritten;
313+ uerr_t err;
314+ struct sockaddr_storage ss;
315+ int sslen = sizeof(ss);
316+
317+ if (getpeername(RBUF_FD (rbuf), (struct sockaddr *)&ss, &sslen) < 0)
318+ return HOSTERR;
319+ if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, INET6_ADDRSTRLEN,
320+ NULL, 0, NI_NUMERICHOST) != 0)
321+ return HOSTERR;
322+
323+ /* Form the request. */
324+ request = ftp_request ("EPSV", NULL);
325+ /* And send it. */
326+ nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
327+ if (nwritten < 0)
328+ {
329+ free (request);
330+ return WRITEFAILED;
331+ }
332+ free (request);
333+ /* Get the server response. */
334+ err = ftp_response (rbuf, &respline);
335+ if (err != FTPOK)
336+ goto fin;
337+ if (strncmp(respline, "229", 3) != 0)
338+ {
339+ err = FTPNOPASV;
340+ goto fin;
341+ }
342+ /* Parse the request. */
343+ s = respline;
344+ for (s += 4; *s && *s != '('; s++);
345+ if (!*s)
346+ {
347+ err = FTPINVPASV;
348+ goto fin;
349+ }
350+ s++;
351+ if (s[0] && s[0] == s[1] && s[0] == s[2])
352+ {
353+ delim = s[0];
354+ s += 3;
355+ }
356+ else
357+ {
358+ err = FTPINVPASV;
359+ goto fin;
360+ }
361+ rcv = strtol (s, &ep, 10);
362+ if (rcv <= 0 || rcv > USHRT_MAX || *ep != delim)
363+ {
364+ err = FTPINVPASV;
365+ goto fin;
366+ }
367+ *pport = (unsigned short)rcv;
368+ err = FTPOK;
369+
370+fin:
371+ free (respline);
372+ return err;
373+}
374+#endif
375
376 /* Sends the TYPE request to the server. */
377 uerr_t
378diff -ur wget-1.8.1.orig/src/ftp.c wget-1.8.1/src/ftp.c
379--- wget-1.8.1.orig/src/ftp.c Tue Dec 4 02:22:05 2001
380+++ wget-1.8.1/src/ftp.c Tue Feb 19 03:35:12 2002
381@@ -33,6 +33,9 @@
382 #include <sys/types.h>
383 #include <assert.h>
384 #include <errno.h>
385+#include <sys/socket.h>
386+#include <netinet/in.h>
387+#include <arpa/inet.h>
388
389 #include "wget.h"
390 #include "utils.h"
391@@ -489,6 +492,54 @@
392 {
393 if (opt.ftp_pasv > 0)
394 {
395+ unsigned short tport;
396+#ifdef INET6
397+ char thost[64];
398+
399+ if (!opt.conn_inet6)
400+ goto noepsv;
401+ if (!opt.server_response)
402+ logputs (LOG_VERBOSE, "==> EPSV ... ");
403+ err = ftp_epsv (&con->rbuf, thost, &tport);
404+ /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV, HOSTERR */
405+ switch (err)
406+ {
407+ case FTPRERR:
408+ logputs (LOG_VERBOSE, "\n");
409+ logputs (LOG_NOTQUIET, _("\
410+Error in server response, closing control connection.\n"));
411+ break;
412+ case WRITEFAILED:
413+ logputs (LOG_VERBOSE, "\n");
414+ logputs (LOG_NOTQUIET,
415+ _("Write failed, closing control connection.\n"));
416+ break;
417+ case FTPNOPASV:
418+ logputs (LOG_VERBOSE, "\n");
419+ logputs (LOG_NOTQUIET, _("Cannot initiate EPSV transfer.\n"));
420+ goto tryeprt;
421+ case FTPINVPASV:
422+ logputs (LOG_VERBOSE, "\n");
423+ logputs (LOG_NOTQUIET, _("Cannot parse EPSV response.\n"));
424+ goto tryeprt;
425+ case HOSTERR:
426+ logputs (LOG_VERBOSE, "\n");
427+ logprintf (LOG_NOTQUIET, "%s: error\n", u->host);
428+ break;
429+ case FTPOK:
430+ /* fine and dandy */
431+ inet_aton(thost, (struct in_addr *)pasv_addr);
432+ goto pasvok;
433+ default:
434+ abort ();
435+ break;
436+ }
437+ CLOSE (csock);
438+ rbuf_uninitialize (&con->rbuf);
439+ return err;
440+
441+ noepsv:
442+#endif
443 if (!opt.server_response)
444 logputs (LOG_VERBOSE, "==> PASV ... ");
445 err = ftp_pasv (&con->rbuf, pasv_addr);
446@@ -528,10 +579,17 @@
447 }
448 if (err==FTPOK)
449 {
450- unsigned short tport;
451-
452+#ifdef INET6
453+ inet_ntop (AF_INET, pasv_addr, thost, sizeof (thost));
454+#endif
455 tport = (pasv_addr[4] << 8) + pasv_addr[5];
456+
457+#ifdef INET6
458+ pasvok:
459+ dtsock = connect_to_one (thost, tport, 1);
460+#else
461 dtsock = connect_to_one (pasv_addr, tport, 1);
462+#endif
463
464 if (dtsock < 0)
465 {
466@@ -539,7 +597,11 @@
467 CLOSE (csock);
468 rbuf_uninitialize (&con->rbuf);
469 logprintf (LOG_VERBOSE, _("couldn't connect to %s:%hu: %s\n"),
470+#ifdef INET6
471+ thost, tport,
472+#else
473 pretty_print_address (pasv_addr), tport,
474+#endif
475 strerror (save_errno));
476 return save_errno == ECONNREFUSED ? CONREFUSED : CONERROR;
477 }
478@@ -552,6 +614,61 @@
479
480 if (!passive_mode_open) /* Try to use a port command if PASV failed */
481 {
482+#ifdef INET6
483+ if (!opt.conn_inet6)
484+ goto noeprt;
485+ tryeprt:
486+ if (!opt.server_response)
487+ logputs (LOG_VERBOSE, "==> EPRT ... ");
488+ err = ftp_eprt (&con->rbuf);
489+ /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
490+ LISTENERR), HOSTERR, FTPPORTERR */
491+ switch (err)
492+ {
493+ case FTPRERR:
494+ logputs (LOG_VERBOSE, "\n");
495+ logputs (LOG_NOTQUIET, _("\
496+Error in server response, closing control connection.\n"));
497+ break;
498+ case WRITEFAILED:
499+ logputs (LOG_VERBOSE, "\n");
500+ logputs (LOG_NOTQUIET,
501+ _("Write failed, closing control connection.\n"));
502+ break;
503+ case CONSOCKERR:
504+ logputs (LOG_VERBOSE, "\n");
505+ logprintf (LOG_NOTQUIET, "socket: %s\n", strerror (errno));
506+ break;
507+ case CONPORTERR: case BINDERR: case LISTENERR:
508+ /* What now? These problems are local... */
509+ logputs (LOG_VERBOSE, "\n");
510+ logprintf (LOG_NOTQUIET, _("Bind error (%s).\n"),
511+ strerror (errno));
512+ closeport (dtsock);
513+ return err;
514+ break;
515+ case HOSTERR:
516+ logputs (LOG_VERBOSE, "\n");
517+ logprintf (LOG_NOTQUIET, "%s: error\n", u->host);
518+ break;
519+ case FTPPORTERR:
520+ logputs (LOG_VERBOSE, "\n");
521+ logputs (LOG_NOTQUIET, _("Invalid EPRT.\n"));
522+ break;
523+ case FTPOK:
524+ /* fine and dandy */
525+ goto portok;
526+ default:
527+ abort ();
528+ break;
529+ } /* eprt switch */
530+ CLOSE (csock);
531+ closeport (dtsock);
532+ rbuf_uninitialize (&con->rbuf);
533+ return err;
534+
535+ noeprt:
536+#endif
537 if (!opt.server_response)
538 logputs (LOG_VERBOSE, "==> PORT ... ");
539 err = ftp_port (&con->rbuf);
540@@ -608,6 +725,9 @@
541 abort ();
542 break;
543 } /* port switch */
544+#ifdef INET6
545+ portok:
546+#endif
547 if (!opt.server_response)
548 logputs (LOG_VERBOSE, _("done. "));
549 } /* dtsock == -1 */
550diff -ur wget-1.8.1.orig/src/ftp.h wget-1.8.1/src/ftp.h
551--- wget-1.8.1.orig/src/ftp.h Thu Nov 22 09:24:27 2001
552+++ wget-1.8.1/src/ftp.h Tue Feb 19 00:32:35 2002
553@@ -37,6 +37,10 @@
554 uerr_t ftp_login PARAMS ((struct rbuf *, const char *, const char *));
555 uerr_t ftp_port PARAMS ((struct rbuf *));
556 uerr_t ftp_pasv PARAMS ((struct rbuf *, unsigned char *));
557+#ifdef INET6
558+uerr_t ftp_eprt PARAMS ((struct rbuf *));
559+uerr_t ftp_epsv PARAMS ((struct rbuf *, char *, unsigned short *));
560+#endif
561 uerr_t ftp_type PARAMS ((struct rbuf *, int));
562 uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *));
563 uerr_t ftp_retr PARAMS ((struct rbuf *, const char *));
564diff -ur wget-1.8.1.orig/src/host.c wget-1.8.1/src/host.c
565--- wget-1.8.1.orig/src/host.c Tue Dec 11 17:32:57 2001
566+++ wget-1.8.1/src/host.c Wed Feb 13 04:14:11 2002
567@@ -77,7 +77,11 @@
568
569 struct address_list {
570 int count; /* number of adrresses */
571+#ifdef INET6
572+ struct addrinfo *addresses;
573+#else
574 ipv4_address *addresses; /* pointer to the string of addresses */
575+#endif
576
577 int faulty; /* number of addresses known not to
578 work. */
579@@ -100,8 +104,17 @@
580 address_list_copy_one (struct address_list *al, int index,
581 unsigned char *ip_store)
582 {
583+#ifdef INET6
584+ struct addrinfo *ai;
585+ assert (index >= al->faulty && index < al->count);
586+ for (ai = al->addresses; ai; ai = ai->ai_next, index--)
587+ if (index <= 0)
588+ break;
589+ memcpy (ip_store, ai, sizeof (*ai));
590+#else
591 assert (index >= al->faulty && index < al->count);
592 memcpy (ip_store, al->addresses + index, sizeof (ipv4_address));
593+#endif
594 }
595
596 /* Check whether two address lists have all their IPs in common. */
597@@ -109,12 +122,27 @@
598 int
599 address_list_match_all (struct address_list *al1, struct address_list *al2)
600 {
601+#ifdef INET6
602+ struct addrinfo *ai1, *ai2;
603+#endif
604 if (al1 == al2)
605 return 1;
606 if (al1->count != al2->count)
607 return 0;
608+#ifdef INET6
609+ for (ai1 = al1->addresses, ai2 = al2->addresses; ai1;
610+ ai1 = ai1->ai_next, ai2 = ai2->ai_next)
611+ {
612+ if (ai1->ai_addrlen != ai2->ai_addrlen)
613+ return 0;
614+ if (memcmp (ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen))
615+ return 0;
616+ }
617+ return 1;
618+#else
619 return 0 == memcmp (al1->addresses, al2->addresses,
620 al1->count * sizeof (ipv4_address));
621+#endif
622 }
623
624 /* Mark the INDEXth element of AL as faulty, so that the next time
625@@ -141,26 +169,44 @@
626 as returned by gethostbyname. */
627
628 static struct address_list *
629+#ifdef INET6
630+address_list_new (struct addrinfo *ai)
631+{
632+ struct addrinfo *res;
633+#else
634 address_list_new (char **h_addr_list)
635 {
636- int count = 0, i;
637+ int i;
638+#endif
639+ int count = 0;
640
641 struct address_list *al = xmalloc (sizeof (struct address_list));
642
643+#ifdef INET6
644+ for (res = ai; res; res = res->ai_next)
645+#else
646 while (h_addr_list[count])
647+#endif
648 ++count;
649 assert (count > 0);
650 al->count = count;
651 al->faulty = 0;
652+#ifdef INET6
653+ al->addresses = ai;
654+#else
655 al->addresses = xmalloc (count * sizeof (ipv4_address));
656+#endif
657 al->refcount = 1;
658
659+#ifndef INET6
660 for (i = 0; i < count; i++)
661 memcpy (al->addresses + i, h_addr_list[i], sizeof (ipv4_address));
662+#endif
663
664 return al;
665 }
666
667+#ifndef INET6
668 /* Like address_list_new, but initialized with only one address. */
669
670 static struct address_list *
671@@ -175,11 +221,16 @@
672
673 return al;
674 }
675+#endif
676
677 static void
678 address_list_delete (struct address_list *al)
679 {
680+#ifdef INET6
681+ freeaddrinfo (al->addresses);
682+#else
683 xfree (al->addresses);
684+#endif
685 xfree (al);
686 }
687
688@@ -203,6 +254,17 @@
689 {
690 return inet_ntoa (*(struct in_addr *)addr);
691 }
692+#ifdef INET6
693+int
694+pretty_print_address_sa (const void *addr, int alen, char *abuf)
695+{
696+ int err = getnameinfo((struct sockaddr *)addr, alen, abuf, INET6_ADDRSTRLEN,
697+ NULL, 0, NI_NUMERICHOST);
698+ if (err)
699+ strcpy (abuf, "???");
700+ return err;
701+}
702+#endif
703
704 /* Add host name HOST with the address ADDR_TEXT to the cache.
705 ADDR_LIST is a NULL-terminated list of addresses, as in struct
706@@ -220,10 +282,23 @@
707 #ifdef DEBUG
708 if (opt.debug)
709 {
710+#ifdef INET6
711+ struct addrinfo *ai;
712+#else
713 int i;
714+#endif
715 debug_logprintf ("Caching %s =>", host);
716+#ifdef INET6
717+ for (ai = al->addresses; ai; ai = ai->ai_next)
718+ {
719+ char hbuf[INET6_ADDRSTRLEN];
720+ pretty_print_address_sa (ai->ai_addr, ai->ai_addrlen, hbuf);
721+ debug_logprintf (" %s", hbuf);
722+ }
723+#else
724 for (i = 0; i < al->count; i++)
725 debug_logprintf (" %s", pretty_print_address (al->addresses + i));
726+#endif
727 debug_logprintf ("\n");
728 }
729 #endif
730@@ -233,6 +308,24 @@
731 lookup_host (const char *host, int silent)
732 {
733 struct address_list *al = NULL;
734+#ifdef INET6
735+ struct addrinfo hints, *res;
736+ int error;
737+
738+ memset(&hints, 0, sizeof(hints));
739+ if (opt.inet)
740+ hints.ai_family = AF_INET;
741+ else if (opt.inet6)
742+ hints.ai_family = AF_INET6;
743+ else
744+ hints.ai_family = AF_UNSPEC;
745+ hints.ai_socktype = SOCK_STREAM;
746+ hints.ai_flags = AI_NUMERICHOST;
747+ /* check `N.N.N.N' or 'X:X:X:X:X:X:X:X'. */
748+ if (!getaddrinfo(host, NULL, &hints, &res))
749+ return address_list_new (res);
750+
751+#else
752 unsigned long addr;
753 struct hostent *hptr;
754
755@@ -254,6 +347,7 @@
756 #endif
757 return address_list_new_one ((char *)&addr + offset);
758 }
759+#endif /* INET6 */
760
761 /* By now we know that the host name we got is not of the form
762 d.d.d.d. Try to find it in our cache of host names. */
763@@ -270,12 +364,29 @@
764 if (!silent)
765 logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
766
767+#ifdef INET6
768+ memset(&hints, 0, sizeof(hints));
769+ if (opt.inet)
770+ hints.ai_family = AF_INET;
771+ else if (opt.inet6)
772+ hints.ai_family = AF_INET6;
773+ else
774+ hints.ai_family = AF_UNSPEC;
775+ hints.ai_socktype = SOCK_STREAM;
776+ error = getaddrinfo(host, NULL, &hints, &res);
777+ if (error)
778+#else
779 /* Look up the host using gethostbyname(). */
780 hptr = gethostbyname (host);
781 if (!hptr)
782+#endif
783 {
784 if (!silent)
785+#ifdef INET6
786+ logprintf (LOG_VERBOSE, _("failed: %s.\n"), gai_strerror(error));
787+#else
788 logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
789+#endif
790 return NULL;
791 }
792
793@@ -284,7 +395,11 @@
794
795 /* Do all systems have h_addr_list, or is it a newer thing? If the
796 latter, use address_list_new_one. */
797+#ifdef INET6
798+ al = address_list_new (res);
799+#else
800 al = address_list_new (hptr->h_addr_list);
801+#endif
802
803 /* Cache the lookup information. */
804 cache_host_lookup (host, al);
805diff -ur wget-1.8.1.orig/src/host.h wget-1.8.1/src/host.h
806--- wget-1.8.1.orig/src/host.h Tue Dec 11 17:32:58 2001
807+++ wget-1.8.1/src/host.h Wed Feb 13 00:14:42 2002
808@@ -38,6 +38,9 @@
809 /* This was originally going to be a macro, but then every caller
810 would have to #include the netinet stuff. */
811 char *pretty_print_address PARAMS ((const void *));
812+#ifdef INET6
813+int pretty_print_address_sa PARAMS ((const void *, int, char *));
814+#endif
815
816 int accept_domain PARAMS ((struct url *));
817 int sufmatch PARAMS ((const char **, const char *));
818diff -ur wget-1.8.1.orig/src/http.c wget-1.8.1/src/http.c
819--- wget-1.8.1.orig/src/http.c Fri Dec 14 01:46:56 2001
820+++ wget-1.8.1/src/http.c Sun Jan 27 08:19:10 2002
821@@ -559,6 +559,11 @@
822 /* Whether keep-alive should be inhibited. */
823 int inhibit_keep_alive;
824
825+ /* Whether we need to print the host header with braces around host,
826+ e.g. "Host: [3ffe:8100:200:2::2]:1234" instead of the usual
827+ "Host: symbolic-name:1234". */
828+ int squares_around_host = 0;
829+
830 #ifdef HAVE_SSL
831 /* initialize ssl_ctx on first run */
832 if (!ssl_ctx)
833@@ -811,6 +816,9 @@
834 "param=value", full_path will be "/foo/bar?param=value". */
835 full_path = url_full_path (u);
836
837+ if (strchr (u->host, ':'))
838+ squares_around_host = 1;
839+
840 /* Allocate the memory for the request. */
841 request = (char *)alloca (strlen (command)
842 + strlen (full_path)
843@@ -832,11 +840,12 @@
844 sprintf (request, "\
845 %s %s HTTP/1.0\r\n\
846 User-Agent: %s\r\n\
847-Host: %s%s\r\n\
848+Host: %s%s%s%s\r\n\
849 Accept: %s\r\n\
850 %s%s%s%s%s%s%s%s\r\n",
851 command, full_path,
852- useragent, u->host,
853+ useragent,
854+ squares_around_host ? "[" : "", u->host, squares_around_host ? "]" : "",
855 port_maybe ? port_maybe : "",
856 HTTP_ACCEPT,
857 request_keep_alive ? request_keep_alive : "",
858diff -ur wget-1.8.1.orig/src/init.c wget-1.8.1/src/init.c
859--- wget-1.8.1.orig/src/init.c Fri Dec 14 04:19:03 2001
860+++ wget-1.8.1/src/init.c Tue Feb 19 02:45:18 2002
861@@ -38,6 +38,7 @@
862 #else
863 # include <sys/socket.h>
864 # include <netinet/in.h>
865+# include <netdb.h>
866 #ifndef __BEOS__
867 # include <arpa/inet.h>
868 #endif
869@@ -142,6 +143,10 @@
870 { "ignorelength", &opt.ignore_length, cmd_boolean },
871 { "ignoretags", &opt.ignore_tags, cmd_vector },
872 { "includedirectories", &opt.includes, cmd_directory_vector },
873+#ifdef INET6
874+ { "inet", &opt.inet, cmd_boolean },
875+ { "inet6", &opt.inet6, cmd_boolean },
876+#endif
877 { "input", &opt.input_filename, cmd_file },
878 { "killlonger", &opt.kill_longer, cmd_boolean },
879 { "limitrate", &opt.limit_rate, cmd_bytes },
880@@ -526,10 +531,18 @@
881 cmd_address (const char *com, const char *val, void *closure)
882 {
883 struct address_list *al;
884+#ifdef INET6
885+ struct addrinfo ai;
886+ struct sockaddr_storage ss;
887+ int slen;
888+#else
889 struct sockaddr_in sin;
890+#endif
891 struct sockaddr_in **target = (struct sockaddr_in **)closure;
892
893+#ifndef INET6
894 memset (&sin, '\0', sizeof (sin));
895+#endif
896
897 al = lookup_host (val, 1);
898 if (!al)
899@@ -538,16 +551,29 @@
900 exec_name, com, val);
901 return 0;
902 }
903+#ifdef INET6
904+ address_list_copy_one (al, 0, (unsigned char *)&ai);
905+ slen = ai.ai_addrlen;
906+ memcpy (&ss, ai.ai_addr, slen);
907+#else
908 address_list_copy_one (al, 0, (unsigned char *)&sin.sin_addr);
909+#endif
910 address_list_release (al);
911
912+#ifndef INET6
913 sin.sin_family = AF_INET;
914 sin.sin_port = 0;
915+#endif
916
917 FREE_MAYBE (*target);
918
919+#ifdef INET6
920+ *target = xmalloc (sizeof (ss));
921+ memcpy (*target, &ss, slen);
922+#else
923 *target = xmalloc (sizeof (sin));
924 memcpy (*target, &sin, sizeof (sin));
925+#endif
926
927 return 1;
928 }
929diff -ur wget-1.8.1.orig/src/main.c wget-1.8.1/src/main.c
930--- wget-1.8.1.orig/src/main.c Mon Dec 10 14:31:44 2001
931+++ wget-1.8.1/src/main.c Tue Feb 19 02:41:12 2002
932@@ -171,6 +171,12 @@
933 -Q, --quota=NUMBER set retrieval quota to NUMBER.\n\
934 --limit-rate=RATE limit download rate to RATE.\n\
935 \n"), stdout);
936+#ifdef INET6
937+ fputs (_("\
938+ --inet use IP version 4 socket.\n\
939+ --inet6 use IP version 6 socket.\n\
940+\n"), stdout);
941+#endif /* INET6 */
942 fputs (_("\
943 Directories:\n\
944 -nd --no-directories don\'t create directories.\n\
945@@ -256,6 +262,10 @@
946 { "help", no_argument, NULL, 'h' },
947 { "html-extension", no_argument, NULL, 'E' },
948 { "ignore-length", no_argument, NULL, 138 },
949+#ifdef INET6
950+ { "inet", no_argument, NULL, '4' },
951+ { "inet6", no_argument, NULL, '6' },
952+#endif
953 { "mirror", no_argument, NULL, 'm' },
954 { "no-clobber", no_argument, NULL, 141 },
955 { "no-directories", no_argument, NULL, 147 },
956@@ -407,6 +417,16 @@
957 case 165:
958 setval ("randomwait", "on");
959 break;
960+#ifdef INET6
961+ case '4':
962+ setval ("inet", "on");
963+ setval ("inet6", "off");
964+ break;
965+ case '6':
966+ setval ("inet6", "on");
967+ setval ("inet", "off");
968+ break;
969+#endif
970 case 'b':
971 setval ("background", "on");
972 break;
973@@ -703,6 +723,14 @@
974 print_usage ();
975 exit (1);
976 }
977+#ifdef INET6
978+ if (opt.inet && opt.inet6)
979+ {
980+ printf (_("Can't inet and inet6 be specified at the same time.\n"));
981+ print_usage ();
982+ exit (1);
983+ }
984+#endif
985 if (opt.timestamping && opt.noclobber)
986 {
987 printf (_("\
988diff -ur wget-1.8.1.orig/src/options.h wget-1.8.1/src/options.h
989--- wget-1.8.1.orig/src/options.h Fri Nov 30 16:39:08 2001
990+++ wget-1.8.1/src/options.h Tue Feb 19 02:49:40 2002
991@@ -153,7 +153,14 @@
992 int page_requisites; /* Whether we need to download all files
993 necessary to display a page properly. */
994
995+#ifdef INET6
996+ int inet;
997+ int inet6;
998+ int conn_inet6; /* connect IPv6? */
999+ struct sockaddr_storage *bind_address;
1000+#else
1001 struct sockaddr_in *bind_address; /* What local IP address to bind to. */
1002+#endif
1003
1004 #ifdef HAVE_SSL
1005 char *sslcertfile; /* external client cert to use. */
1006diff -ur wget-1.8.1.orig/src/url.c wget-1.8.1/src/url.c
1007--- wget-1.8.1.orig/src/url.c Sat Dec 15 00:45:59 2001
1008+++ wget-1.8.1/src/url.c Sun Jan 27 05:43:17 2002
1009@@ -111,7 +111,7 @@
1010 RU, 0, 0, 0, 0, 0, 0, 0, /* @ A B C D E F G */
1011 0, 0, 0, 0, 0, 0, 0, 0, /* H I J K L M N O */
1012 0, 0, 0, 0, 0, 0, 0, 0, /* P Q R S T U V W */
1013- 0, 0, 0, U, U, U, U, 0, /* X Y Z [ \ ] ^ _ */
1014+ 0, 0, 0, RU, U, RU, U, 0, /* X Y Z [ \ ] ^ _ */
1015 U, 0, 0, 0, 0, 0, 0, 0, /* ` a b c d e f g */
1016 0, 0, 0, 0, 0, 0, 0, 0, /* h i j k l m n o */
1017 0, 0, 0, 0, 0, 0, 0, 0, /* p q r s t u v w */
1018@@ -528,6 +528,11 @@
1019 memcpy (*user, str, len);
1020 (*user)[len] = '\0';
1021
1022+ if (*user)
1023+ decode_string (*user);
1024+ if (*passwd)
1025+ decode_string (*passwd);
1026+
1027 return 1;
1028 }
1029
1030@@ -617,16 +622,20 @@
1031 }
1032
1033 static char *parse_errors[] = {
1034-#define PE_NO_ERROR 0
1035+#define PE_NO_ERROR 0
1036 "No error",
1037-#define PE_UNSUPPORTED_SCHEME 1
1038+#define PE_UNSUPPORTED_SCHEME 1
1039 "Unsupported scheme",
1040-#define PE_EMPTY_HOST 2
1041+#define PE_EMPTY_HOST 2
1042 "Empty host",
1043-#define PE_BAD_PORT_NUMBER 3
1044+#define PE_BAD_PORT_NUMBER 3
1045 "Bad port number",
1046-#define PE_INVALID_USER_NAME 4
1047- "Invalid user name"
1048+#define PE_INVALID_USER_NAME 4
1049+ "Invalid user name",
1050+#define PE_UNTERMINATED_IPV6_ADDRESS 5
1051+ "Unterminated IPv6 numeric address",
1052+#define PE_INVALID_IPV6_ADDRESS 6
1053+ "Invalid char in IPv6 numeric address"
1054 };
1055
1056 #define SETERR(p, v) do { \
1057@@ -688,8 +697,45 @@
1058 fragment_b = fragment_e = NULL;
1059
1060 host_b = p;
1061- p = strpbrk_or_eos (p, ":/;?#");
1062- host_e = p;
1063+
1064+ if (*p == '[')
1065+ {
1066+ /* Support http://[::1]/ used by IPv6. */
1067+ int invalid = 0;
1068+ ++p;
1069+ while (1)
1070+ {
1071+ char c = *p++;
1072+ switch (c)
1073+ {
1074+ case ']':
1075+ goto out;
1076+ case '\0':
1077+ SETERR (error, PE_UNTERMINATED_IPV6_ADDRESS);
1078+ return NULL;
1079+ case ':': case '.':
1080+ break;
1081+ default:
1082+ if (ISXDIGIT (c))
1083+ break;
1084+ invalid = 1;
1085+ }
1086+ }
1087+ out:
1088+ if (invalid)
1089+ {
1090+ SETERR (error, PE_INVALID_IPV6_ADDRESS);
1091+ return NULL;
1092+ }
1093+ /* Don't include brackets in [host_b, host_p). */
1094+ ++host_b;
1095+ host_e = p - 1;
1096+ }
1097+ else
1098+ {
1099+ p = strpbrk_or_eos (p, ":/;?#");
1100+ host_e = p;
1101+ }
1102
1103 if (host_b == host_e)
1104 {
1105@@ -1575,6 +1621,37 @@
1106 memcpy (constr + baselength, link, linklength);
1107 constr[baselength + linklength] = '\0';
1108 }
1109+ else if (linklength > 1 && *link == '/' && *(link + 1) == '/')
1110+ {
1111+ /* LINK begins with "//" and so is a net path: we need to
1112+ replace everything after (and including) the double slash
1113+ with LINK. */
1114+
1115+ /* uri_merge("foo", "//new/bar") -> "//new/bar" */
1116+ /* uri_merge("//old/foo", "//new/bar") -> "//new/bar" */
1117+ /* uri_merge("http://old/foo", "//new/bar") -> "http://new/bar" */
1118+
1119+ int span;
1120+ const char *slash;
1121+ const char *start_insert;
1122+
1123+ /* Look for first slash. */
1124+ slash = memchr (base, '/', end - base);
1125+ /* If found slash and it is a double slash, then replace
1126+ from this point, else default to replacing from the
1127+ beginning. */
1128+ if (slash && *(slash + 1) == '/')
1129+ start_insert = slash;
1130+ else
1131+ start_insert = base;
1132+
1133+ span = start_insert - base;
1134+ constr = (char *)xmalloc (span + linklength + 1);
1135+ if (span)
1136+ memcpy (constr, base, span);
1137+ memcpy (constr + span, link, linklength);
1138+ constr[span + linklength] = '\0';
1139+ }
1140 else if (*link == '/')
1141 {
1142 /* LINK is an absolute path: we need to replace everything
1143@@ -1734,6 +1811,8 @@
1144 char *scheme_str = supported_schemes[url->scheme].leading_string;
1145 int fplen = full_path_length (url);
1146
1147+ int brackets_around_host = 0;
1148+
1149 assert (scheme_str != NULL);
1150
1151 /* Make sure the user name and password are quoted. */
1152@@ -1749,8 +1828,12 @@
1153 }
1154 }
1155
1156+ if (strchr (url->host, ':'))
1157+ brackets_around_host = 1;
1158+
1159 size = (strlen (scheme_str)
1160 + strlen (url->host)
1161+ + (brackets_around_host ? 2 : 0)
1162 + fplen
1163 + 1);
1164 if (url->port != scheme_port)
1165@@ -1776,7 +1859,11 @@
1166 *p++ = '@';
1167 }
1168
1169+ if (brackets_around_host)
1170+ *p++ = '[';
1171 APPEND (p, url->host);
1172+ if (brackets_around_host)
1173+ *p++ = ']';
1174 if (url->port != scheme_port)
1175 {
1176 *p++ = ':';
1177--- wget-1.8.2/configure.in.orig Wed Jun 5 20:57:48 2002
1178+++ wget-1.8.2/configure.in Wed Jun 5 21:02:38 2002
1179@@ -74,6 +74,11 @@
1180 DEBUG=$enableval, DEBUG=yes)
1181 test x"${DEBUG}" = xyes && AC_DEFINE(DEBUG,,[Support for debugging output])
1182
1183+AC_ARG_ENABLE(ipv6,
1184+[ --enable-ipv6 enable IPv6 support],
1185+INET6=$enableval, INET6=yes)
1186+test x"${INET6}" = xyes && AC_DEFINE(INET6,,[IPv6 support])
1187+
1188 wget_need_md5=no
1189
1190 case "${USE_OPIE}${USE_DIGEST}" in
1191--- wget-1.8.2/po/pl.po.orig Sun May 19 05:18:59 2002
1192+++ wget-1.8.2/po/pl.po Wed Jun 5 21:07:23 2002
1193@@ -1227,3 +1227,29 @@
1194 #, c-format
1195 msgid "Failed to unlink symlink `%s': %s\n"
1196