$NetBSD: patch-aj,v 1.2 2000/01/15 22:55:48 hubertf Exp $

diff -x *.orig -urN ./WWW/Library/Implementation/HTFTP.c /usr/pkgsrc/www/lynx/work.unpatched/lynx2-8-2/WWW/Library/Implementation/HTFTP.c
--- ./WWW/Library/Implementation/HTFTP.c	Tue May 25 19:13:02 1999
+++ /usr/pkgsrc/www/lynx/work.unpatched/lynx2-8-2/WWW/Library/Implementation/HTFTP.c	Sat Jan 15 07:57:18 2000
@@ -1013,10 +1013,11 @@
 */
 PRIVATE int get_listen_socket NOARGS
 {
-    struct sockaddr_in soc_address;	/* Binary network address */
-    struct sockaddr_in* soc_in = &soc_address;
+    struct sockaddr_storage soc_address;	/* Binary network address */
+    struct sockaddr_in* soc_in = (struct sockaddr_in *)&soc_address;
     int new_socket;			/* Will be master_socket */
-
+    int af;
+    int slen;
 
     FD_ZERO(&open_sockets);	/* Clear our record of open sockets */
     num_sockets = 0;
@@ -1026,9 +1027,18 @@
 	return master_socket;  /* Done already */
 #endif /* !REPEAT_LISTEN */
 
+    /* query address family of control connection */
+    slen = sizeof(soc_address);
+    if (getsockname(control->socket, (struct sockaddr *)&soc_address,
+		&slen) < 0) {
+	return HTInetStatus("getsockname failed");
+    }
+    af = soc_address.ss_family;
+    memset(&soc_address, 0, sizeof(soc_address));
+
 /*  Create internet socket
 */
-    new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    new_socket = socket(af, SOCK_STREAM, IPPROTO_TCP);
 
     if (new_socket < 0)
 	return HTInetStatus(gettext("socket for master socket"));
@@ -1037,8 +1047,24 @@
 
 /*  Search for a free port.
 */
-    soc_in->sin_family = AF_INET;	    /* Family = internet, host order  */
-    soc_in->sin_addr.s_addr = INADDR_ANY;   /* Any peer address */
+    memset(&soc_address, 0, sizeof(soc_address));
+    soc_address.ss_family = af;
+    switch (af) {
+    case AF_INET:
+#ifdef SIN6_LEN
+	soc_address.ss_len = sizeof(struct sockaddr_in);
+#endif
+	break;
+#ifdef INET6
+    case AF_INET6:
+#ifdef SIN6_LEN
+	soc_address.ss_len = sizeof(struct sockaddr_in6);
+#endif
+	break;
+#endif
+    default:
+	HTInetStatus("AF");
+    }
 #ifdef POLL_PORTS
     {
 	unsigned short old_port_number = port_number;
@@ -1049,15 +1075,19 @@
 	    if (port_number == old_port_number) {
 		return HTInetStatus("bind");
 	    }
-	    soc_address.sin_port = htons(port_number);
+	    soc_in->sin_port = htons(port_number);
 #ifdef SOCKS
 	    if (socks_flag)
 		if ((status=Rbind(new_socket,
 			(struct sockaddr*)&soc_address,
 			    /* Cast to generic sockaddr */
-			sizeof(soc_address)
+#ifdef SIN6_LEN
+			soc_address.ss_len,
+#else
+			SA_LEN((struct sockaddr *)&soc_address),
+#endif
 #ifndef SHORTENED_RBIND
-			,socks_bind_remoteAddr
+			socks_bind_remoteAddr
 #endif /* !SHORTENED_RBIND */
 						)) == 0)
 		    break;
@@ -1066,7 +1096,12 @@
 	    if ((status=bind(new_socket,
 		    (struct sockaddr*)&soc_address,
 			    /* Cast to generic sockaddr */
-		    sizeof(soc_address))) == 0)
+#ifdef SIN6_LEN
+		    soc_address.ss_len
+#else
+		    SA_LEN((struct sockaddr *)&soc_address)
+#endif
+		    )) == 0)
 		break;
 	    CTRACE(tfp, "TCP bind attempt to port %d yields %d, errno=%d\n",
 		port_number, status, SOCKET_ERRNO);
@@ -1088,17 +1123,21 @@
 			     (void *)&address_length);
 	if (status<0) return HTInetStatus("getsockname");
 	CTRACE(tfp, "HTFTP: This host is %s\n",
-	    HTInetString(soc_in));
+	    HTInetString((SockA *)soc_in));
 
-	soc_address.sin_port = 0;	/* Unspecified: please allocate */
+	soc_in->sin_port = 0;	/* Unspecified: please allocate */
 #ifdef SOCKS
 	if (socks_flag)
 	    status=Rbind(new_socket,
 			 (struct sockaddr*)&soc_address,
 			 /* Cast to generic sockaddr */
-			 sizeof(soc_address)
+#ifdef SIN6_LEN
+			 soc_address.ss_len,
+#else
+			 SA_LEN((struct sockaddr *)&soc_address),
+#endif
 #ifndef SHORTENED_RBIND
-			,socks_bind_remoteAddr
+			socks_bind_remoteAddr
 #endif /* !SHORTENED_RBIND */
 						);
 	else
@@ -1106,7 +1145,12 @@
 	status=bind(new_socket,
 		    (struct sockaddr*)&soc_address,
 		    /* Cast to generic sockaddr */
-		    sizeof(soc_address));
+#ifdef SIN6_LEN
+		    soc_address.ss_len
+#else
+		    SA_LEN((struct sockaddr *)&soc_address)
+#endif
+		    );
 	if (status<0) return HTInetStatus("bind");
 
 	address_length = sizeof(soc_address);
@@ -1126,7 +1170,7 @@
 
     CTRACE(tfp, "HTFTP: bound to port %d on %s\n",
 		(int)ntohs(soc_in->sin_port),
-		HTInetString(soc_in));
+		HTInetString((SockA *)soc_in));
 
 #ifdef REPEAT_LISTEN
     if (master_socket >= 0)
@@ -1138,7 +1182,9 @@
 /*	Now we must find out who we are to tell the other guy
 */
     (void)HTHostName();		/* Make address valid - doesn't work*/
-    sprintf(port_command, "PORT %d,%d,%d,%d,%d,%d%c%c",
+    switch (soc_address.ss_family) {
+    case AF_INET:
+	sprintf(port_command, "PORT %d,%d,%d,%d,%d,%d%c%c",
 		    (int)*((unsigned char *)(&soc_in->sin_addr)+0),
 		    (int)*((unsigned char *)(&soc_in->sin_addr)+1),
 		    (int)*((unsigned char *)(&soc_in->sin_addr)+2),
@@ -1146,7 +1192,29 @@
 		    (int)*((unsigned char *)(&soc_in->sin_port)+0),
 		    (int)*((unsigned char *)(&soc_in->sin_port)+1),
 		    CR, LF);
-
+	break;
+#ifdef INET6
+    case AF_INET6:
+      {
+	char hostbuf[MAXHOSTNAMELEN];
+	char portbuf[MAXHOSTNAMELEN];
+	getnameinfo((struct sockaddr *)&soc_address,
+#ifdef SIN6_LEN
+	    soc_address.ss_len,
+#else
+	    SA_LEN((struct sockaddr *)&soc_address),
+#endif
+	    hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf),
+	    NI_NUMERICHOST | NI_NUMERICSERV);
+	sprintf(port_command, "EPRT |%d|%s|%s|%c%c", 2, hostbuf, portbuf,
+		CR, LF);
+	break;
+      }
+#endif
+    default:
+	sprintf(port_command, "JUNK%c%c", CR, LF);
+	break;
+    }
 
 /*	Inform TCP that we will accept connections
 */
@@ -2594,7 +2662,8 @@
 	if (status < 0) {
 	    NETCLOSE (control->socket);
 	    control->socket = -1;
-	    close_master_socket ();
+	    if (master_socket >= 0)
+		(void)close_master_socket ();
 	    /* HT_INTERRUPTED would fall through, if we could interrupt
 	       somehow in the middle of it, which we currently can't. */
 	    return status;
@@ -2631,26 +2700,50 @@
 	    int status;
 	    data_soc = status;
 
-	    status = send_cmd_1("PASV");
-	    if (status != 2) {
-		if (status < 0)
-		    continue;		/* retry or Bad return */
-		return -status;		/* bad reply */
+	    status = send_cmd_1("EPSV");
+	    if (status < 0)	/* retry or Bad return */
+		continue;
+	    else if (status != 2) {
+		status = send_cmd_1("PASV");
+		if (status < 0)	/* retry or Bad return */
+		    continue;
+		else if (status != 2) {
+		    return -status; 	/* bad reply */
+		}
 	    }
-	    for (p = response_text; *p && *p != ','; p++)
-		; /* null body */
 
-	    while (--p > response_text && '0' <= *p && *p <= '9')
-		; /* null body */
+	    if (strncmp(command, "PASV", 4) == 0) {
+		for (p = response_text; *p && *p != ','; p++)
+		    ; /* null body */
+
+		while (--p > response_text && '0' <= *p && *p <= '9')
+		    ; /* null body */
 
-	   status = sscanf(p+1, "%d,%d,%d,%d,%d,%d",
-		   &h0, &h1, &h2, &h3, &p0, &p1);
-	   if (status < 4) {
-	       fprintf(tfp, "HTFTP: PASV reply has no inet address!\n");
-	       return -99;
-	   }
-	   passive_port = (p0<<8) + p1;
-	   CTRACE(tfp, "HTFTP: Server is listening on port %d\n",
+	       status = sscanf(p+1, "%d,%d,%d,%d,%d,%d",
+		       &h0, &h1, &h2, &h3, &p0, &p1);
+	       if (status < 4) {
+		   fprintf(tfp, "HTFTP: PASV reply has no inet address!\n");
+		   return -99;
+	       }
+	       passive_port = (p0<<8) + p1;
+	    } else if (strncmp(command, "EPSV", 4) == 0) {
+		char ch;
+		/*
+		 * EPSV |||port|
+		 */
+		for (p = response_text; *p && !isspace(*p); p++)
+		    ; /* null body */
+		for (p = response_text; *p && isspace(*p); p++)
+		    ; /* null body */
+		status = sscanf(p+1, "%c%c%c%d%c",
+		       &h0, &h1, &h2, &p0, &h3);
+		if (status != 5) {
+		    fprintf(tfp, "HTFTP: EPSV reply has invalid format!\n");
+		    return -99;
+		}
+		passive_port = p0;
+	    }
+	    CTRACE(tfp, "HTFTP: Server is listening on port %d\n",
 			passive_port);
 
 
@@ -3162,7 +3255,7 @@
 /*	Wait for the connection
 */
     {
-	struct sockaddr_in soc_address;
+	struct sockaddr_storage soc_address;
 	int	soc_addrlen=sizeof(soc_address);
 #ifdef SOCKS
 	if (socks_flag)
