$NetBSD: patch-ae,v 1.3 2000/08/16 00:31:34 itojun Exp $
Index: ftp.c
===================================================================
RCS file: /cvsroot/apps/w3m/ftp.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -1 -r1.1 -r1.2
--- ftp.c	2000/08/15 23:53:35	1.1
+++ ftp.c	2000/08/16 00:28:03	1.2
@@ -15,4 +15,5 @@
 
-#ifdef FTPPASS_HOSTNAMEGEN
 #include <sys/socket.h>
+
+#ifdef FTPPASS_HOSTNAMEGEN
 #include <netinet/in.h>
@@ -22,3 +23,8 @@
 
+#ifdef INET6
+#include <netdb.h>
+#endif
+
 typedef struct _FTP {
+    int family;
     FILE *rcontrol;
@@ -105,2 +111,8 @@
     Str tmp;
+#ifdef INET6
+    struct sockaddr_storage ss;
+#else
+    struct sockaddr ss;
+#endif
+    int sslen;
     FTP ftp = New(struct _FTP);
@@ -116,3 +128,7 @@
 	if (n > 0 && pass[n - 1] == '@') {
+#ifdef INET6
+	    struct sockaddr_storage sockname;
+#else
 	    struct sockaddr_in sockname;
+#endif
 	    int socknamelen = sizeof(sockname);
@@ -120,5 +136,19 @@
 	    if (!getsockname(fd, (struct sockaddr *) &sockname, &socknamelen)) {
+#ifdef INET6
+		char hbuf[NI_MAXHOST];
+#else
 		struct hostent *sockent;
+#endif
 		Str tmp2 = Strnew_charp(pass);
 
+#ifdef INET6
+		if (getnameinfo((struct sockaddr *)&sockname, socknamelen,
+		    hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) == 0) {
+		    Strcat_charp(tmp2, hbuf);
+		} else if (getnameinfo((struct sockaddr *)&sockname, socknamelen,
+			 hbuf, sizeof(hbuf), NULL, 0, 0) == 0) {
+		    Strcat_m_charp(tmp2, "[", hbuf, "]", NULL);
+		} else
+		    Strcat_charp(tmp2, "invalid");
+#else
 		if (sockent = gethostbyaddr((char *) &sockname.sin_addr,
@@ -129,2 +159,3 @@
 		    Strcat_m_charp(tmp2, "[", inet_ntoa(sockname.sin_addr), "]", NULL);
+#endif
 
@@ -135,2 +166,8 @@
 #endif
+    sslen = sizeof(ss);
+    if (getsockname(fd, (struct sockaddr *)&ss, &sslen) < 0) {
+	close(fd);
+	return -1;
+    }
+    ftp->family = ((struct sockaddr *)&ss)->sa_family;
     ftp->rcontrol = fdopen(fd, "rb");
@@ -176,3 +213,46 @@
 
+#ifdef INET6
 int
+ftp_epsv(FTP ftp)
+{
+    int port;
+    int data_s;
+    char *p;
+    Str tmp;
+    char hbuf[NI_MAXHOST];
+    struct sockaddr_storage ss;
+    int sslen;
+
+    sslen = sizeof(ss);
+    if (getpeername(fileno(ftp->wcontrol), (struct sockaddr *)&ss, &sslen) < 0)
+	return -1;
+    if (getnameinfo((struct sockaddr *)&ss, ((struct sockaddr *)&ss)->sa_len,
+	hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) {
+	return -1;
+    }
+
+    fwrite("EPSV\r\n", 6, sizeof(char), ftp->wcontrol);
+    fflush(ftp->wcontrol);
+    tmp = read_response(ftp);
+    if (atoi(tmp->ptr) != 229)
+	return -1;
+    for (p = tmp->ptr + 4; *p && *p != '('; p++);	/*)*/
+    if (*p == '\0')
+	return -1;
+    p++;
+    /* find "|||port|" */
+    if (p[0] && p[0] == p[1] && p[0] == p[2])
+	p += 3;
+    else
+	return -1;
+    sscanf(p, "%d", &port);
+    data_s = openSocket(hbuf, "", port);
+    if (data_s < 0)
+	return -1;
+    ftp->data = fdopen(data_s, "rb");
+    return 0;
+}
+#endif
+
+int
 ftp_pasv(FTP ftp)
@@ -183,2 +263,9 @@
     Str tmp;
+
+#ifdef INET6
+    if (ftp->family == AF_INET6 || ftp->family == AF_INET) {
+	if (ftp_epsv(ftp) == 0)
+	    return 0;
+    }
+#endif
 
