+#ifdef ENABLE_IPV6
+/* Similar to ftp_lprt, but uses `LPSV' 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_lpsv (int csock, ip_address *addr, int *port)
+{
+ char *request, *respline, *s;
+ int nwritten, i, af, addrlen, portlen;
+ uerr_t err;
+ unsigned char tmp[16];
+ unsigned char tmpprt[2];
+
+ assert (addr != NULL);
+ assert (port != NULL);
+
+ xzero (*addr);
+
+ /* Form the request. */
+ request = ftp_request ("LPSV", NULL);
+
+ /* And send it. */
+ nwritten = fd_write (csock, request, strlen (request), -1);
+ if (nwritten < 0)
+ {
+ xfree (request);
+ return WRITEFAILED;
+ }
+ xfree (request);
+
+ /* Get the server response. */
+ err = ftp_response (csock, &respline);
+ if (err != FTPOK)
+ return err;
+ if (*respline != '2')
+ {
+ xfree (respline);
+ return FTPNOPASV;
+ }
+
+ /* Parse the response. */
+ s = respline;
+ for (s += 4; *s && !c_isdigit (*s); s++)
+ ;
+ if (!*s)
+ return FTPINVPASV;
+
+ /* First, get the address family */
+ af = 0;
+ for (; c_isdigit (*s); s++)
+ af = (*s - '0') + 10 * af;
+
+ if (af != 4 && af != 6)
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ if (!*s || *s++ != ',')
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ /* Then, get the address length */
+ addrlen = 0;
+ for (; c_isdigit (*s); s++)
+ addrlen = (*s - '0') + 10 * addrlen;
+
+ if (!*s || *s++ != ',')
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ if (addrlen > 16)
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ if ((af == 4 && addrlen != 4)
+ || (af == 6 && addrlen != 16))
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ /* Now, we get the actual address */
+ for (i = 0; i < addrlen; i++)
+ {
+ tmp[i] = 0;
+ for (; c_isdigit (*s); s++)
+ tmp[i] = (*s - '0') + 10 * tmp[i];
+ if (*s == ',')
+ s++;
+ else
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+ }
+
+ /* Now, get the port length */
+ portlen = 0;
+ for (; c_isdigit (*s); s++)
+ portlen = (*s - '0') + 10 * portlen;
+
+ if (!*s || *s++ != ',')
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ if (portlen > 2)
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ /* Finally, we get the port number */
+ tmpprt[0] = 0;
+ for (; c_isdigit (*s); s++)
+ tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
+
+ if (!*s || *s++ != ',')
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ tmpprt[1] = 0;
+ for (; c_isdigit (*s); s++)
+ tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
+
+ assert (s != NULL);
+
+ if (af == 4)
+ {
+ addr->family = AF_INET;
+ memcpy (IP_INADDR_DATA (addr), tmp, 4);
+ *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
+ DEBUGP (("lpsv addr is: %s\n", print_address(addr)));
+ DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
+ DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
+ DEBUGP (("*port is: %d\n", *port));
+ }
+ else
+ {
+ assert (af == 6);
+ addr->family = AF_INET6;
+ memcpy (IP_INADDR_DATA (addr), tmp, 16);
+ *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
+ DEBUGP (("lpsv addr is: %s\n", print_address(addr)));
+ DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
+ DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
+ DEBUGP (("*port is: %d\n", *port));
+ }
+
+ xfree (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 (int csock, ip_address *ip, int *port)
+{
+ char *request, *respline, *start, delim, *s;
+ int nwritten, i;
+ uerr_t err;
+ int tport;
+
+ assert (ip != NULL);
+ assert (port != NULL);
+
+ /* IP already contains the IP address of the control connection's
+ peer, so we don't need to call socket_ip_address here. */
+
+ /* Form the request. */
+ /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
+ request = ftp_request ("EPSV", (ip->family == AF_INET ? "1" : "2"));
+
+ /* And send it. */
+ nwritten = fd_write (csock, request, strlen (request), -1);
+ if (nwritten < 0)
+ {
+ xfree (request);
+ return WRITEFAILED;
+ }
+ xfree (request);
+
+ /* Get the server response. */
+ err = ftp_response (csock, &respline);
+ if (err != FTPOK)
+ return err;
+ if (*respline != '2')
+ {
+ xfree (respline);
+ return FTPNOPASV;
+ }
+
+ assert (respline != NULL);
+
+ DEBUGP(("respline is %s\n", respline));
+
+ /* Parse the response. */
+ s = respline;
+
+ /* Skip the useless stuff and get what's inside the parentheses */
+ start = strchr (respline, '(');
+ if (start == NULL)
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ /* Skip the first two void fields */
+ s = start + 1;
+ delim = *s++;
+ if (delim < 33 || delim > 126)
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ for (i = 0; i < 2; i++)
+ {
+ if (*s++ != delim)
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+ }
+
+ /* Finally, get the port number */
+ tport = 0;
+ for (i = 1; c_isdigit (*s); s++)
+ {
+ if (i > 5)
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+ tport = (*s - '0') + 10 * tport;
+ }
+
+ /* Make sure that the response terminates correcty */
+ if (*s++ != delim)
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ if (*s++ != ')')
+ {
+ xfree (respline);
+ return FTPINVPASV;
+ }
+
+ *port = tport;
+
+ xfree (respline);
+ return FTPOK;
+}
+#endif
+