+static int cproc_pasv(struct ftp *ftp, int code, const char *buf, void *cls)
+{
+ const char *str;
+ unsigned int addr[6];
+ struct sockaddr_in sa;
+ unsigned int ipaddr;
+ int port;
+
+ if(code != 227) {
+ errmsg("ftp_passive failed\n");
+ goto nopasv;
+ }
+
+ str = buf;
+ while(*str) {
+ if(sscanf(str, "%u,%u,%u,%u,%u,%u", addr, addr + 1, addr + 2, addr + 3,
+ addr + 4, addr + 5) == 6) {
+ break;
+ }
+ str++;
+ }
+ if(!*str || (addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]) >= 256) {
+ errmsg("ftp_passive: failed to parse response: %s\n", buf);
+ goto nopasv;
+ }
+ port = (addr[4] << 8) | addr[5];
+ ipaddr = ((uint32_t)addr[0] << 24) | ((uint32_t)addr[1] << 16) |
+ ((uint32_t)addr[2] << 8) | addr[3];
+
+ if((ftp->data = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
+ fprintf(stderr, "ftp_passive: failed to allocate socket\n");
+ goto nopasv;
+ }
+
+ infomsg("passive mode: %d.%d.%d.%d port %d\n", addr[0], addr[1], addr[2], addr[3],
+ port);
+
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = htonl(ipaddr);
+ sa.sin_port = htons(port);
+
+ if(connect(ftp->data, (struct sockaddr*)&sa, sizeof sa) == -1) {
+ errmsg("ftp_passive: failed to connect to %s:%p\n", inet_ntoa(sa.sin_addr), port);
+ close(ftp->data);
+ ftp->data = -1;
+ goto nopasv;
+ }
+
+ ftp->status = FTP_CONN_PASV;
+ return 0;
+
+nopasv:
+ ftp->passive = 0;
+ ftp_active(ftp);
+ return 0;
+}
+