cc3e7ee422bb2ad40ba43ca332558a59f3d77114
galt
  Fri May 13 11:48:55 2011 -0700
require FTP to check for return code of 331 before sending the PASS command.
diff --git src/lib/net.c src/lib/net.c
index 3e00091..a57d9c6 100644
--- src/lib/net.c
+++ src/lib/net.c
@@ -507,31 +507,31 @@
     else
 	{
     	return readyCount > 0;	/* Zero readyCount indicates time out */
 	}
     }
 }
 
 static void sendFtpCommandOnly(int sd, char *cmd)
 /* send command to ftp server */
 {   
 mustWriteFd(sd, cmd, strlen(cmd));
 }
 
 #define NET_FTP_TIMEOUT 1000000
 
-static boolean receiveFtpReply(int sd, char *cmd, struct dyString **retReply)
+static boolean receiveFtpReply(int sd, char *cmd, struct dyString **retReply, int *retCode)
 /* send command to ftp server and check resulting reply code, 
  * warn and return FALSE if not desired reply.  If retReply is non-NULL, store reply text there. */
 {
 char *startLastLine = NULL;
 struct dyString *rs = newDyString(4*1024);
 while (1)
     {
     int readSize = 0;
     while (1)
 	{
 	char buf[4*1024];
 	if (!readReadyWait(sd, NET_FTP_TIMEOUT))
 	    {
 	    warn("ftp server response timed out > %d microsec", NET_FTP_TIMEOUT);
 	    return FALSE;
@@ -565,39 +565,41 @@
 	break;  // EOF
     /* must be some text info we can't use, ignore it till we get status code */
     }
 
 int reply = atoi(startLastLine);
 if ((reply < 200) || (reply > 399))
     {
     warn("ftp server error on cmd=[%s] response=[%s]\n",cmd,rs->string);
     return FALSE;
     }
     
 if (retReply)
     *retReply = rs;
 else
     dyStringFree(&rs);
+if (retCode)
+    *retCode = reply;
 return TRUE;
 }
 
-static boolean sendFtpCommand(int sd, char *cmd, struct dyString **retReply)
+static boolean sendFtpCommand(int sd, char *cmd, struct dyString **retReply, int *retCode)
 /* send command to ftp server and check resulting reply code, 
  * warn and return FALSE if not desired reply.  If retReply is non-NULL, store reply text there. */
 {   
 sendFtpCommandOnly(sd, cmd);
-return receiveFtpReply(sd, cmd, retReply);
+return receiveFtpReply(sd, cmd, retReply, retCode);
 }
 
 static int parsePasvPort(char *rs)
 /* parse PASV reply to get the port and return it */
 {
 char *words[7];
 int wordCount;
 char *rsStart = strchr(rs,'(');
 char *rsEnd = strchr(rs,')');
 int result = 0;
 rsStart++;
 *rsEnd=0;
 wordCount = chopString(rsStart, ",", words, ArraySize(words));
 if (wordCount != 6)
     errAbort("PASV reply does not parse correctly");
@@ -668,48 +670,52 @@
     errAbort("mktime failed while parsing strptime'd MDTM string [%s]", words[1]);
 return t;
 }    
 
 
 static int openFtpControlSocket(char *host, int port, char *user, char *password)
 /* Open a socket to host,port; authenticate anonymous ftp; set type to I; 
  * return socket desc or -1 if there was an error. */
 {
 int sd = netConnect(host, port);
 if (sd < 0)
     return -1;
 
 /* First read the welcome msg */
 if (readReadyWait(sd, NET_FTP_TIMEOUT))
-    sendFtpCommand(sd, "", NULL);
+    sendFtpCommand(sd, "", NULL, NULL);
 
 char cmd[256];
+int retCode = 0;
 safef(cmd,sizeof(cmd),"USER %s\r\n", user);
-if (!sendFtpCommand(sd, cmd, NULL))
+if (!sendFtpCommand(sd, cmd, NULL, &retCode))
     {
     close(sd);
     return -1;
     }
 
+if (retCode == 331)
+    {
 safef(cmd,sizeof(cmd),"PASS %s\r\n", password);
-if (!sendFtpCommand(sd, cmd, NULL))
+    if (!sendFtpCommand(sd, cmd, NULL, NULL))
     {
     close(sd);
     return -1;
     }
+    }
 
-if (!sendFtpCommand(sd, "TYPE I\r\n", NULL))
+if (!sendFtpCommand(sd, "TYPE I\r\n", NULL, NULL))
     {
     close(sd);
     return -1;
     }
 /* 200 Type set to I */
 /* (send the data as binary, so can support compressed files) */
 return sd;
 }
 
 boolean netGetFtpInfo(char *url, long long *retSize, time_t *retTime)
 /* Return date in UTC and size of ftp url file */
 {
 /* Parse the URL and connect. */
 struct netParsedUrl npu;
 netParseUrl(url, &npu);
@@ -718,41 +724,41 @@
 
 // TODO maybe remove this workaround where udc cache wants info on URL "/" ?
 if (sameString(npu.file,"/"))
     {
     *retSize = 0;
     *retTime = time(NULL);
     return TRUE;
     }
 
 int sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password);
 if (sd < 0)
     return FALSE;
 char cmd[256];
 safef(cmd,sizeof(cmd),"SIZE %s\r\n", npu.file);
 struct dyString *rs = NULL;
-if (!sendFtpCommand(sd, cmd, &rs))
+if (!sendFtpCommand(sd, cmd, &rs, NULL))
     {
     close(sd);
     return FALSE;
     }
 *retSize = parseFtpSIZE(rs->string);
 /* 200 12345 */
 dyStringFree(&rs);
 
 safef(cmd,sizeof(cmd),"MDTM %s\r\n", npu.file);
-if (!sendFtpCommand(sd, cmd, &rs))
+if (!sendFtpCommand(sd, cmd, &rs, NULL))
     {
     close(sd);
     return FALSE;
     }
 *retTime = parseFtpMDTM(rs->string);
 /* 200 YYYYMMDDhhmmss */
 dyStringFree(&rs);
 close(sd);   
 return TRUE;
 }
 
 static void sendFtpDataToPipe(int pipefd[2], int sd, int sdata, struct netParsedUrl npu)
 /* This is to be executed by the child process after the fork in netGetOpenFtpSockets.
  * It keeps the ftp control socket alive while reading from the ftp data socket
  * and writing to the pipe to the parent process, which closes the ftp sockets
@@ -804,41 +810,41 @@
  * Otherwise, create a pipe and fork to keep control socket alive in the child 
  * process until we are done fetching data. */
 {
 char cmd[256];
 
 /* Parse the URL and connect. */
 struct netParsedUrl npu;
 netParseUrl(url, &npu);
 if (!sameString(npu.protocol, "ftp"))
     errAbort("netGetOpenFtpSockets: url (%s) is not for ftp.", url);
 int sd = openFtpControlSocket(npu.host, atoi(npu.port), npu.user, npu.password);
 if (sd == -1)
     return -1;
 
 struct dyString *rs = NULL;
-if (!sendFtpCommand(sd, "PASV\r\n", &rs))
+if (!sendFtpCommand(sd, "PASV\r\n", &rs, NULL))
     {
     close(sd);
     return -1;
     }
 /* 227 Entering Passive Mode (128,231,210,81,222,250) */
 
 if (npu.byteRangeStart != -1)
     {
     safef(cmd,sizeof(cmd),"REST %lld\r\n", (long long) npu.byteRangeStart);
-    if (!sendFtpCommand(sd, cmd, NULL))
+    if (!sendFtpCommand(sd, cmd, NULL, NULL))
 	{
 	close(sd);
 	return -1;
 	}
     }
 
 /* RETR for files, LIST for directories ending in / */
 safef(cmd,sizeof(cmd),"%s %s\r\n",((npu.file[strlen(npu.file)-1]) == '/') ? "LIST" : "RETR", npu.file);
 sendFtpCommandOnly(sd, cmd);
 
 int sdata = netConnect(npu.host, parsePasvPort(rs->string));
 dyStringFree(&rs);
 if (sdata < 0)
     {
     close(sd);
@@ -848,31 +854,31 @@
 int secondsWaited = 0;
 while (TRUE)
     {
     if (secondsWaited >= 10)
 	{
 	warn("ftp server error on cmd=[%s] timed-out waiting for data or error\n", cmd);
 	close(sd);
 	close(sdata);
 	return -1;
 	}
     if (readReadyWait(sdata, NET_FTP_TIMEOUT))
 	break;   // we have some data
     if (readReadyWait(sd, 0)) /* wait in microsec */
 	{
 	// this can see an error like bad filename
-	if (!receiveFtpReply(sd, cmd, NULL))
+	if (!receiveFtpReply(sd, cmd, NULL, NULL))
 	    {
 	    close(sd);
 	    close(sdata);
 	    return -1;
 	    }
 	}
     ++secondsWaited;
     }
 
 if (retCtrlSd != NULL)
     {
     *retCtrlSd = sd;
     return sdata;
     }
 else