sync with trunk r46493
[reactos.git] / dll / win32 / wininet / ftp.c
index 770fef2..1f03199 100644 (file)
 #include "config.h"
 #include "wine/port.h"
 
+#if defined(__MINGW32__) || defined (_MSC_VER)
+#include <ws2tcpip.h>
+#endif
+
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
 #ifdef HAVE_SYS_SOCKET_H
 # include <sys/socket.h>
 #endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
 #include <time.h>
 #include <assert.h>
 
 
 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
 
-typedef struct _WININETFTPSESSIONW WININETFTPSESSIONW;
+typedef struct _ftp_session_t ftp_session_t;
 
 typedef struct
 {
-    WININETHANDLEHEADER hdr;
-    WININETFTPSESSIONW *lpFtpSession;
+    object_header_t hdr;
+    ftp_session_t *lpFtpSession;
     BOOL session_deleted;
     int nDataSocket;
-} WININETFTPFILE, *LPWININETFTPFILE;
+    WCHAR *cache_file;
+    HANDLE cache_file_handle;
+} ftp_file_t;
 
-typedef struct _WININETFTPSESSIONW
+struct _ftp_session_t
 {
-    WININETHANDLEHEADER hdr;
-    WININETAPPINFOW *lpAppInfo;
+    object_header_t hdr;
+    appinfo_t *lpAppInfo;
     int sndSocket;
     int lstnSocket;
     int pasvSocket; /* data socket connected by us in case of passive FTP */
-    LPWININETFTPFILE download_in_progress;
+    ftp_file_t *download_in_progress;
     struct sockaddr_in socketAddress;
     struct sockaddr_in lstnSocketAddress;
+    LPWSTR servername;
+    INTERNET_PORT serverport;
     LPWSTR  lpszPassword;
     LPWSTR  lpszUserName;
-} *LPWININETFTPSESSIONW;
+};
 
 typedef struct
 {
     BOOL bIsDirectory;
     LPWSTR lpszName;
     DWORD nSize;
-    struct tm tmLastModified;
+    SYSTEMTIME tmLastModified;
     unsigned short permissions;
 } FILEPROPERTIESW, *LPFILEPROPERTIESW;
 
 typedef struct
 {
-    WININETHANDLEHEADER hdr;
-    WININETFTPSESSIONW *lpFtpSession;
+    object_header_t hdr;
+    ftp_session_t *lpFtpSession;
     DWORD index;
     DWORD size;
     LPFILEPROPERTIESW lpafp;
@@ -165,46 +179,51 @@ static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
 
 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
-       INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext);
-static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
-static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
-static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
-static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext);
-static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
-static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
-static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
-static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
-static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
-static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
-static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
-static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
-static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
-static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
+       INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext);
+static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType);
+static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket);
+static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile);
+static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext);
+static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType);
+static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile);
+static BOOL FTP_InitListenSocket(ftp_session_t*);
+static BOOL FTP_ConnectToHost(ftp_session_t*);
+static BOOL FTP_SendPassword(ftp_session_t*);
+static BOOL FTP_SendAccount(ftp_session_t*);
+static BOOL FTP_SendType(ftp_session_t*, DWORD dwType);
+static BOOL FTP_SendPort(ftp_session_t*);
+static BOOL FTP_DoPassive(ftp_session_t*);
+static BOOL FTP_SendPortOrPasv(ftp_session_t*);
 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
-static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
+static BOOL FTP_ParseDirectory(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile,
         LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
-static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
+static HINTERNET FTP_ReceiveFileList(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile,
         LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext);
 static DWORD FTP_SetResponseError(DWORD dwResponse);
 static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData);
-static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
+static BOOL FTP_FtpPutFileW(ftp_session_t*, LPCWSTR lpszLocalFile,
         LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext);
-static BOOL FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory);
-static BOOL FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory);
-static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
+static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
+static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
+static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*,
         LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext);
-static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
+static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory,
         LPDWORD lpdwCurrentDirectory);
-static BOOL FTP_FtpRenameFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest);
-static BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory);
-static BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName);
-static HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName,
-        DWORD fdwAccess, DWORD dwFlags, DWORD_PTR dwContext);
-static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
+static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest);
+static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
+static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName);
+static BOOL FTP_FtpGetFileW(ftp_session_t*, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
         BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
         DWORD_PTR dwContext);
 
+/* A temporary helper until we get rid of INTERNET_GetLastError calls */
+static BOOL res_to_le(DWORD res)
+{
+    if(res != ERROR_SUCCESS)
+        INTERNET_SetLastError(res);
+    return res == ERROR_SUCCESS;
+}
 
 /***********************************************************************
  *           FtpPutFileA (WININET.@)
@@ -223,8 +242,8 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
     LPWSTR lpwzNewRemoteFile;
     BOOL ret;
     
-    lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
-    lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
+    lpwzLocalFile = heap_strdupAtoW(lpszLocalFile);
+    lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile);
     ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
                       dwFlags, dwContext);
     HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
@@ -235,7 +254,7 @@ BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE("%p\n", lpwfs);
 
@@ -259,8 +278,8 @@ static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
     LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
 {
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
     BOOL r = FALSE;
 
     if (!lpszLocalFile || !lpszNewRemoteFile)
@@ -269,7 +288,7 @@ BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
         return FALSE;
     }
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hConnect );
     if (!lpwfs)
     {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
@@ -302,12 +321,12 @@ BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
 
         workRequest.asyncproc = AsyncFtpPutFileProc;
         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
-        req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
-        req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
+        req->lpszLocalFile = heap_strdupW(lpszLocalFile);
+        req->lpszNewRemoteFile = heap_strdupW(lpszNewRemoteFile);
        req->dwFlags = dwFlags;
        req->dwContext = dwContext;
 
-       r = INTERNET_AsyncCall(&workRequest);
+       r = res_to_le(INTERNET_AsyncCall(&workRequest));
     }
     else
     {
@@ -331,12 +350,12 @@ lend:
  *    FALSE on failure
  *
  */
-static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
+static BOOL FTP_FtpPutFileW(ftp_session_t *lpwfs, LPCWSTR lpszLocalFile,
     LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
 {
     HANDLE hFile;
     BOOL bSuccess = FALSE;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
     INT nResCode;
 
     TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
@@ -375,7 +394,10 @@ static BOOL FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
     }
 
     if (lpwfs->lstnSocket != -1)
+    {
         closesocket(lpwfs->lstnSocket);
+        lpwfs->lstnSocket = -1;
+    }
 
     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
     {
@@ -408,7 +430,7 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
     LPWSTR lpwzDirectory;
     BOOL ret;
     
-    lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
+    lpwzDirectory = heap_strdupAtoW(lpszDirectory);
     ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
     HeapFree(GetProcessHeap(), 0, lpwzDirectory);
     return ret;
@@ -418,7 +440,7 @@ BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE("%p\n", lpwfs);
 
@@ -438,8 +460,8 @@ static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
  */
 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
 {
-    LPWININETFTPSESSIONW lpwfs = NULL;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs = NULL;
+    appinfo_t *hIC = NULL;
     BOOL r = FALSE;
 
     if (!lpszDirectory)
@@ -448,7 +470,7 @@ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
         goto lend;
     }
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hConnect );
     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
     {
         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
@@ -472,9 +494,9 @@ BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
         workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
         req = &workRequest.u.FtpSetCurrentDirectoryW;
-        req->lpszDirectory = WININET_strdupW(lpszDirectory);
+        req->lpszDirectory = heap_strdupW(lpszDirectory);
 
-       r = INTERNET_AsyncCall(&workRequest);
+       r = res_to_le(INTERNET_AsyncCall(&workRequest));
     }
     else
     {
@@ -499,10 +521,10 @@ lend:
  *    FALSE on failure
  *
  */
-static BOOL FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
+static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
 {
     INT nResCode;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
     DWORD bSuccess = FALSE;
 
     TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
@@ -554,7 +576,7 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
     LPWSTR lpwzDirectory;
     BOOL ret;
     
-    lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
+    lpwzDirectory = heap_strdupAtoW(lpszDirectory);
     ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
     HeapFree(GetProcessHeap(), 0, lpwzDirectory);
     return ret;
@@ -564,7 +586,7 @@ BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE(" %p\n", lpwfs);
 
@@ -584,11 +606,11 @@ static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
  */
 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
 {
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
     BOOL r = FALSE;
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hConnect );
     if (!lpwfs)
     {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
@@ -622,9 +644,9 @@ BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
         workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
         req = &workRequest.u.FtpCreateDirectoryW;
-        req->lpszDirectory = WININET_strdupW(lpszDirectory);
+        req->lpszDirectory = heap_strdupW(lpszDirectory);
 
-       r = INTERNET_AsyncCall(&workRequest);
+       r = res_to_le(INTERNET_AsyncCall(&workRequest));
     }
     else
     {
@@ -647,11 +669,11 @@ lend:
  *    FALSE on failure
  *
  */
-static BOOL FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
+static BOOL FTP_FtpCreateDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
 
     TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
 
@@ -703,14 +725,14 @@ HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
     LPWIN32_FIND_DATAW lpFindFileDataW;
     HINTERNET ret;
     
-    lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
+    lpwzSearchFile = heap_strdupAtoW(lpszSearchFile);
     lpFindFileDataW = lpFindFileData?&wfd:NULL;
     ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
     HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
     
     if (ret && lpFindFileData)
         WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
-    
+
     return ret;
 }
 
@@ -718,7 +740,7 @@ HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE("%p\n", lpwfs);
 
@@ -740,11 +762,11 @@ static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
     LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
 {
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
     HINTERNET r = NULL;
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hConnect );
     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
     {
         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
@@ -766,7 +788,7 @@ HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
         workRequest.asyncproc = AsyncFtpFindFirstFileProc;
         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
         req = &workRequest.u.FtpFindFirstFileW;
-        req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
+        req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : heap_strdupW(lpszSearchFile);
        req->lpFindFileData = lpFindFileData;
        req->dwFlags = dwFlags;
        req->dwContext= dwContext;
@@ -797,11 +819,11 @@ lend:
  *    NULL on failure
  *
  */
-static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
+static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t *lpwfs,
     LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
 {
     INT nResCode;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
     HINTERNET hFindNext = NULL;
 
     TRACE("\n");
@@ -845,7 +867,10 @@ static HINTERNET FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
 
 lend:
     if (lpwfs->lstnSocket != -1)
+    {
         closesocket(lpwfs->lstnSocket);
+        lpwfs->lstnSocket = -1;
+    }
 
     hIC = lpwfs->lpAppInfo;
     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
@@ -854,13 +879,13 @@ lend:
 
         if (hFindNext)
        {
-            iar.dwResult = (DWORD)hFindNext;
+            iar.dwResult = (DWORD_PTR)hFindNext;
             iar.dwError = ERROR_SUCCESS;
             SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
                 &iar, sizeof(INTERNET_ASYNC_RESULT));
        }
 
-        iar.dwResult = (DWORD)hFindNext;
+        iar.dwResult = (DWORD_PTR)hFindNext;
         iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
         SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
             &iar, sizeof(INTERNET_ASYNC_RESULT));
@@ -913,7 +938,7 @@ BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDire
 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE("%p\n", lpwfs);
 
@@ -933,13 +958,13 @@ static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
     LPDWORD lpdwCurrentDirectory)
 {
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
     BOOL r = FALSE;
 
     TRACE("%p %p %p\n", hFtpSession, lpszCurrentDirectory, lpdwCurrentDirectory);
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
     if (NULL == lpwfs)
     {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
@@ -982,7 +1007,7 @@ BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDir
        req->lpszDirectory = lpszCurrentDirectory;
        req->lpdwDirectory = lpdwCurrentDirectory;
 
-       r = INTERNET_AsyncCall(&workRequest);
+       r = res_to_le(INTERNET_AsyncCall(&workRequest));
     }
     else
     {
@@ -1008,11 +1033,11 @@ lend:
  *    FALSE on failure
  *
  */
-static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
+static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t *lpwfs, LPWSTR lpszCurrentDirectory,
        LPDWORD lpdwCurrentDirectory)
 {
     INT nResCode;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
     DWORD bSuccess = FALSE;
 
     /* Clear any error information */
@@ -1029,7 +1054,7 @@ static BOOL FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszC
         if (nResCode == 257) /* Extract directory name */
         {
             DWORD firstpos, lastpos, len;
-            LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
+            LPWSTR lpszResponseBuffer = heap_strdupAtoW(INTERNET_GetResponseBuffer());
 
             for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
             {
@@ -1071,118 +1096,6 @@ lend:
     return bSuccess;
 }
 
-/***********************************************************************
- *           FtpOpenFileA (WININET.@)
- *
- * Open a remote file for writing or reading
- *
- * RETURNS
- *    HINTERNET handle on success
- *    NULL on failure
- *
- */
-HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
-    LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
-    DWORD_PTR dwContext)
-{
-    LPWSTR lpwzFileName;
-    HINTERNET ret;
-    
-    lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
-    ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
-    HeapFree(GetProcessHeap(), 0, lpwzFileName);
-    return ret;
-}
-
-
-static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
-{
-    struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
-
-    TRACE("%p\n", lpwfs);
-
-    FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
-        req->dwAccess, req->dwFlags, req->dwContext);
-    HeapFree(GetProcessHeap(), 0, req->lpszFilename);
-}
-
-/***********************************************************************
- *           FtpOpenFileW (WININET.@)
- *
- * Open a remote file for writing or reading
- *
- * RETURNS
- *    HINTERNET handle on success
- *    NULL on failure
- *
- */
-HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
-    LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
-    DWORD_PTR dwContext)
-{
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
-    HINTERNET r = NULL;
-    
-    TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
-        debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
-
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
-    if (!lpwfs)
-    {
-        INTERNET_SetLastError(ERROR_INVALID_HANDLE);
-        return FALSE;
-    }
-
-    if (WH_HFTPSESSION != lpwfs->hdr.htype)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-        goto lend;
-    }
-
-    if ((!lpszFileName) ||
-        ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
-        ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
-    {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-        goto lend;
-    }
-
-    if (lpwfs->download_in_progress != NULL)
-    {
-        INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
-        goto lend;
-    }
-
-    hIC = lpwfs->lpAppInfo;
-    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST workRequest;
-        struct WORKREQ_FTPOPENFILEW *req;
-
-        workRequest.asyncproc = AsyncFtpOpenFileProc;
-        workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
-        req = &workRequest.u.FtpOpenFileW;
-       req->lpszFilename = WININET_strdupW(lpszFileName);
-       req->dwAccess = fdwAccess;
-       req->dwFlags = dwFlags;
-       req->dwContext = dwContext;
-
-       INTERNET_AsyncCall(&workRequest);
-       r = NULL;
-    }
-    else
-    {
-       r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
-    }
-
-lend:
-    WININET_Release( &lpwfs->hdr );
-
-    return r;
-}
-
 
 /***********************************************************************
  *           FTPFILE_Destroy(internal)
@@ -1191,15 +1104,18 @@ lend:
  * the 'transfer complete' message (this is a bit of a hack though :-/ )
  *
  */
-static void FTPFILE_Destroy(WININETHANDLEHEADER *hdr)
+static void FTPFILE_Destroy(object_header_t *hdr)
 {
-    LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
-    LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
+    ftp_file_t *lpwh = (ftp_file_t*) hdr;
+    ftp_session_t *lpwfs = lpwh->lpFtpSession;
     INT nResCode;
 
     TRACE("\n");
 
-    WININET_Release(&lpwh->lpFtpSession->hdr);
+    if (lpwh->cache_file_handle != INVALID_HANDLE_VALUE)
+        CloseHandle(lpwh->cache_file_handle);
+
+    HeapFree(GetProcessHeap(), 0, lpwh->cache_file);
 
     if (!lpwh->session_deleted)
         lpwfs->download_in_progress = NULL;
@@ -1210,10 +1126,12 @@ static void FTPFILE_Destroy(WININETHANDLEHEADER *hdr)
     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
     if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n");
 
+    WININET_Release(&lpwh->lpFtpSession->hdr);
+
     HeapFree(GetProcessHeap(), 0, lpwh);
 }
 
-static DWORD FTPFILE_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+static DWORD FTPFILE_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
 {
     switch(option) {
     case INTERNET_OPTION_HANDLE_TYPE:
@@ -1225,15 +1143,47 @@ static DWORD FTPFILE_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *b
         *size = sizeof(DWORD);
         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE;
         return ERROR_SUCCESS;
-    }
+    case INTERNET_OPTION_DATAFILE_NAME:
+    {
+        DWORD required;
+        ftp_file_t *file = (ftp_file_t *)hdr;
 
+        TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
+
+        if (!file->cache_file)
+        {
+            *size = 0;
+            return ERROR_INTERNET_ITEM_NOT_FOUND;
+        }
+        if (unicode)
+        {
+            required = (lstrlenW(file->cache_file) + 1) * sizeof(WCHAR);
+            if (*size < required)
+                return ERROR_INSUFFICIENT_BUFFER;
+
+            *size = required;
+            memcpy(buffer, file->cache_file, *size);
+            return ERROR_SUCCESS;
+        }
+        else
+        {
+            required = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, NULL, 0, NULL, NULL);
+            if (required > *size)
+                return ERROR_INSUFFICIENT_BUFFER;
+
+            *size = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, buffer, *size, NULL, NULL);
+            return ERROR_SUCCESS;
+        }
+    }
+    }
     return INET_QueryOption(option, buffer, size, unicode);
 }
 
-static DWORD FTPFILE_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read)
+static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
 {
-    WININETFTPFILE *file = (WININETFTPFILE*)hdr;
+    ftp_file_t *file = (ftp_file_t*)hdr;
     int res;
+    DWORD error;
 
     if (file->nDataSocket == -1)
         return ERROR_INTERNET_DISCONNECTED;
@@ -1242,29 +1192,119 @@ static DWORD FTPFILE_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size
     res = recv(file->nDataSocket, buffer, size, MSG_WAITALL);
     *read = res>0 ? res : 0;
 
-    return res>=0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME*/
+    error = res >= 0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME */
+    if (error == ERROR_SUCCESS && file->cache_file)
+    {
+        DWORD bytes_written;
+
+        if (!WriteFile(file->cache_file_handle, buffer, *read, &bytes_written, NULL))
+            WARN("WriteFile failed: %u\n", GetLastError());
+    }
+    return error;
+}
+
+static DWORD FTPFILE_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
+    DWORD flags, DWORD_PTR context)
+{
+    return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength);
 }
 
-static BOOL FTPFILE_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written)
+static DWORD FTPFILE_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
+    DWORD flags, DWORD_PTR context)
 {
-    LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
+    return FTPFILE_ReadFile(hdr, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength);
+}
+
+static DWORD FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
+{
+    ftp_file_t *lpwh = (ftp_file_t*) hdr;
     int res;
 
     res = send(lpwh->nDataSocket, buffer, size, 0);
 
     *written = res>0 ? res : 0;
-    return res >= 0;
+    return res >= 0 ? ERROR_SUCCESS : sock_get_error(errno);
+}
+
+static void FTP_ReceiveRequestData(ftp_file_t *file, BOOL first_notif)
+{
+    INTERNET_ASYNC_RESULT iar;
+    BYTE buffer[4096];
+    int available;
+
+    TRACE("%p\n", file);
+
+    available = recv(file->nDataSocket, buffer, sizeof(buffer), MSG_PEEK);
+
+    if(available != -1) {
+        iar.dwResult = (DWORD_PTR)file->hdr.hInternet;
+        iar.dwError = first_notif ? 0 : available;
+    }else {
+        iar.dwResult = 0;
+        iar.dwError = INTERNET_GetLastError();
+    }
+
+    INTERNET_SendCallback(&file->hdr, file->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+                          sizeof(INTERNET_ASYNC_RESULT));
+}
+
+static void FTPFILE_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
+{
+    ftp_file_t *file = (ftp_file_t*)workRequest->hdr;
+
+    FTP_ReceiveRequestData(file, FALSE);
+}
+
+static DWORD FTPFILE_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
+{
+    ftp_file_t *file = (ftp_file_t*) hdr;
+    int retval, unread = 0;
+
+    TRACE("(%p %p %x %lx)\n", file, available, flags, ctx);
+
+#ifdef FIONREAD
+    retval = ioctlsocket(file->nDataSocket, FIONREAD, &unread);
+    if (!retval)
+        TRACE("%d bytes of queued, but unread data\n", unread);
+#else
+    FIXME("FIONREAD not available\n");
+#endif
+
+    *available = unread;
+
+    if(!unread) {
+        BYTE byte;
+
+        *available = 0;
+
+        retval = recv(file->nDataSocket, &byte, 1, MSG_PEEK);
+        if(retval > 0) {
+            WORKREQUEST workRequest;
+
+            *available = 0;
+            workRequest.asyncproc = FTPFILE_AsyncQueryDataAvailableProc;
+            workRequest.hdr = WININET_AddRef( &file->hdr );
+
+            INTERNET_AsyncCall(&workRequest);
+
+            return ERROR_IO_PENDING;
+        }
+    }
+
+    return ERROR_SUCCESS;
 }
 
-static const HANDLEHEADERVtbl FTPFILEVtbl = {
+
+static const object_vtbl_t FTPFILEVtbl = {
     FTPFILE_Destroy,
     NULL,
     FTPFILE_QueryOption,
     NULL,
     FTPFILE_ReadFile,
-    NULL,
+    FTPFILE_ReadFileExA,
+    FTPFILE_ReadFileExW,
     FTPFILE_WriteFile,
-    NULL,
+    FTPFILE_QueryDataAvailable,
     NULL
 };
 
@@ -1278,14 +1318,14 @@ static const HANDLEHEADERVtbl FTPFILEVtbl = {
  *    NULL on failure
  *
  */
-HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
+static HINTERNET FTP_FtpOpenFileW(ftp_session_t *lpwfs,
        LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
        DWORD_PTR dwContext)
 {
     INT nDataSocket;
     BOOL bSuccess = FALSE;
-    LPWININETFTPFILE lpwh = NULL;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_file_t *lpwh = NULL;
+    appinfo_t *hIC = NULL;
     HINTERNET handle = NULL;
 
     TRACE("\n");
@@ -1307,15 +1347,18 @@ HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
     /* Get data socket to server */
     if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
     {
-        lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
+        lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_file_t));
         lpwh->hdr.htype = WH_HFILE;
         lpwh->hdr.vtbl = &FTPFILEVtbl;
         lpwh->hdr.dwFlags = dwFlags;
         lpwh->hdr.dwContext = dwContext;
+        lpwh->hdr.dwInternalFlags = 0;
         lpwh->hdr.refs = 1;
         lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
         lpwh->nDataSocket = nDataSocket;
-       lpwh->session_deleted = FALSE;
+        lpwh->cache_file = NULL;
+        lpwh->cache_file_handle = INVALID_HANDLE_VALUE;
+        lpwh->session_deleted = FALSE;
 
         WININET_AddRef( &lpwfs->hdr );
         lpwh->lpFtpSession = lpwfs;
@@ -1330,7 +1373,45 @@ HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
     }
 
     if (lpwfs->lstnSocket != -1)
+    {
         closesocket(lpwfs->lstnSocket);
+        lpwfs->lstnSocket = -1;
+    }
+
+    if (bSuccess && fdwAccess == GENERIC_READ)
+    {
+        WCHAR filename[MAX_PATH + 1];
+        URL_COMPONENTSW uc;
+        DWORD len;
+
+        memset(&uc, 0, sizeof(uc));
+        uc.dwStructSize = sizeof(uc);
+        uc.nScheme      = INTERNET_SCHEME_FTP;
+        uc.lpszHostName = lpwfs->servername;
+        uc.nPort        = lpwfs->serverport;
+        uc.lpszUserName = lpwfs->lpszUserName;
+        uc.lpszUrlPath  = heap_strdupW(lpszFileName);
+
+        if (!InternetCreateUrlW(&uc, 0, NULL, &len) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+        {
+            WCHAR *url = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+
+            if (url && InternetCreateUrlW(&uc, 0, url, &len) && CreateUrlCacheEntryW(url, 0, NULL, filename, 0))
+            {
+                lpwh->cache_file = heap_strdupW(filename);
+                lpwh->cache_file_handle = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ,
+                                                      NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+                if (lpwh->cache_file_handle == INVALID_HANDLE_VALUE)
+                {
+                    WARN("Could not create cache file: %u\n", GetLastError());
+                    HeapFree(GetProcessHeap(), 0, lpwh->cache_file);
+                    lpwh->cache_file = NULL;
+                }
+            }
+            HeapFree(GetProcessHeap(), 0, url);
+        }
+        HeapFree(GetProcessHeap(), 0, uc.lpszUrlPath);
+    }
 
     hIC = lpwfs->lpAppInfo;
     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
@@ -1339,16 +1420,20 @@ HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
 
        if (lpwh)
        {
-            iar.dwResult = (DWORD)handle;
+            iar.dwResult = (DWORD_PTR)handle;
             iar.dwError = ERROR_SUCCESS;
             SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
                 &iar, sizeof(INTERNET_ASYNC_RESULT));
        }
 
-        iar.dwResult = (DWORD)bSuccess;
-        iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
-        SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
-            &iar, sizeof(INTERNET_ASYNC_RESULT));
+        if(bSuccess) {
+            FTP_ReceiveRequestData(lpwh, TRUE);
+        }else {
+            iar.dwResult = 0;
+            iar.dwError = INTERNET_GetLastError();
+            SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
+                    &iar, sizeof(INTERNET_ASYNC_RESULT));
+        }
     }
 
 lend:
@@ -1359,6 +1444,119 @@ lend:
 }
 
 
+/***********************************************************************
+ *           FtpOpenFileA (WININET.@)
+ *
+ * Open a remote file for writing or reading
+ *
+ * RETURNS
+ *    HINTERNET handle on success
+ *    NULL on failure
+ *
+ */
+HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
+    LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
+    DWORD_PTR dwContext)
+{
+    LPWSTR lpwzFileName;
+    HINTERNET ret;
+
+    lpwzFileName = heap_strdupAtoW(lpszFileName);
+    ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
+    HeapFree(GetProcessHeap(), 0, lpwzFileName);
+    return ret;
+}
+
+
+static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
+{
+    struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
+
+    TRACE("%p\n", lpwfs);
+
+    FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
+        req->dwAccess, req->dwFlags, req->dwContext);
+    HeapFree(GetProcessHeap(), 0, req->lpszFilename);
+}
+
+/***********************************************************************
+ *           FtpOpenFileW (WININET.@)
+ *
+ * Open a remote file for writing or reading
+ *
+ * RETURNS
+ *    HINTERNET handle on success
+ *    NULL on failure
+ *
+ */
+HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
+    LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
+    DWORD_PTR dwContext)
+{
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
+    HINTERNET r = NULL;
+
+    TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
+        debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
+
+    lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
+    if (!lpwfs)
+    {
+        INTERNET_SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    if (WH_HFTPSESSION != lpwfs->hdr.htype)
+    {
+        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+        goto lend;
+    }
+
+    if ((!lpszFileName) ||
+        ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
+        ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
+    {
+        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        goto lend;
+    }
+
+    if (lpwfs->download_in_progress != NULL)
+    {
+        INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
+        goto lend;
+    }
+
+    hIC = lpwfs->lpAppInfo;
+    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+    {
+        WORKREQUEST workRequest;
+        struct WORKREQ_FTPOPENFILEW *req;
+
+        workRequest.asyncproc = AsyncFtpOpenFileProc;
+        workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
+        req = &workRequest.u.FtpOpenFileW;
+       req->lpszFilename = heap_strdupW(lpszFileName);
+       req->dwAccess = fdwAccess;
+       req->dwFlags = dwFlags;
+       req->dwContext = dwContext;
+
+       INTERNET_AsyncCall(&workRequest);
+       r = NULL;
+    }
+    else
+    {
+       r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
+    }
+
+lend:
+    WININET_Release( &lpwfs->hdr );
+
+    return r;
+}
+
+
 /***********************************************************************
  *           FtpGetFileA (WININET.@)
  *
@@ -1377,8 +1575,8 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN
     LPWSTR lpwzNewFile;
     BOOL ret;
     
-    lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
-    lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
+    lpwzRemoteFile = heap_strdupAtoW(lpszRemoteFile);
+    lpwzNewFile = heap_strdupAtoW(lpszNewFile);
     ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
         dwLocalFlagsAttribute, dwInternetFlags, dwContext);
     HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
@@ -1390,7 +1588,7 @@ BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszN
 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE("%p\n", lpwfs);
 
@@ -1416,8 +1614,8 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps
     BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
     DWORD_PTR dwContext)
 {
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
     BOOL r = FALSE;
 
     if (!lpszRemoteFile || !lpszNewFile)
@@ -1426,7 +1624,7 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps
         return FALSE;
     }
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hInternet );
     if (!lpwfs)
     {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
@@ -1460,14 +1658,14 @@ BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lps
         workRequest.asyncproc = AsyncFtpGetFileProc;
         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
         req = &workRequest.u.FtpGetFileW;
-        req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
-        req->lpszNewFile = WININET_strdupW(lpszNewFile);
+        req->lpszRemoteFile = heap_strdupW(lpszRemoteFile);
+        req->lpszNewFile = heap_strdupW(lpszNewFile);
        req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
        req->fFailIfExists = fFailIfExists;
        req->dwFlags = dwInternetFlags;
        req->dwContext = dwContext;
 
-       r = INTERNET_AsyncCall(&workRequest);
+       r = res_to_le(INTERNET_AsyncCall(&workRequest));
     }
     else
     {
@@ -1492,13 +1690,13 @@ lend:
  *    FALSE on failure
  *
  */
-static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
+static BOOL FTP_FtpGetFileW(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
        BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
        DWORD_PTR dwContext)
 {
     BOOL bSuccess = FALSE;
     HANDLE hFile;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
 
     TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
 
@@ -1537,7 +1735,10 @@ static BOOL FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile,
     }
 
     if (lpwfs->lstnSocket != -1)
+    {
         closesocket(lpwfs->lstnSocket);
+        lpwfs->lstnSocket = -1;
+    }
 
     CloseHandle(hFile);
 
@@ -1584,7 +1785,7 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
     LPWSTR lpwzFileName;
     BOOL ret;
     
-    lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
+    lpwzFileName = heap_strdupAtoW(lpszFileName);
     ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
     HeapFree(GetProcessHeap(), 0, lpwzFileName);
     return ret;
@@ -1593,7 +1794,7 @@ BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE("%p\n", lpwfs);
 
@@ -1613,11 +1814,11 @@ static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
  */
 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
 {
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
     BOOL r = FALSE;
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
     if (!lpwfs)
     {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
@@ -1651,9 +1852,9 @@ BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
         workRequest.asyncproc = AsyncFtpDeleteFileProc;
         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
         req = &workRequest.u.FtpDeleteFileW;
-        req->lpszFilename = WININET_strdupW(lpszFileName);
+        req->lpszFilename = heap_strdupW(lpszFileName);
 
-       r = INTERNET_AsyncCall(&workRequest);
+       r = res_to_le(INTERNET_AsyncCall(&workRequest));
     }
     else
     {
@@ -1676,11 +1877,11 @@ lend:
  *    FALSE on failure
  *
  */
-BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
+BOOL FTP_FtpDeleteFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
 
     TRACE("%p\n", lpwfs);
 
@@ -1729,7 +1930,7 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
     LPWSTR lpwzDirectory;
     BOOL ret;
     
-    lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
+    lpwzDirectory = heap_strdupAtoW(lpszDirectory);
     ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
     HeapFree(GetProcessHeap(), 0, lpwzDirectory);
     return ret;
@@ -1738,7 +1939,7 @@ BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE("%p\n", lpwfs);
 
@@ -1758,11 +1959,11 @@ static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
  */
 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
 {
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
     BOOL r = FALSE;
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
     if (!lpwfs)
     {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
@@ -1796,9 +1997,9 @@ BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
         workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
         req = &workRequest.u.FtpRemoveDirectoryW;
-        req->lpszDirectory = WININET_strdupW(lpszDirectory);
+        req->lpszDirectory = heap_strdupW(lpszDirectory);
 
-       r = INTERNET_AsyncCall(&workRequest);
+       r = res_to_le(INTERNET_AsyncCall(&workRequest));
     }
     else
     {
@@ -1821,11 +2022,11 @@ lend:
  *    FALSE on failure
  *
  */
-BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
+BOOL FTP_FtpRemoveDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
 
     TRACE("\n");
 
@@ -1876,8 +2077,8 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes
     LPWSTR lpwzDest;
     BOOL ret;
     
-    lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
-    lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
+    lpwzSrc = heap_strdupAtoW(lpszSrc);
+    lpwzDest = heap_strdupAtoW(lpszDest);
     ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
     HeapFree(GetProcessHeap(), 0, lpwzSrc);
     HeapFree(GetProcessHeap(), 0, lpwzDest);
@@ -1887,7 +2088,7 @@ BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDes
 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) workRequest->hdr;
 
     TRACE("%p\n", lpwfs);
 
@@ -1908,11 +2109,11 @@ static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
  */
 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
 {
-    LPWININETFTPSESSIONW lpwfs;
-    LPWININETAPPINFOW hIC = NULL;
+    ftp_session_t *lpwfs;
+    appinfo_t *hIC = NULL;
     BOOL r = FALSE;
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hFtpSession );
     if (!lpwfs)
     {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
@@ -1946,10 +2147,10 @@ BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszD
         workRequest.asyncproc = AsyncFtpRenameFileProc;
         workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
         req = &workRequest.u.FtpRenameFileW;
-        req->lpszSrcFile = WININET_strdupW(lpszSrc);
-        req->lpszDestFile = WININET_strdupW(lpszDest);
+        req->lpszSrcFile = heap_strdupW(lpszSrc);
+        req->lpszDestFile = heap_strdupW(lpszDest);
 
-       r = INTERNET_AsyncCall(&workRequest);
+       r = res_to_le(INTERNET_AsyncCall(&workRequest));
     }
     else
     {
@@ -1972,12 +2173,11 @@ lend:
  *    FALSE on failure
  *
  */
-BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
-                         LPCWSTR lpszSrc, LPCWSTR lpszDest)
+BOOL FTP_FtpRenameFileW(ftp_session_t *lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
-    LPWININETAPPINFOW hIC = NULL;
+    appinfo_t *hIC = NULL;
 
     TRACE("\n");
 
@@ -2040,7 +2240,7 @@ BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags
         return FALSE;
     }
 
-    if (!(cmdW = WININET_strdup_AtoW(lpszCommand)))
+    if (!(cmdW = heap_strdupAtoW(lpszCommand)))
     {
         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
         return FALSE;
@@ -2059,7 +2259,7 @@ BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags
                          LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
 {
     BOOL r = FALSE;
-    LPWININETFTPSESSIONW lpwfs;
+    ftp_session_t *lpwfs;
     LPSTR cmd = NULL;
     DWORD len, nBytesSent= 0;
     INT nResCode, nRC = 0;
@@ -2079,7 +2279,7 @@ BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags
         return FALSE;
     }
 
-    lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
+    lpwfs = (ftp_session_t*) WININET_GetObject( hConnect );
     if (!lpwfs)
     {
         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
@@ -2142,9 +2342,9 @@ lend:
  *
  * Deallocate session handle
  */
-static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr)
+static void FTPSESSION_Destroy(object_header_t *hdr)
 {
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) hdr;
 
     TRACE("\n");
 
@@ -2152,12 +2352,13 @@ static void FTPSESSION_Destroy(WININETHANDLEHEADER *hdr)
 
     HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
     HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
+    HeapFree(GetProcessHeap(), 0, lpwfs->servername);
     HeapFree(GetProcessHeap(), 0, lpwfs);
 }
 
-static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr)
+static void FTPSESSION_CloseConnection(object_header_t *hdr)
 {
-    LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
+    ftp_session_t *lpwfs = (ftp_session_t*) hdr;
 
     TRACE("\n");
 
@@ -2180,7 +2381,7 @@ static void FTPSESSION_CloseConnection(WININETHANDLEHEADER *hdr)
                       INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
 }
 
-static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+static DWORD FTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
 {
     switch(option) {
     case INTERNET_OPTION_HANDLE_TYPE:
@@ -2197,7 +2398,7 @@ static DWORD FTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void
     return INET_QueryOption(option, buffer, size, unicode);
 }
 
-static const HANDLEHEADERVtbl FTPSESSIONVtbl = {
+static const object_vtbl_t FTPSESSIONVtbl = {
     FTPSESSION_Destroy,
     FTPSESSION_CloseConnection,
     FTPSESSION_QueryOption,
@@ -2230,7 +2431,7 @@ static const HANDLEHEADERVtbl FTPSESSIONVtbl = {
  *
  */
 
-HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
+HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
        INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
        LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
        DWORD dwInternalFlags)
@@ -2247,8 +2448,9 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
     INT nsocket = -1;
     UINT sock_namelen;
     BOOL bSuccess = FALSE;
-    LPWININETFTPSESSIONW lpwfs = NULL;
+    ftp_session_t *lpwfs = NULL;
     HINTERNET handle = NULL;
+    char szaddr[INET_ADDRSTRLEN];
 
     TRACE("%p  Server(%s) Port(%d) User(%s) Paswd(%s)\n",
            hIC, debugstr_w(lpszServerName),
@@ -2256,13 +2458,13 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
 
     assert( hIC->hdr.htype == WH_HINIT );
 
-    if (NULL == lpszUserName && NULL != lpszPassword)
+    if ((!lpszUserName || !*lpszUserName) && lpszPassword && *lpszPassword)
     {
        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
         goto lerror;
     }
     
-    lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
+    lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(ftp_session_t));
     if (NULL == lpwfs)
     {
         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
@@ -2270,7 +2472,9 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
     }
 
     if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
-       nServerPort = INTERNET_DEFAULT_FTP_PORT;
+        lpwfs->serverport = INTERNET_DEFAULT_FTP_PORT;
+    else
+        lpwfs->serverport = nServerPort;
 
     lpwfs->hdr.htype = WH_HFTPSESSION;
     lpwfs->hdr.vtbl = &FTPSESSIONVtbl;
@@ -2302,12 +2506,12 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
         if(hIC->lpszProxyBypass)
             FIXME("Proxy bypass is ignored.\n");
     }
-    if ( !lpszUserName) {
+    if (!lpszUserName || !strlenW(lpszUserName)) {
         HKEY key;
         WCHAR szPassword[MAX_PATH];
         DWORD len = sizeof(szPassword);
 
-        lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
+        lpwfs->lpszUserName = heap_strdupW(szDefaultUsername);
 
         RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
         if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
@@ -2320,23 +2524,20 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
         RegCloseKey(key);
 
         TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
-        lpwfs->lpszPassword = WININET_strdupW(szPassword);
+        lpwfs->lpszPassword = heap_strdupW(szPassword);
     }
     else {
-        lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
-
-        if (lpszPassword)
-            lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
-        else
-            lpwfs->lpszPassword = WININET_strdupW(szEmpty);
+        lpwfs->lpszUserName = heap_strdupW(lpszUserName);
+        lpwfs->lpszPassword = heap_strdupW(lpszPassword ? lpszPassword : szEmpty);
     }
+    lpwfs->servername = heap_strdupW(lpszServerName);
     
     /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
     if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
     {
         INTERNET_ASYNC_RESULT iar;
 
-        iar.dwResult = (DWORD)handle;
+        iar.dwResult = (DWORD_PTR)handle;
         iar.dwError = ERROR_SUCCESS;
 
         SendAsyncCallback(&hIC->hdr, dwContext,
@@ -2345,16 +2546,25 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
     }
         
     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
-        (LPWSTR) lpszServerName, strlenW(lpszServerName));
+        (LPWSTR) lpszServerName, (strlenW(lpszServerName)+1) * sizeof(WCHAR));
 
-    if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
+    sock_namelen = sizeof(socketAddr);
+    if (!GetAddress(lpszServerName, lpwfs->serverport, (struct sockaddr *)&socketAddr, &sock_namelen))
     {
        INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
         goto lerror;
     }
 
+    if (socketAddr.sin_family != AF_INET)
+    {
+        WARN("unsupported address family %d\n", socketAddr.sin_family);
+        INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
+        goto lerror;
+    }
+
+    inet_ntop(socketAddr.sin_family, &socketAddr.sin_addr, szaddr, sizeof(szaddr));
     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
-        (LPWSTR) lpszServerName, strlenW(lpszServerName));
+                      szaddr, strlen(szaddr)+1);
 
     nsocket = socket(AF_INET,SOCK_STREAM,0);
     if (nsocket == -1)
@@ -2364,19 +2574,20 @@ HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
     }
 
     SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
-        &socketAddr, sizeof(struct sockaddr_in));
+                      szaddr, strlen(szaddr)+1);
 
-    if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
+    if (connect(nsocket, (struct sockaddr *)&socketAddr, sock_namelen) < 0)
     {
        ERR("Unable to connect (%s)\n", strerror(errno));
        INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
+       closesocket(nsocket);
     }
     else
     {
         TRACE("Connected to server\n");
        lpwfs->sndSocket = nsocket;
         SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
-            &socketAddr, sizeof(struct sockaddr_in));
+                          szaddr, strlen(szaddr)+1);
 
        sock_namelen = sizeof(lpwfs->socketAddress);
        getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
@@ -2397,16 +2608,6 @@ lerror:
         handle = NULL;
     }
 
-    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        INTERNET_ASYNC_RESULT iar;
-
-        iar.dwResult = bSuccess ? (DWORD_PTR)lpwfs : 0;
-        iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
-        SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
-            &iar, sizeof(INTERNET_ASYNC_RESULT));
-    }
-
     return handle;
 }
 
@@ -2421,7 +2622,7 @@ lerror:
  *   NULL on failure
  *
  */
-static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
+static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
@@ -2465,7 +2666,7 @@ lend:
  *
  */
 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
-       INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
+       INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext)
 {
        DWORD len;
        CHAR *buf;
@@ -2520,10 +2721,10 @@ static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
  *
  */
 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
-       INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
+       INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext)
 {
     BOOL ret;
-    LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
+    LPSTR lpszParamA = heap_strdupWtoA(lpszParam);
     ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
     HeapFree(GetProcessHeap(), 0, lpszParamA);
     return ret;
@@ -2539,7 +2740,7 @@ static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
  *   0 on failure
  *
  */
-INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext)
+INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext)
 {
     LPSTR lpszResponse = INTERNET_GetResponseBuffer();
     DWORD nRecv;
@@ -2602,7 +2803,7 @@ lerror:
  *   NULL on failure
  *
  */
-static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
+static BOOL FTP_SendPassword(ftp_session_t *lpwfs)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
@@ -2642,7 +2843,7 @@ lend:
  *   FALSE on failure
  *
  */
-static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
+static BOOL FTP_SendAccount(ftp_session_t *lpwfs)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
@@ -2672,7 +2873,7 @@ lend:
  *   FALSE on failure
  *
  */
-static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
+static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
@@ -2719,10 +2920,10 @@ lend:
  *   FALSE on failure
  *
  */
-static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
+static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs)
 {
     BOOL bSuccess = FALSE;
-    socklen_t namelen = sizeof(struct sockaddr_in);
+    socklen_t namelen = sizeof(lpwfs->lstnSocketAddress);
 
     TRACE("\n");
 
@@ -2737,9 +2938,9 @@ static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
     lpwfs->lstnSocketAddress = lpwfs->socketAddress;
 
     /* and get the system to assign us a port */
-    lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
+    lpwfs->lstnSocketAddress.sin_port = htons(0);
 
-    if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
+    if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1)
     {
         TRACE("Unable to bind socket\n");
         goto lend;
@@ -2778,7 +2979,7 @@ lend:
  * (i.e. it sends it always),
  * so we probably don't want to do that either.
  */
-static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
+static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType)
 {
     INT nResCode;
     WCHAR type[] = { 'I','\0' };
@@ -2816,7 +3017,7 @@ lend:
  *   FALSE on failure
  *
  */
-static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
+static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
@@ -2860,7 +3061,7 @@ lend:
  *   FALSE on failure
  *
  */
-static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
+static BOOL FTP_SendPort(ftp_session_t *lpwfs)
 {
     static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
     INT nResCode;
@@ -2904,7 +3105,7 @@ lend:
  *   FALSE on failure
  *
  */
-static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
+static BOOL FTP_DoPassive(ftp_session_t *lpwfs)
 {
     INT nResCode;
     BOOL bSuccess = FALSE;
@@ -2976,7 +3177,7 @@ lend:
 }
 
 
-static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
+static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs)
 {
     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
     {
@@ -3005,7 +3206,7 @@ static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
  *   FALSE on failure
  *
  */
-static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
+static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket)
 {
     struct sockaddr_in saddr;
     socklen_t addrlen = sizeof(struct sockaddr);
@@ -3014,6 +3215,7 @@ static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
     {
        *nDataSocket = lpwfs->pasvSocket;
+       lpwfs->pasvSocket = -1;
     }
     else
     {
@@ -3035,7 +3237,7 @@ static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
  *   FALSE on failure
  *
  */
-static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
+static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile)
 {
     BY_HANDLE_FILE_INFORMATION fi;
     DWORD nBytesRead = 0;
@@ -3116,7 +3318,7 @@ static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFi
  *   0 on failure
  *
  */
-static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
+static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
 {
     INT nResCode;
     BOOL ret;
@@ -3162,7 +3364,7 @@ lend:
  *   FALSE on failure
  *
  */
-static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
+static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile)
 {
     DWORD nBytesWritten;
     INT nRC = 0;
@@ -3202,7 +3404,7 @@ recv_end:
  *
  * Deallocate session handle
  */
-static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr)
+static void FTPFINDNEXT_Destroy(object_header_t *hdr)
 {
     LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
     DWORD i;
@@ -3220,7 +3422,7 @@ static void FTPFINDNEXT_Destroy(WININETHANDLEHEADER *hdr)
     HeapFree(GetProcessHeap(), 0, lpwfn);
 }
 
-static DWORD WINAPI FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data)
+static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data)
 {
     WIN32_FIND_DATAW *find_data = data;
     DWORD res = ERROR_SUCCESS;
@@ -3260,7 +3462,7 @@ static void FTPFINDNEXT_AsyncFindNextFileProc(WORKREQUEST *workRequest)
     FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)workRequest->hdr, req->lpFindFileData);
 }
 
-static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
 {
     switch(option) {
     case INTERNET_OPTION_HANDLE_TYPE:
@@ -3277,7 +3479,7 @@ static DWORD FTPFINDNEXT_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, voi
     return INET_QueryOption(option, buffer, size, unicode);
 }
 
-static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data)
+static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data)
 {
     WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr;
 
@@ -3299,7 +3501,7 @@ static DWORD FTPFINDNEXT_FindNextFileW(WININETHANDLEHEADER *hdr, void *data)
     return FTPFINDNEXT_FindNextFileProc(find, data);
 }
 
-static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = {
+static const object_vtbl_t FTPFINDNEXTVtbl = {
     FTPFINDNEXT_Destroy,
     NULL,
     FTPFINDNEXT_QueryOption,
@@ -3308,6 +3510,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = {
     NULL,
     NULL,
     NULL,
+    NULL,
     FTPFINDNEXT_FindNextFileW
 };
 
@@ -3321,7 +3524,7 @@ static const HANDLEHEADERVtbl FTPFINDNEXTVtbl = {
  *   NULL on failure
  *
  */
-static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
+static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
        LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
 {
     DWORD dwSize = 0;
@@ -3382,9 +3585,7 @@ static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFi
 
     if (lpafp)
     {
-       /* Convert 'Unix' time to Windows time */
-       RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
-                                 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
+        SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime );
        lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
        lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
        
@@ -3452,12 +3653,12 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT
                 lpfp->nSize = atol(pszToken);
             }
             
-            lpfp->tmLastModified.tm_sec  = 0;
-            lpfp->tmLastModified.tm_min  = 0;
-            lpfp->tmLastModified.tm_hour = 0;
-            lpfp->tmLastModified.tm_mday = 0;
-            lpfp->tmLastModified.tm_mon  = 0;
-            lpfp->tmLastModified.tm_year = 0;
+            lpfp->tmLastModified.wSecond = 0;
+            lpfp->tmLastModified.wMinute = 0;
+            lpfp->tmLastModified.wHour   = 0;
+            lpfp->tmLastModified.wDay    = 0;
+            lpfp->tmLastModified.wMonth  = 0;
+            lpfp->tmLastModified.wYear   = 0;
             
             /* Determine month */
             pszToken = strtok(NULL, szSpace);
@@ -3465,38 +3666,35 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT
             if(strlen(pszToken) >= 3) {
                 pszToken[3] = 0;
                 if((pszTmp = StrStrIA(szMonths, pszToken)))
-                    lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
+                    lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1;
             }
             /* Determine day */
             pszToken = strtok(NULL, szSpace);
             if(!pszToken) continue;
-            lpfp->tmLastModified.tm_mday = atoi(pszToken);
+            lpfp->tmLastModified.wDay = atoi(pszToken);
             /* Determine time or year */
             pszToken = strtok(NULL, szSpace);
             if(!pszToken) continue;
             if((pszTmp = strchr(pszToken, ':'))) {
-                struct tm* apTM;
-                time_t aTime;
+                SYSTEMTIME curr_time;
                 *pszTmp = 0;
                 pszTmp++;
-                lpfp->tmLastModified.tm_min = atoi(pszTmp);
-                lpfp->tmLastModified.tm_hour = atoi(pszToken);
-                time(&aTime);
-                apTM = localtime(&aTime);
-                lpfp->tmLastModified.tm_year = apTM->tm_year;
+                lpfp->tmLastModified.wMinute = atoi(pszTmp);
+                lpfp->tmLastModified.wHour = atoi(pszToken);
+                GetLocalTime( &curr_time );
+                lpfp->tmLastModified.wYear = curr_time.wYear;
             }
             else {
-                lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
-                lpfp->tmLastModified.tm_hour = 12;
+                lpfp->tmLastModified.wYear = atoi(pszToken);
+                lpfp->tmLastModified.wHour = 12;
             }
-            TRACE("Mod time: %02d:%02d:%02d  %02d/%02d/%02d\n",
-                lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
-                (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
-                lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
+            TRACE("Mod time: %02d:%02d:%02d  %04d/%02d/%02d\n",
+                  lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond,
+                  lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay);
 
             pszToken = strtok(NULL, szSpace);
             if(!pszToken) continue;
-            lpfp->lpszName = WININET_strdup_AtoW(pszToken);
+            lpfp->lpszName = heap_strdupAtoW(pszToken);
             TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
         }
         /* NT way of parsing ... :
@@ -3505,32 +3703,31 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT
                 05-09-03  06:02PM             12656686 2003-04-21bgm_cmd_e.rgz
         */
         else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
+            int mon, mday, year, hour, min;
             lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
             
-            sscanf(pszToken, "%d-%d-%d",
-                &lpfp->tmLastModified.tm_mon,
-                &lpfp->tmLastModified.tm_mday,
-                &lpfp->tmLastModified.tm_year);
+            sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year);
+            lpfp->tmLastModified.wDay   = mday;
+            lpfp->tmLastModified.wMonth = mon;
+            lpfp->tmLastModified.wYear  = year;
 
             /* Hacky and bad Y2K protection :-) */
-            if (lpfp->tmLastModified.tm_year < 70)
-                lpfp->tmLastModified.tm_year += 100;
-            
+            if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000;
+
             pszToken = strtok(NULL, szSpace);
             if(!pszToken) continue;
-            sscanf(pszToken, "%d:%d",
-                &lpfp->tmLastModified.tm_hour,
-                &lpfp->tmLastModified.tm_min);
+            sscanf(pszToken, "%d:%d", &hour, &min);
+            lpfp->tmLastModified.wHour   = hour;
+            lpfp->tmLastModified.wMinute = min;
             if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
-                lpfp->tmLastModified.tm_hour += 12;
+                lpfp->tmLastModified.wHour += 12;
             }
-            lpfp->tmLastModified.tm_sec = 0;
+            lpfp->tmLastModified.wSecond = 0;
+
+            TRACE("Mod time: %02d:%02d:%02d  %04d/%02d/%02d\n",
+                  lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond,
+                  lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay);
 
-            TRACE("Mod time: %02d:%02d:%02d  %02d/%02d/%02d\n",
-                lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
-                (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
-                lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
-            
             pszToken = strtok(NULL, szSpace);
             if(!pszToken) continue;
             if(!strcasecmp(pszToken, "<DIR>")) {
@@ -3546,7 +3743,7 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT
             
             pszToken = strtok(NULL, szSpace);
             if(!pszToken) continue;
-            lpfp->lpszName = WININET_strdup_AtoW(pszToken);
+            lpfp->lpszName = heap_strdupAtoW(pszToken);
             TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
         }
         /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
@@ -3578,7 +3775,7 @@ static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERT
  *   TRUE on success
  *   FALSE on failure
  */
-static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
+static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
     LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
 {
     BOOL bSuccess = TRUE;