[WININET] Fixes RETR on WinNT FTP servers.

Lionel Ulmer lionel.ulmer at free.fr
Sat Jul 19 10:58:34 CDT 2003


Hi all,

This is the next step in getting Ragnarok Online patcher to work fine... I
now manage to download fine the first file. There is still a problem with
the second file, but that will be part of a second patch (because I feel the
change to be a bit more controversial than in this one).

If anyone wants to write some unit test code for the FTP functions, feel
free, I think that they need it :)

                 Lionel

Changelog:
 - use SIZE command to retrieve the file size (as the file size is not part
   of the WinNT acknowledgement string)
 - frees the handle / close the socket on end of download
 - fix InternetReadFile in the FTP case
 - fix FTP_ReceiveResponse

-- 
		 Lionel Ulmer - http://www.bbrox.org/
-------------- next part --------------
Index: dlls/wininet/ftp.c
===================================================================
RCS file: /home/wine/wine/dlls/wininet/ftp.c,v
retrieving revision 1.29
diff -u -r1.29 ftp.c
--- dlls/wininet/ftp.c	15 Jul 2003 20:51:02 -0000	1.29
+++ dlls/wininet/ftp.c	19 Jul 2003 15:50:54 -0000
@@ -72,6 +72,7 @@
   FTP_CMD_STOR,
   FTP_CMD_TYPE,
   FTP_CMD_USER,
+  FTP_CMD_SIZE,
 
   /* FTP commands without arguments. */
   FTP_CMD_ABOR,
@@ -96,6 +97,7 @@
   "STOR",
   "TYPE",
   "USER",
+  "SIZE",
   "ABOR",
   "LIST",
   "NLST",
@@ -120,6 +122,7 @@
 BOOL FTP_SendPassword(LPWININETFTPSESSIONA lpwfs);
 BOOL FTP_SendAccount(LPWININETFTPSESSIONA lpwfs);
 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType);
+BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize);
 BOOL FTP_SendPort(LPWININETFTPSESSIONA lpwfs);
 BOOL FTP_DoPassive(LPWININETFTPSESSIONA lpwfs);
 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs);
@@ -1690,7 +1693,6 @@
 
     if (nRecv >= 3)
     {
-        lpszResponse[nRecv] = '\0';
         rc = atoi(lpszResponse);
 
         if (lpfnStatusCB)
@@ -1896,7 +1898,7 @@
 BOOL FTP_SendType(LPWININETFTPSESSIONA lpwfs, DWORD dwType)
 {
     INT nResCode;
-    CHAR type[2] = { "I\0" };
+    CHAR type[2] = { "I" };
     BOOL bSuccess = FALSE;
 
     TRACE("\n");
@@ -1920,6 +1922,49 @@
     return bSuccess;
 }
 
+/***********************************************************************
+ *           FTP_GetFileSize (internal)
+ *
+ * Retrieves from the server the size of the given file
+ *
+ * RETURNS
+ *   TRUE on success
+ *   FALSE on failure
+ *
+ */
+BOOL FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs, LPCSTR lpszRemoteFile, DWORD *dwSize)
+{
+    INT nResCode;
+    BOOL bSuccess = FALSE;
+
+    TRACE("\n");
+
+    if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
+        goto lend;
+
+    nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
+        MAX_REPLY_LEN, 0, 0, 0);
+    if (nResCode)
+    {
+        if (nResCode == 213) {
+	    /* Now parses the output to get the actual file size */
+	    int i;
+	    LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
+
+	    for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
+	    if (lpszResponseBuffer[i] == '\0') return FALSE;
+	    *dwSize = atol(&(lpszResponseBuffer[i + 1]));
+	    
+            bSuccess = TRUE;
+	} else {
+            FTP_SetResponseError(nResCode);
+	}
+    }
+
+lend:
+    return bSuccess;
+}
+
 
 /***********************************************************************
  *           FTP_SendPort (internal)
@@ -2210,33 +2255,19 @@
     if (!FTP_SendPortOrPasv(lpwfs))
         goto lend;
 
+    if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
+	goto lend;
+
+    TRACE("Waiting to receive %ld bytes\n", nResult);
+    
     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
         goto lend;
 
     nResCode = FTP_ReceiveResponse(lpwfs->sndSocket, INTERNET_GetResponseBuffer(),
         MAX_REPLY_LEN, 0, 0, 0);
-    if (nResCode)
-    {
-        if (nResCode == 125 || nResCode == 150)
-        {
-            /* Parse size of data to be retrieved */
-            INT i, sizepos = -1;
-	    LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
-            for (i = strlen(lpszResponseBuffer) - 1; i >= 0; i--)
-            {
-                if ('(' == lpszResponseBuffer[i])
-                {
-                    sizepos = i;
-                    break;
-                }
-            }
-
-            if (sizepos >= 0)
-            {
-                nResult = atol(&lpszResponseBuffer[sizepos+1]);
-                TRACE("Waiting to receive %ld bytes\n", nResult);
-            }
-        }
+    if ((nResCode != 125) && (nResCode != 150)) {
+	/* That means that we got an error getting the file. */
+	nResult = 0;
     }
 
 lend:
@@ -2316,6 +2347,8 @@
  */
 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs)
 {
+    TRACE("\n");
+    
     if (lpwfs->sndSocket != -1)
         close(lpwfs->sndSocket);
 
@@ -2335,7 +2368,7 @@
 
 
 /***********************************************************************
- *           FTP_CloseSessionHandle (internal)
+ *           FTP_CloseFindNextHandle (internal)
  *
  * Deallocate session handle
  *
@@ -2362,6 +2395,28 @@
     return TRUE;
 }
 
+/***********************************************************************
+ *           FTP_CloseFindNextHandle (internal)
+ *
+ * Closes the file transfer handle. This also 'cleans' the data queue of
+ * the 'transfer conplete' message (this is a bit of a hack though :-/ )
+ *
+ * RETURNS
+ *   TRUE on success
+ *   FALSE on failure
+ *
+ */
+BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwh)
+{
+    TRACE("\n");
+    
+    if (lpwh->nDataSocket != -1)
+        close(lpwh->nDataSocket);
+
+    HeapFree(GetProcessHeap(), 0, lpwh);
+    
+    return TRUE;
+}
 
 /***********************************************************************
  *           FTP_ReceiveFileList (internal)
Index: dlls/wininet/internet.c
===================================================================
RCS file: /home/wine/wine/dlls/wininet/internet.c,v
retrieving revision 1.61
diff -u -r1.61 internet.c
--- dlls/wininet/internet.c	9 Jul 2003 22:15:33 -0000	1.61
+++ dlls/wininet/internet.c	19 Jul 2003 15:50:55 -0000
@@ -701,6 +701,10 @@
 		retval = FTP_CloseFindNextHandle((LPWININETFINDNEXTA) lpwh);
 		break;
 
+	    case WH_HFILE:
+		retval = FTP_CloseFileTransferHandle((LPWININETFILE) lpwh);
+		break;
+		
 	    default:
 		break;
 	}
@@ -1331,12 +1335,6 @@
             break;
     }
 
-    if (nSocket != -1)
-    {
-        int res = recv(nSocket, lpBuffer, dwNumOfBytesToRead, 0);
-        retval = (res >= 0);
-        *dwNumOfBytesRead = retval ? res : 0;
-    }
     return retval;
 }
 
Index: dlls/wininet/internet.h
===================================================================
RCS file: /home/wine/wine/dlls/wininet/internet.h,v
retrieving revision 1.11
diff -u -r1.11 internet.h
--- dlls/wininet/internet.h	20 Jun 2003 23:26:56 -0000	1.11
+++ dlls/wininet/internet.h	19 Jul 2003 15:50:55 -0000
@@ -243,6 +243,7 @@
 
 BOOL FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs);
 BOOL FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn);
+BOOL FTP_CloseFileTransferHandle(LPWININETFILE lpwfn);
 BOOLAPI FTP_FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
     LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext);
 BOOLAPI FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory);


More information about the wine-patches mailing list