xref: /reactos/dll/win32/wininet/ftp.c (revision e152f78a)
15f12c8d7Swinesync #ifdef __REACTOS__
25f12c8d7Swinesync #include "precomp.h"
35f12c8d7Swinesync #else
4c2c66affSColin Finck /*
5c2c66affSColin Finck  * WININET - Ftp implementation
6c2c66affSColin Finck  *
7c2c66affSColin Finck  * Copyright 1999 Corel Corporation
8c2c66affSColin Finck  * Copyright 2004 Mike McCormack for CodeWeavers
9c2c66affSColin Finck  * Copyright 2004 Kevin Koltzau
10c2c66affSColin Finck  * Copyright 2007 Hans Leidekker
11c2c66affSColin Finck  *
12c2c66affSColin Finck  * Ulrich Czekalla
13c2c66affSColin Finck  * Noureddine Jemmali
14c2c66affSColin Finck  *
15c2c66affSColin Finck  * Copyright 2000 Andreas Mohr
16c2c66affSColin Finck  * Copyright 2002 Jaco Greeff
17c2c66affSColin Finck  *
18c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
19c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
20c2c66affSColin Finck  * License as published by the Free Software Foundation; either
21c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
22c2c66affSColin Finck  *
23c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
24c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26c2c66affSColin Finck  * Lesser General Public License for more details.
27c2c66affSColin Finck  *
28c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
29c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
30c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31c2c66affSColin Finck  */
32c2c66affSColin Finck 
33bc01cef0SAmine Khaldi #include "ws2tcpip.h"
34bc01cef0SAmine Khaldi 
35bc01cef0SAmine Khaldi #include <stdarg.h>
36bc01cef0SAmine Khaldi #include <stdio.h>
37bc01cef0SAmine Khaldi #include <stdlib.h>
38bc01cef0SAmine Khaldi #include <string.h>
39bc01cef0SAmine Khaldi #include <time.h>
40bc01cef0SAmine Khaldi #include <assert.h>
41bc01cef0SAmine Khaldi 
42bc01cef0SAmine Khaldi #include "windef.h"
43bc01cef0SAmine Khaldi #include "winbase.h"
44bc01cef0SAmine Khaldi #include "wingdi.h"
45bc01cef0SAmine Khaldi #include "winuser.h"
46bc01cef0SAmine Khaldi #include "wininet.h"
47bc01cef0SAmine Khaldi #include "winnls.h"
48bc01cef0SAmine Khaldi #include "winerror.h"
49bc01cef0SAmine Khaldi #include "winreg.h"
50bc01cef0SAmine Khaldi #include "winternl.h"
51bc01cef0SAmine Khaldi #include "shlwapi.h"
52bc01cef0SAmine Khaldi 
53bc01cef0SAmine Khaldi #include "wine/debug.h"
54c2c66affSColin Finck #include "internet.h"
555f12c8d7Swinesync #endif /* defined(__REACTOS__) */
56c2c66affSColin Finck 
57bc01cef0SAmine Khaldi WINE_DEFAULT_DEBUG_CHANNEL(wininet);
58bc01cef0SAmine Khaldi 
59c2c66affSColin Finck #define RESPONSE_TIMEOUT        30
60c2c66affSColin Finck 
61c2c66affSColin Finck typedef struct _ftp_session_t ftp_session_t;
62c2c66affSColin Finck 
63c2c66affSColin Finck typedef struct
64c2c66affSColin Finck {
65c2c66affSColin Finck     object_header_t hdr;
66c2c66affSColin Finck     ftp_session_t *lpFtpSession;
67c2c66affSColin Finck     BOOL session_deleted;
68c2c66affSColin Finck     int nDataSocket;
69c2c66affSColin Finck     WCHAR *cache_file;
70c2c66affSColin Finck     HANDLE cache_file_handle;
71c2c66affSColin Finck } ftp_file_t;
72c2c66affSColin Finck 
73c2c66affSColin Finck struct _ftp_session_t
74c2c66affSColin Finck {
75c2c66affSColin Finck     object_header_t hdr;
76c2c66affSColin Finck     appinfo_t *lpAppInfo;
77c2c66affSColin Finck     int sndSocket;
78c2c66affSColin Finck     int lstnSocket;
79c2c66affSColin Finck     int pasvSocket; /* data socket connected by us in case of passive FTP */
80c2c66affSColin Finck     ftp_file_t *download_in_progress;
81c2c66affSColin Finck     struct sockaddr_in socketAddress;
82c2c66affSColin Finck     struct sockaddr_in lstnSocketAddress;
83c2c66affSColin Finck     LPWSTR servername;
84c2c66affSColin Finck     INTERNET_PORT serverport;
85c2c66affSColin Finck     LPWSTR  lpszPassword;
86c2c66affSColin Finck     LPWSTR  lpszUserName;
87c2c66affSColin Finck };
88c2c66affSColin Finck 
89c2c66affSColin Finck typedef struct
90c2c66affSColin Finck {
91c2c66affSColin Finck     BOOL bIsDirectory;
92c2c66affSColin Finck     LPWSTR lpszName;
93c2c66affSColin Finck     DWORD nSize;
94c2c66affSColin Finck     SYSTEMTIME tmLastModified;
95c2c66affSColin Finck     unsigned short permissions;
96c2c66affSColin Finck } FILEPROPERTIESW, *LPFILEPROPERTIESW;
97c2c66affSColin Finck 
98c2c66affSColin Finck typedef struct
99c2c66affSColin Finck {
100c2c66affSColin Finck     object_header_t hdr;
101c2c66affSColin Finck     ftp_session_t *lpFtpSession;
102c2c66affSColin Finck     DWORD index;
103c2c66affSColin Finck     DWORD size;
104c2c66affSColin Finck     LPFILEPROPERTIESW lpafp;
105c2c66affSColin Finck } WININETFTPFINDNEXTW, *LPWININETFTPFINDNEXTW;
106c2c66affSColin Finck 
107c2c66affSColin Finck #define DATA_PACKET_SIZE 	0x2000
108c2c66affSColin Finck #define szCRLF 			"\r\n"
109c2c66affSColin Finck #define MAX_BACKLOG 		5
110c2c66affSColin Finck 
111c2c66affSColin Finck /* Testing shows that Windows only accepts dwFlags where the last
112c2c66affSColin Finck  * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY.
113c2c66affSColin Finck  */
114c2c66affSColin Finck #define FTP_CONDITION_MASK      0x0007
115c2c66affSColin Finck 
116c2c66affSColin Finck typedef enum {
117c2c66affSColin Finck   /* FTP commands with arguments. */
118c2c66affSColin Finck   FTP_CMD_ACCT,
119c2c66affSColin Finck   FTP_CMD_CWD,
120c2c66affSColin Finck   FTP_CMD_DELE,
121c2c66affSColin Finck   FTP_CMD_MKD,
122c2c66affSColin Finck   FTP_CMD_PASS,
123c2c66affSColin Finck   FTP_CMD_PORT,
124c2c66affSColin Finck   FTP_CMD_RETR,
125c2c66affSColin Finck   FTP_CMD_RMD,
126c2c66affSColin Finck   FTP_CMD_RNFR,
127c2c66affSColin Finck   FTP_CMD_RNTO,
128c2c66affSColin Finck   FTP_CMD_STOR,
129c2c66affSColin Finck   FTP_CMD_TYPE,
130c2c66affSColin Finck   FTP_CMD_USER,
131c2c66affSColin Finck   FTP_CMD_SIZE,
132c2c66affSColin Finck 
133c2c66affSColin Finck   /* FTP commands without arguments. */
134c2c66affSColin Finck   FTP_CMD_ABOR,
135c2c66affSColin Finck   FTP_CMD_LIST,
136c2c66affSColin Finck   FTP_CMD_NLST,
137c2c66affSColin Finck   FTP_CMD_PASV,
138c2c66affSColin Finck   FTP_CMD_PWD,
139c2c66affSColin Finck   FTP_CMD_QUIT,
140c2c66affSColin Finck } FTP_COMMAND;
141c2c66affSColin Finck 
142c2c66affSColin Finck static const CHAR *const szFtpCommands[] = {
143c2c66affSColin Finck   "ACCT",
144c2c66affSColin Finck   "CWD",
145c2c66affSColin Finck   "DELE",
146c2c66affSColin Finck   "MKD",
147c2c66affSColin Finck   "PASS",
148c2c66affSColin Finck   "PORT",
149c2c66affSColin Finck   "RETR",
150c2c66affSColin Finck   "RMD",
151c2c66affSColin Finck   "RNFR",
152c2c66affSColin Finck   "RNTO",
153c2c66affSColin Finck   "STOR",
154c2c66affSColin Finck   "TYPE",
155c2c66affSColin Finck   "USER",
156c2c66affSColin Finck   "SIZE",
157c2c66affSColin Finck   "ABOR",
158c2c66affSColin Finck   "LIST",
159c2c66affSColin Finck   "NLST",
160c2c66affSColin Finck   "PASV",
161c2c66affSColin Finck   "PWD",
162c2c66affSColin Finck   "QUIT",
163c2c66affSColin Finck };
164c2c66affSColin Finck 
165c2c66affSColin Finck static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
166c2c66affSColin Finck 
167c2c66affSColin Finck static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
168c2c66affSColin Finck 	INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext);
169c2c66affSColin Finck static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType);
170c2c66affSColin Finck static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket);
171c2c66affSColin Finck static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile);
172c2c66affSColin Finck static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext);
173c2c66affSColin Finck static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType);
174c2c66affSColin Finck static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile);
175c2c66affSColin Finck static BOOL FTP_InitListenSocket(ftp_session_t*);
176c2c66affSColin Finck static BOOL FTP_ConnectToHost(ftp_session_t*);
177c2c66affSColin Finck static BOOL FTP_SendPassword(ftp_session_t*);
178c2c66affSColin Finck static BOOL FTP_SendAccount(ftp_session_t*);
179c2c66affSColin Finck static BOOL FTP_SendType(ftp_session_t*, DWORD dwType);
180c2c66affSColin Finck static BOOL FTP_SendPort(ftp_session_t*);
181c2c66affSColin Finck static BOOL FTP_DoPassive(ftp_session_t*);
182c2c66affSColin Finck static BOOL FTP_SendPortOrPasv(ftp_session_t*);
183c2c66affSColin Finck static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
184c2c66affSColin Finck static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
185c2c66affSColin Finck static BOOL FTP_ParseDirectory(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile,
186c2c66affSColin Finck         LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
187c2c66affSColin Finck static HINTERNET FTP_ReceiveFileList(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile,
188c2c66affSColin Finck         LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext);
189c2c66affSColin Finck static DWORD FTP_SetResponseError(DWORD dwResponse);
190c2c66affSColin Finck static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData);
191c2c66affSColin Finck static BOOL FTP_FtpPutFileW(ftp_session_t*, LPCWSTR lpszLocalFile,
192c2c66affSColin Finck         LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext);
193c2c66affSColin Finck static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
194c2c66affSColin Finck static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
195c2c66affSColin Finck static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*,
196c2c66affSColin Finck         LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext);
197c2c66affSColin Finck static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory,
198c2c66affSColin Finck         LPDWORD lpdwCurrentDirectory);
199c2c66affSColin Finck static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest);
200c2c66affSColin Finck static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
201c2c66affSColin Finck static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName);
202c2c66affSColin Finck static BOOL FTP_FtpGetFileW(ftp_session_t*, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
203c2c66affSColin Finck         BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
204c2c66affSColin Finck         DWORD_PTR dwContext);
205c2c66affSColin Finck 
206c2c66affSColin Finck /* A temporary helper until we get rid of INTERNET_GetLastError calls */
res_to_le(DWORD res)207c2c66affSColin Finck static BOOL res_to_le(DWORD res)
208c2c66affSColin Finck {
209c2c66affSColin Finck     if(res != ERROR_SUCCESS)
210c2c66affSColin Finck         INTERNET_SetLastError(res);
211c2c66affSColin Finck     return res == ERROR_SUCCESS;
212c2c66affSColin Finck }
213c2c66affSColin Finck 
214c2c66affSColin Finck /***********************************************************************
215c2c66affSColin Finck  *           FtpPutFileA (WININET.@)
216c2c66affSColin Finck  *
217c2c66affSColin Finck  * Uploads a file to the FTP server
218c2c66affSColin Finck  *
219c2c66affSColin Finck  * RETURNS
220c2c66affSColin Finck  *    TRUE on success
221c2c66affSColin Finck  *    FALSE on failure
222c2c66affSColin Finck  *
223c2c66affSColin Finck  */
FtpPutFileA(HINTERNET hConnect,LPCSTR lpszLocalFile,LPCSTR lpszNewRemoteFile,DWORD dwFlags,DWORD_PTR dwContext)224c2c66affSColin Finck BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
225c2c66affSColin Finck     LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
226c2c66affSColin Finck {
227c2c66affSColin Finck     LPWSTR lpwzLocalFile;
228c2c66affSColin Finck     LPWSTR lpwzNewRemoteFile;
229c2c66affSColin Finck     BOOL ret;
230c2c66affSColin Finck 
231c2c66affSColin Finck     lpwzLocalFile = heap_strdupAtoW(lpszLocalFile);
232c2c66affSColin Finck     lpwzNewRemoteFile = heap_strdupAtoW(lpszNewRemoteFile);
233c2c66affSColin Finck     ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
234c2c66affSColin Finck                       dwFlags, dwContext);
235c2c66affSColin Finck     heap_free(lpwzLocalFile);
236c2c66affSColin Finck     heap_free(lpwzNewRemoteFile);
237c2c66affSColin Finck     return ret;
238c2c66affSColin Finck }
239c2c66affSColin Finck 
240c2c66affSColin Finck typedef struct {
241c2c66affSColin Finck     task_header_t hdr;
242c2c66affSColin Finck     WCHAR *local_file;
243c2c66affSColin Finck     WCHAR *remote_file;
244c2c66affSColin Finck     DWORD flags;
245c2c66affSColin Finck     DWORD_PTR context;
246c2c66affSColin Finck } put_file_task_t;
247c2c66affSColin Finck 
AsyncFtpPutFileProc(task_header_t * hdr)248c2c66affSColin Finck static void AsyncFtpPutFileProc(task_header_t *hdr)
249c2c66affSColin Finck {
250c2c66affSColin Finck     put_file_task_t *task = (put_file_task_t*)hdr;
251c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
252c2c66affSColin Finck 
253c2c66affSColin Finck     TRACE("%p\n", session);
254c2c66affSColin Finck 
255c2c66affSColin Finck     FTP_FtpPutFileW(session, task->local_file, task->remote_file,
256c2c66affSColin Finck                task->flags, task->context);
257c2c66affSColin Finck 
258c2c66affSColin Finck     heap_free(task->local_file);
259c2c66affSColin Finck     heap_free(task->remote_file);
260c2c66affSColin Finck }
261c2c66affSColin Finck 
262c2c66affSColin Finck /***********************************************************************
263c2c66affSColin Finck  *           FtpPutFileW (WININET.@)
264c2c66affSColin Finck  *
265c2c66affSColin Finck  * Uploads a file to the FTP server
266c2c66affSColin Finck  *
267c2c66affSColin Finck  * RETURNS
268c2c66affSColin Finck  *    TRUE on success
269c2c66affSColin Finck  *    FALSE on failure
270c2c66affSColin Finck  *
271c2c66affSColin Finck  */
FtpPutFileW(HINTERNET hConnect,LPCWSTR lpszLocalFile,LPCWSTR lpszNewRemoteFile,DWORD dwFlags,DWORD_PTR dwContext)272c2c66affSColin Finck BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
273c2c66affSColin Finck     LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
274c2c66affSColin Finck {
275c2c66affSColin Finck     ftp_session_t *lpwfs;
276c2c66affSColin Finck     appinfo_t *hIC = NULL;
277c2c66affSColin Finck     BOOL r = FALSE;
278c2c66affSColin Finck 
279c2c66affSColin Finck     if (!lpszLocalFile || !lpszNewRemoteFile)
280c2c66affSColin Finck     {
281c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
282c2c66affSColin Finck         return FALSE;
283c2c66affSColin Finck     }
284c2c66affSColin Finck 
285c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hConnect );
286c2c66affSColin Finck     if (!lpwfs)
287c2c66affSColin Finck     {
288c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
289c2c66affSColin Finck         return FALSE;
290c2c66affSColin Finck     }
291c2c66affSColin Finck 
292c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
293c2c66affSColin Finck     {
294c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
295c2c66affSColin Finck         goto lend;
296c2c66affSColin Finck     }
297c2c66affSColin Finck 
298c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
299c2c66affSColin Finck     {
300c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
301c2c66affSColin Finck         goto lend;
302c2c66affSColin Finck     }
303c2c66affSColin Finck 
304c2c66affSColin Finck     if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
305c2c66affSColin Finck     {
306c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
307c2c66affSColin Finck         goto lend;
308c2c66affSColin Finck     }
309c2c66affSColin Finck 
310c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
311c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
312c2c66affSColin Finck     {
313c2c66affSColin Finck         put_file_task_t *task = alloc_async_task(&lpwfs->hdr, AsyncFtpPutFileProc, sizeof(*task));
314c2c66affSColin Finck 
315c2c66affSColin Finck         task->local_file = heap_strdupW(lpszLocalFile);
316c2c66affSColin Finck         task->remote_file = heap_strdupW(lpszNewRemoteFile);
317c2c66affSColin Finck         task->flags = dwFlags;
318c2c66affSColin Finck         task->context = dwContext;
319c2c66affSColin Finck 
320c2c66affSColin Finck         r = res_to_le(INTERNET_AsyncCall(&task->hdr));
321c2c66affSColin Finck     }
322c2c66affSColin Finck     else
323c2c66affSColin Finck     {
324c2c66affSColin Finck         r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
325c2c66affSColin Finck 	    lpszNewRemoteFile, dwFlags, dwContext);
326c2c66affSColin Finck     }
327c2c66affSColin Finck 
328c2c66affSColin Finck lend:
329c2c66affSColin Finck     WININET_Release( &lpwfs->hdr );
330c2c66affSColin Finck 
331c2c66affSColin Finck     return r;
332c2c66affSColin Finck }
333c2c66affSColin Finck 
334c2c66affSColin Finck /***********************************************************************
335c2c66affSColin Finck  *           FTP_FtpPutFileW (Internal)
336c2c66affSColin Finck  *
337c2c66affSColin Finck  * Uploads a file to the FTP server
338c2c66affSColin Finck  *
339c2c66affSColin Finck  * RETURNS
340c2c66affSColin Finck  *    TRUE on success
341c2c66affSColin Finck  *    FALSE on failure
342c2c66affSColin Finck  *
343c2c66affSColin Finck  */
FTP_FtpPutFileW(ftp_session_t * lpwfs,LPCWSTR lpszLocalFile,LPCWSTR lpszNewRemoteFile,DWORD dwFlags,DWORD_PTR dwContext)344c2c66affSColin Finck static BOOL FTP_FtpPutFileW(ftp_session_t *lpwfs, LPCWSTR lpszLocalFile,
345c2c66affSColin Finck     LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
346c2c66affSColin Finck {
347c2c66affSColin Finck     HANDLE hFile;
348c2c66affSColin Finck     BOOL bSuccess = FALSE;
349c2c66affSColin Finck     appinfo_t *hIC = NULL;
350c2c66affSColin Finck     INT nResCode;
351c2c66affSColin Finck 
352c2c66affSColin Finck     TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
353c2c66affSColin Finck 
354c2c66affSColin Finck     /* Clear any error information */
355c2c66affSColin Finck     INTERNET_SetLastError(0);
356c2c66affSColin Finck 
357c2c66affSColin Finck     /* Open file to be uploaded */
358c2c66affSColin Finck     if (INVALID_HANDLE_VALUE ==
359c2c66affSColin Finck         (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
360c2c66affSColin Finck         /* Let CreateFile set the appropriate error */
361c2c66affSColin Finck         return FALSE;
362c2c66affSColin Finck 
363c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
364c2c66affSColin Finck 
365c2c66affSColin Finck     INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
366c2c66affSColin Finck 
367c2c66affSColin Finck     if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
368c2c66affSColin Finck     {
369c2c66affSColin Finck         INT nDataSocket;
370c2c66affSColin Finck 
371c2c66affSColin Finck         /* Get data socket to server */
372c2c66affSColin Finck         if (FTP_GetDataSocket(lpwfs, &nDataSocket))
373c2c66affSColin Finck         {
374c2c66affSColin Finck             FTP_SendData(lpwfs, nDataSocket, hFile);
375c2c66affSColin Finck             closesocket(nDataSocket);
376c2c66affSColin Finck 	    nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
377c2c66affSColin Finck 	    if (nResCode)
378c2c66affSColin Finck 	    {
379c2c66affSColin Finck 	        if (nResCode == 226)
380c2c66affSColin Finck 		    bSuccess = TRUE;
381c2c66affSColin Finck 		else
382c2c66affSColin Finck 		    FTP_SetResponseError(nResCode);
383c2c66affSColin Finck 	    }
384c2c66affSColin Finck         }
385c2c66affSColin Finck     }
386c2c66affSColin Finck 
387c2c66affSColin Finck     if (lpwfs->lstnSocket != -1)
388c2c66affSColin Finck     {
389c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
390c2c66affSColin Finck         lpwfs->lstnSocket = -1;
391c2c66affSColin Finck     }
392c2c66affSColin Finck 
393c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
394c2c66affSColin Finck     {
395c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
396c2c66affSColin Finck 
397c2c66affSColin Finck         iar.dwResult = (DWORD)bSuccess;
398c2c66affSColin Finck         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
399c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
400c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
401c2c66affSColin Finck     }
402c2c66affSColin Finck 
403c2c66affSColin Finck     CloseHandle(hFile);
404c2c66affSColin Finck 
405c2c66affSColin Finck     return bSuccess;
406c2c66affSColin Finck }
407c2c66affSColin Finck 
408c2c66affSColin Finck 
409c2c66affSColin Finck /***********************************************************************
410c2c66affSColin Finck  *           FtpSetCurrentDirectoryA (WININET.@)
411c2c66affSColin Finck  *
412c2c66affSColin Finck  * Change the working directory on the FTP server
413c2c66affSColin Finck  *
414c2c66affSColin Finck  * RETURNS
415c2c66affSColin Finck  *    TRUE on success
416c2c66affSColin Finck  *    FALSE on failure
417c2c66affSColin Finck  *
418c2c66affSColin Finck  */
FtpSetCurrentDirectoryA(HINTERNET hConnect,LPCSTR lpszDirectory)419c2c66affSColin Finck BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
420c2c66affSColin Finck {
421c2c66affSColin Finck     LPWSTR lpwzDirectory;
422c2c66affSColin Finck     BOOL ret;
423c2c66affSColin Finck 
424c2c66affSColin Finck     lpwzDirectory = heap_strdupAtoW(lpszDirectory);
425c2c66affSColin Finck     ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
426c2c66affSColin Finck     heap_free(lpwzDirectory);
427c2c66affSColin Finck     return ret;
428c2c66affSColin Finck }
429c2c66affSColin Finck 
430c2c66affSColin Finck typedef struct {
431c2c66affSColin Finck     task_header_t hdr;
432c2c66affSColin Finck     WCHAR *directory;
433c2c66affSColin Finck } directory_task_t;
434c2c66affSColin Finck 
AsyncFtpSetCurrentDirectoryProc(task_header_t * hdr)435c2c66affSColin Finck static void AsyncFtpSetCurrentDirectoryProc(task_header_t *hdr)
436c2c66affSColin Finck {
437c2c66affSColin Finck     directory_task_t *task = (directory_task_t*)hdr;
438c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
439c2c66affSColin Finck 
440c2c66affSColin Finck     TRACE("%p\n", session);
441c2c66affSColin Finck 
442c2c66affSColin Finck     FTP_FtpSetCurrentDirectoryW(session, task->directory);
443c2c66affSColin Finck     heap_free(task->directory);
444c2c66affSColin Finck }
445c2c66affSColin Finck 
446c2c66affSColin Finck /***********************************************************************
447c2c66affSColin Finck  *           FtpSetCurrentDirectoryW (WININET.@)
448c2c66affSColin Finck  *
449c2c66affSColin Finck  * Change the working directory on the FTP server
450c2c66affSColin Finck  *
451c2c66affSColin Finck  * RETURNS
452c2c66affSColin Finck  *    TRUE on success
453c2c66affSColin Finck  *    FALSE on failure
454c2c66affSColin Finck  *
455c2c66affSColin Finck  */
FtpSetCurrentDirectoryW(HINTERNET hConnect,LPCWSTR lpszDirectory)456c2c66affSColin Finck BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
457c2c66affSColin Finck {
458c2c66affSColin Finck     ftp_session_t *lpwfs = NULL;
459c2c66affSColin Finck     appinfo_t *hIC = NULL;
460c2c66affSColin Finck     BOOL r = FALSE;
461c2c66affSColin Finck 
462c2c66affSColin Finck     if (!lpszDirectory)
463c2c66affSColin Finck     {
464c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
465c2c66affSColin Finck         goto lend;
466c2c66affSColin Finck     }
467c2c66affSColin Finck 
468c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hConnect );
469c2c66affSColin Finck     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
470c2c66affSColin Finck     {
471c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
472c2c66affSColin Finck         goto lend;
473c2c66affSColin Finck     }
474c2c66affSColin Finck 
475c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
476c2c66affSColin Finck     {
477c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
478c2c66affSColin Finck         goto lend;
479c2c66affSColin Finck     }
480c2c66affSColin Finck 
481c2c66affSColin Finck     TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
482c2c66affSColin Finck 
483c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
484c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
485c2c66affSColin Finck     {
486c2c66affSColin Finck         directory_task_t *task;
487c2c66affSColin Finck 
488c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpSetCurrentDirectoryProc, sizeof(*task));
489c2c66affSColin Finck         task->directory = heap_strdupW(lpszDirectory);
490c2c66affSColin Finck 
491c2c66affSColin Finck         r = res_to_le(INTERNET_AsyncCall(&task->hdr));
492c2c66affSColin Finck     }
493c2c66affSColin Finck     else
494c2c66affSColin Finck     {
495c2c66affSColin Finck         r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
496c2c66affSColin Finck     }
497c2c66affSColin Finck 
498c2c66affSColin Finck lend:
499c2c66affSColin Finck     if( lpwfs )
500c2c66affSColin Finck         WININET_Release( &lpwfs->hdr );
501c2c66affSColin Finck 
502c2c66affSColin Finck     return r;
503c2c66affSColin Finck }
504c2c66affSColin Finck 
505c2c66affSColin Finck 
506c2c66affSColin Finck /***********************************************************************
507c2c66affSColin Finck  *           FTP_FtpSetCurrentDirectoryW (Internal)
508c2c66affSColin Finck  *
509c2c66affSColin Finck  * Change the working directory on the FTP server
510c2c66affSColin Finck  *
511c2c66affSColin Finck  * RETURNS
512c2c66affSColin Finck  *    TRUE on success
513c2c66affSColin Finck  *    FALSE on failure
514c2c66affSColin Finck  *
515c2c66affSColin Finck  */
FTP_FtpSetCurrentDirectoryW(ftp_session_t * lpwfs,LPCWSTR lpszDirectory)516c2c66affSColin Finck static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
517c2c66affSColin Finck {
518c2c66affSColin Finck     INT nResCode;
519c2c66affSColin Finck     appinfo_t *hIC = NULL;
520c2c66affSColin Finck     BOOL bSuccess = FALSE;
521c2c66affSColin Finck 
522c2c66affSColin Finck     TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
523c2c66affSColin Finck 
524c2c66affSColin Finck     /* Clear any error information */
525c2c66affSColin Finck     INTERNET_SetLastError(0);
526c2c66affSColin Finck 
527c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
528c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
529c2c66affSColin Finck         lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
530c2c66affSColin Finck         goto lend;
531c2c66affSColin Finck 
532c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
533c2c66affSColin Finck 
534c2c66affSColin Finck     if (nResCode)
535c2c66affSColin Finck     {
536c2c66affSColin Finck         if (nResCode == 250)
537c2c66affSColin Finck             bSuccess = TRUE;
538c2c66affSColin Finck         else
539c2c66affSColin Finck             FTP_SetResponseError(nResCode);
540c2c66affSColin Finck     }
541c2c66affSColin Finck 
542c2c66affSColin Finck lend:
543c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
544c2c66affSColin Finck     {
545c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
546c2c66affSColin Finck 
547c2c66affSColin Finck         iar.dwResult = bSuccess;
548c2c66affSColin Finck         iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
549c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
550c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
551c2c66affSColin Finck     }
552c2c66affSColin Finck     return bSuccess;
553c2c66affSColin Finck }
554c2c66affSColin Finck 
555c2c66affSColin Finck 
556c2c66affSColin Finck /***********************************************************************
557c2c66affSColin Finck  *           FtpCreateDirectoryA (WININET.@)
558c2c66affSColin Finck  *
559c2c66affSColin Finck  * Create new directory on the FTP server
560c2c66affSColin Finck  *
561c2c66affSColin Finck  * RETURNS
562c2c66affSColin Finck  *    TRUE on success
563c2c66affSColin Finck  *    FALSE on failure
564c2c66affSColin Finck  *
565c2c66affSColin Finck  */
FtpCreateDirectoryA(HINTERNET hConnect,LPCSTR lpszDirectory)566c2c66affSColin Finck BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
567c2c66affSColin Finck {
568c2c66affSColin Finck     LPWSTR lpwzDirectory;
569c2c66affSColin Finck     BOOL ret;
570c2c66affSColin Finck 
571c2c66affSColin Finck     lpwzDirectory = heap_strdupAtoW(lpszDirectory);
572c2c66affSColin Finck     ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
573c2c66affSColin Finck     heap_free(lpwzDirectory);
574c2c66affSColin Finck     return ret;
575c2c66affSColin Finck }
576c2c66affSColin Finck 
577c2c66affSColin Finck 
AsyncFtpCreateDirectoryProc(task_header_t * hdr)578c2c66affSColin Finck static void AsyncFtpCreateDirectoryProc(task_header_t *hdr)
579c2c66affSColin Finck {
580c2c66affSColin Finck     directory_task_t *task = (directory_task_t*)hdr;
581c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
582c2c66affSColin Finck 
583c2c66affSColin Finck     TRACE(" %p\n", session);
584c2c66affSColin Finck 
585c2c66affSColin Finck     FTP_FtpCreateDirectoryW(session, task->directory);
586c2c66affSColin Finck     heap_free(task->directory);
587c2c66affSColin Finck }
588c2c66affSColin Finck 
589c2c66affSColin Finck /***********************************************************************
590c2c66affSColin Finck  *           FtpCreateDirectoryW (WININET.@)
591c2c66affSColin Finck  *
592c2c66affSColin Finck  * Create new directory on the FTP server
593c2c66affSColin Finck  *
594c2c66affSColin Finck  * RETURNS
595c2c66affSColin Finck  *    TRUE on success
596c2c66affSColin Finck  *    FALSE on failure
597c2c66affSColin Finck  *
598c2c66affSColin Finck  */
FtpCreateDirectoryW(HINTERNET hConnect,LPCWSTR lpszDirectory)599c2c66affSColin Finck BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
600c2c66affSColin Finck {
601c2c66affSColin Finck     ftp_session_t *lpwfs;
602c2c66affSColin Finck     appinfo_t *hIC = NULL;
603c2c66affSColin Finck     BOOL r = FALSE;
604c2c66affSColin Finck 
605c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hConnect );
606c2c66affSColin Finck     if (!lpwfs)
607c2c66affSColin Finck     {
608c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
609c2c66affSColin Finck         return FALSE;
610c2c66affSColin Finck     }
611c2c66affSColin Finck 
612c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
613c2c66affSColin Finck     {
614c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
615c2c66affSColin Finck         goto lend;
616c2c66affSColin Finck     }
617c2c66affSColin Finck 
618c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
619c2c66affSColin Finck     {
620c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
621c2c66affSColin Finck         goto lend;
622c2c66affSColin Finck     }
623c2c66affSColin Finck 
624c2c66affSColin Finck     if (!lpszDirectory)
625c2c66affSColin Finck     {
626c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
627c2c66affSColin Finck         goto lend;
628c2c66affSColin Finck     }
629c2c66affSColin Finck 
630c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
631c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
632c2c66affSColin Finck     {
633c2c66affSColin Finck         directory_task_t *task;
634c2c66affSColin Finck 
635c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpCreateDirectoryProc, sizeof(*task));
636c2c66affSColin Finck         task->directory = heap_strdupW(lpszDirectory);
637c2c66affSColin Finck 
638c2c66affSColin Finck         r = res_to_le(INTERNET_AsyncCall(&task->hdr));
639c2c66affSColin Finck     }
640c2c66affSColin Finck     else
641c2c66affSColin Finck     {
642c2c66affSColin Finck         r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
643c2c66affSColin Finck     }
644c2c66affSColin Finck lend:
645c2c66affSColin Finck     WININET_Release( &lpwfs->hdr );
646c2c66affSColin Finck 
647c2c66affSColin Finck     return r;
648c2c66affSColin Finck }
649c2c66affSColin Finck 
650c2c66affSColin Finck 
651c2c66affSColin Finck /***********************************************************************
652c2c66affSColin Finck  *           FTP_FtpCreateDirectoryW (Internal)
653c2c66affSColin Finck  *
654c2c66affSColin Finck  * Create new directory on the FTP server
655c2c66affSColin Finck  *
656c2c66affSColin Finck  * RETURNS
657c2c66affSColin Finck  *    TRUE on success
658c2c66affSColin Finck  *    FALSE on failure
659c2c66affSColin Finck  *
660c2c66affSColin Finck  */
FTP_FtpCreateDirectoryW(ftp_session_t * lpwfs,LPCWSTR lpszDirectory)661c2c66affSColin Finck static BOOL FTP_FtpCreateDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
662c2c66affSColin Finck {
663c2c66affSColin Finck     INT nResCode;
664c2c66affSColin Finck     BOOL bSuccess = FALSE;
665c2c66affSColin Finck     appinfo_t *hIC = NULL;
666c2c66affSColin Finck 
667c2c66affSColin Finck     TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
668c2c66affSColin Finck 
669c2c66affSColin Finck     /* Clear any error information */
670c2c66affSColin Finck     INTERNET_SetLastError(0);
671c2c66affSColin Finck 
672c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
673c2c66affSColin Finck         goto lend;
674c2c66affSColin Finck 
675c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
676c2c66affSColin Finck     if (nResCode)
677c2c66affSColin Finck     {
678c2c66affSColin Finck         if (nResCode == 257)
679c2c66affSColin Finck             bSuccess = TRUE;
680c2c66affSColin Finck         else
681c2c66affSColin Finck             FTP_SetResponseError(nResCode);
682c2c66affSColin Finck     }
683c2c66affSColin Finck 
684c2c66affSColin Finck lend:
685c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
686c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
687c2c66affSColin Finck     {
688c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
689c2c66affSColin Finck 
690c2c66affSColin Finck         iar.dwResult = (DWORD)bSuccess;
691c2c66affSColin Finck         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
692c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
693c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
694c2c66affSColin Finck     }
695c2c66affSColin Finck 
696c2c66affSColin Finck     return bSuccess;
697c2c66affSColin Finck }
698c2c66affSColin Finck 
699c2c66affSColin Finck /***********************************************************************
700c2c66affSColin Finck  *           FtpFindFirstFileA (WININET.@)
701c2c66affSColin Finck  *
702c2c66affSColin Finck  * Search the specified directory
703c2c66affSColin Finck  *
704c2c66affSColin Finck  * RETURNS
705c2c66affSColin Finck  *    HINTERNET on success
706c2c66affSColin Finck  *    NULL on failure
707c2c66affSColin Finck  *
708c2c66affSColin Finck  */
FtpFindFirstFileA(HINTERNET hConnect,LPCSTR lpszSearchFile,LPWIN32_FIND_DATAA lpFindFileData,DWORD dwFlags,DWORD_PTR dwContext)709c2c66affSColin Finck HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
710c2c66affSColin Finck     LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
711c2c66affSColin Finck {
712c2c66affSColin Finck     LPWSTR lpwzSearchFile;
713c2c66affSColin Finck     WIN32_FIND_DATAW wfd;
714c2c66affSColin Finck     LPWIN32_FIND_DATAW lpFindFileDataW;
715c2c66affSColin Finck     HINTERNET ret;
716c2c66affSColin Finck 
717c2c66affSColin Finck     lpwzSearchFile = heap_strdupAtoW(lpszSearchFile);
718c2c66affSColin Finck     lpFindFileDataW = lpFindFileData?&wfd:NULL;
719c2c66affSColin Finck     ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
720c2c66affSColin Finck     heap_free(lpwzSearchFile);
721c2c66affSColin Finck 
722c2c66affSColin Finck     if (ret && lpFindFileData)
723c2c66affSColin Finck         WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
724c2c66affSColin Finck 
725c2c66affSColin Finck     return ret;
726c2c66affSColin Finck }
727c2c66affSColin Finck 
728c2c66affSColin Finck typedef struct {
729c2c66affSColin Finck     task_header_t hdr;
730c2c66affSColin Finck     WCHAR *search_file;
731c2c66affSColin Finck     WIN32_FIND_DATAW *find_file_data;
732c2c66affSColin Finck     DWORD flags;
733c2c66affSColin Finck     DWORD_PTR context;
734c2c66affSColin Finck } find_first_file_task_t;
735c2c66affSColin Finck 
AsyncFtpFindFirstFileProc(task_header_t * hdr)736c2c66affSColin Finck static void AsyncFtpFindFirstFileProc(task_header_t *hdr)
737c2c66affSColin Finck {
738c2c66affSColin Finck     find_first_file_task_t *task = (find_first_file_task_t*)hdr;
739c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
740c2c66affSColin Finck 
741c2c66affSColin Finck     TRACE("%p\n", session);
742c2c66affSColin Finck 
743c2c66affSColin Finck     FTP_FtpFindFirstFileW(session, task->search_file, task->find_file_data, task->flags, task->context);
744c2c66affSColin Finck     heap_free(task->search_file);
745c2c66affSColin Finck }
746c2c66affSColin Finck 
747c2c66affSColin Finck /***********************************************************************
748c2c66affSColin Finck  *           FtpFindFirstFileW (WININET.@)
749c2c66affSColin Finck  *
750c2c66affSColin Finck  * Search the specified directory
751c2c66affSColin Finck  *
752c2c66affSColin Finck  * RETURNS
753c2c66affSColin Finck  *    HINTERNET on success
754c2c66affSColin Finck  *    NULL on failure
755c2c66affSColin Finck  *
756c2c66affSColin Finck  */
FtpFindFirstFileW(HINTERNET hConnect,LPCWSTR lpszSearchFile,LPWIN32_FIND_DATAW lpFindFileData,DWORD dwFlags,DWORD_PTR dwContext)757c2c66affSColin Finck HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
758c2c66affSColin Finck     LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
759c2c66affSColin Finck {
760c2c66affSColin Finck     ftp_session_t *lpwfs;
761c2c66affSColin Finck     appinfo_t *hIC = NULL;
762c2c66affSColin Finck     HINTERNET r = NULL;
763c2c66affSColin Finck 
764c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hConnect );
765c2c66affSColin Finck     if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
766c2c66affSColin Finck     {
767c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
768c2c66affSColin Finck         goto lend;
769c2c66affSColin Finck     }
770c2c66affSColin Finck 
771c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
772c2c66affSColin Finck     {
773c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
774c2c66affSColin Finck         goto lend;
775c2c66affSColin Finck     }
776c2c66affSColin Finck 
777c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
778c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
779c2c66affSColin Finck     {
780c2c66affSColin Finck         find_first_file_task_t *task;
781c2c66affSColin Finck 
782c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpFindFirstFileProc, sizeof(*task));
783c2c66affSColin Finck         task->search_file = heap_strdupW(lpszSearchFile);
784c2c66affSColin Finck         task->find_file_data = lpFindFileData;
785c2c66affSColin Finck         task->flags = dwFlags;
786c2c66affSColin Finck         task->context = dwContext;
787c2c66affSColin Finck 
788c2c66affSColin Finck         INTERNET_AsyncCall(&task->hdr);
789c2c66affSColin Finck         r = NULL;
790c2c66affSColin Finck     }
791c2c66affSColin Finck     else
792c2c66affSColin Finck     {
793c2c66affSColin Finck         r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
794c2c66affSColin Finck             dwFlags, dwContext);
795c2c66affSColin Finck     }
796c2c66affSColin Finck lend:
797c2c66affSColin Finck     if( lpwfs )
798c2c66affSColin Finck         WININET_Release( &lpwfs->hdr );
799c2c66affSColin Finck 
800c2c66affSColin Finck     return r;
801c2c66affSColin Finck }
802c2c66affSColin Finck 
803c2c66affSColin Finck 
804c2c66affSColin Finck /***********************************************************************
805c2c66affSColin Finck  *           FTP_FtpFindFirstFileW (Internal)
806c2c66affSColin Finck  *
807c2c66affSColin Finck  * Search the specified directory
808c2c66affSColin Finck  *
809c2c66affSColin Finck  * RETURNS
810c2c66affSColin Finck  *    HINTERNET on success
811c2c66affSColin Finck  *    NULL on failure
812c2c66affSColin Finck  *
813c2c66affSColin Finck  */
FTP_FtpFindFirstFileW(ftp_session_t * lpwfs,LPCWSTR lpszSearchFile,LPWIN32_FIND_DATAW lpFindFileData,DWORD dwFlags,DWORD_PTR dwContext)814c2c66affSColin Finck static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t *lpwfs,
815c2c66affSColin Finck     LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
816c2c66affSColin Finck {
817c2c66affSColin Finck     INT nResCode;
818c2c66affSColin Finck     appinfo_t *hIC = NULL;
819c2c66affSColin Finck     HINTERNET hFindNext = NULL;
820c2c66affSColin Finck     LPWSTR lpszSearchPath = NULL;
821c2c66affSColin Finck 
822c2c66affSColin Finck     TRACE("\n");
823c2c66affSColin Finck 
824c2c66affSColin Finck     /* Clear any error information */
825c2c66affSColin Finck     INTERNET_SetLastError(0);
826c2c66affSColin Finck 
827c2c66affSColin Finck     if (!FTP_InitListenSocket(lpwfs))
828c2c66affSColin Finck         goto lend;
829c2c66affSColin Finck 
830c2c66affSColin Finck     if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
831c2c66affSColin Finck         goto lend;
832c2c66affSColin Finck 
833c2c66affSColin Finck     if (!FTP_SendPortOrPasv(lpwfs))
834c2c66affSColin Finck         goto lend;
835c2c66affSColin Finck 
836c2c66affSColin Finck     /* split search path into file and path */
837c2c66affSColin Finck     if (lpszSearchFile)
838c2c66affSColin Finck     {
839c2c66affSColin Finck         LPCWSTR name = lpszSearchFile, p;
8405f12c8d7Swinesync         if ((p = wcsrchr( name, '\\' ))) name = p + 1;
8415f12c8d7Swinesync         if ((p = wcsrchr( name, '/' ))) name = p + 1;
842c2c66affSColin Finck         if (name != lpszSearchFile)
843c2c66affSColin Finck         {
844c2c66affSColin Finck             lpszSearchPath = heap_strndupW(lpszSearchFile, name - lpszSearchFile);
845c2c66affSColin Finck             lpszSearchFile = name;
846c2c66affSColin Finck         }
847c2c66affSColin Finck     }
848c2c66affSColin Finck 
849c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, lpszSearchPath,
850c2c66affSColin Finck         lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
851c2c66affSColin Finck         goto lend;
852c2c66affSColin Finck 
853c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
854c2c66affSColin Finck     if (nResCode)
855c2c66affSColin Finck     {
856c2c66affSColin Finck         if (nResCode == 125 || nResCode == 150)
857c2c66affSColin Finck         {
858c2c66affSColin Finck             INT nDataSocket;
859c2c66affSColin Finck 
860c2c66affSColin Finck             /* Get data socket to server */
861c2c66affSColin Finck             if (FTP_GetDataSocket(lpwfs, &nDataSocket))
862c2c66affSColin Finck             {
863c2c66affSColin Finck                 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
864c2c66affSColin Finck                 closesocket(nDataSocket);
865c2c66affSColin Finck                 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
866c2c66affSColin Finck                 if (nResCode != 226 && nResCode != 250)
867c2c66affSColin Finck                     INTERNET_SetLastError(ERROR_NO_MORE_FILES);
868c2c66affSColin Finck             }
869c2c66affSColin Finck         }
870c2c66affSColin Finck         else
871c2c66affSColin Finck             FTP_SetResponseError(nResCode);
872c2c66affSColin Finck     }
873c2c66affSColin Finck 
874c2c66affSColin Finck lend:
875c2c66affSColin Finck     heap_free(lpszSearchPath);
876c2c66affSColin Finck 
877c2c66affSColin Finck     if (lpwfs->lstnSocket != -1)
878c2c66affSColin Finck     {
879c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
880c2c66affSColin Finck         lpwfs->lstnSocket = -1;
881c2c66affSColin Finck     }
882c2c66affSColin Finck 
883c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
884c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
885c2c66affSColin Finck     {
886c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
887c2c66affSColin Finck 
888c2c66affSColin Finck         if (hFindNext)
889c2c66affSColin Finck 	{
890c2c66affSColin Finck             iar.dwResult = (DWORD_PTR)hFindNext;
891c2c66affSColin Finck             iar.dwError = ERROR_SUCCESS;
892c2c66affSColin Finck             INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
893c2c66affSColin Finck                 &iar, sizeof(INTERNET_ASYNC_RESULT));
894c2c66affSColin Finck 	}
895c2c66affSColin Finck 
896c2c66affSColin Finck         iar.dwResult = (DWORD_PTR)hFindNext;
897c2c66affSColin Finck         iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
898c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
899c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
900c2c66affSColin Finck     }
901c2c66affSColin Finck 
902c2c66affSColin Finck     return hFindNext;
903c2c66affSColin Finck }
904c2c66affSColin Finck 
905c2c66affSColin Finck 
906c2c66affSColin Finck /***********************************************************************
907c2c66affSColin Finck  *           FtpGetCurrentDirectoryA (WININET.@)
908c2c66affSColin Finck  *
909c2c66affSColin Finck  * Retrieves the current directory
910c2c66affSColin Finck  *
911c2c66affSColin Finck  * RETURNS
912c2c66affSColin Finck  *    TRUE on success
913c2c66affSColin Finck  *    FALSE on failure
914c2c66affSColin Finck  *
915c2c66affSColin Finck  */
FtpGetCurrentDirectoryA(HINTERNET hFtpSession,LPSTR lpszCurrentDirectory,LPDWORD lpdwCurrentDirectory)916c2c66affSColin Finck BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
917c2c66affSColin Finck     LPDWORD lpdwCurrentDirectory)
918c2c66affSColin Finck {
919c2c66affSColin Finck     WCHAR *dir = NULL;
920c2c66affSColin Finck     DWORD len;
921c2c66affSColin Finck     BOOL ret;
922c2c66affSColin Finck 
923c2c66affSColin Finck     if(lpdwCurrentDirectory) {
924c2c66affSColin Finck         len = *lpdwCurrentDirectory;
925c2c66affSColin Finck         if(lpszCurrentDirectory)
926c2c66affSColin Finck         {
927c2c66affSColin Finck             dir = heap_alloc(len * sizeof(WCHAR));
928c2c66affSColin Finck             if (NULL == dir)
929c2c66affSColin Finck             {
930c2c66affSColin Finck                 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
931c2c66affSColin Finck                 return FALSE;
932c2c66affSColin Finck             }
933c2c66affSColin Finck         }
934c2c66affSColin Finck     }
935c2c66affSColin Finck     ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
936c2c66affSColin Finck 
937c2c66affSColin Finck     if (ret && lpszCurrentDirectory)
938c2c66affSColin Finck         WideCharToMultiByte(CP_ACP, 0, dir, -1, lpszCurrentDirectory, len, NULL, NULL);
939c2c66affSColin Finck 
940c2c66affSColin Finck     if (lpdwCurrentDirectory) *lpdwCurrentDirectory = len;
941c2c66affSColin Finck     heap_free(dir);
942c2c66affSColin Finck     return ret;
943c2c66affSColin Finck }
944c2c66affSColin Finck 
945c2c66affSColin Finck typedef struct {
946c2c66affSColin Finck     task_header_t hdr;
947c2c66affSColin Finck     WCHAR *directory;
948c2c66affSColin Finck     DWORD *directory_len;
949c2c66affSColin Finck } get_current_dir_task_t;
950c2c66affSColin Finck 
AsyncFtpGetCurrentDirectoryProc(task_header_t * hdr)951c2c66affSColin Finck static void AsyncFtpGetCurrentDirectoryProc(task_header_t *hdr)
952c2c66affSColin Finck {
953c2c66affSColin Finck     get_current_dir_task_t *task = (get_current_dir_task_t*)hdr;
954c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
955c2c66affSColin Finck 
956c2c66affSColin Finck     TRACE("%p\n", session);
957c2c66affSColin Finck 
958c2c66affSColin Finck     FTP_FtpGetCurrentDirectoryW(session, task->directory, task->directory_len);
959c2c66affSColin Finck }
960c2c66affSColin Finck 
961c2c66affSColin Finck /***********************************************************************
962c2c66affSColin Finck  *           FtpGetCurrentDirectoryW (WININET.@)
963c2c66affSColin Finck  *
964c2c66affSColin Finck  * Retrieves the current directory
965c2c66affSColin Finck  *
966c2c66affSColin Finck  * RETURNS
967c2c66affSColin Finck  *    TRUE on success
968c2c66affSColin Finck  *    FALSE on failure
969c2c66affSColin Finck  *
970c2c66affSColin Finck  */
FtpGetCurrentDirectoryW(HINTERNET hFtpSession,LPWSTR lpszCurrentDirectory,LPDWORD lpdwCurrentDirectory)971c2c66affSColin Finck BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
972c2c66affSColin Finck     LPDWORD lpdwCurrentDirectory)
973c2c66affSColin Finck {
974c2c66affSColin Finck     ftp_session_t *lpwfs;
975c2c66affSColin Finck     appinfo_t *hIC = NULL;
976c2c66affSColin Finck     BOOL r = FALSE;
977c2c66affSColin Finck 
978c2c66affSColin Finck     TRACE("%p %p %p\n", hFtpSession, lpszCurrentDirectory, lpdwCurrentDirectory);
979c2c66affSColin Finck 
980c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hFtpSession );
981c2c66affSColin Finck     if (NULL == lpwfs)
982c2c66affSColin Finck     {
983c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
984c2c66affSColin Finck         goto lend;
985c2c66affSColin Finck     }
986c2c66affSColin Finck 
987c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
988c2c66affSColin Finck     {
989c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
990c2c66affSColin Finck         goto lend;
991c2c66affSColin Finck     }
992c2c66affSColin Finck 
993c2c66affSColin Finck     if (!lpdwCurrentDirectory)
994c2c66affSColin Finck     {
995c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
996c2c66affSColin Finck         goto lend;
997c2c66affSColin Finck     }
998c2c66affSColin Finck 
999c2c66affSColin Finck     if (lpszCurrentDirectory == NULL)
1000c2c66affSColin Finck     {
1001c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1002c2c66affSColin Finck         goto lend;
1003c2c66affSColin Finck     }
1004c2c66affSColin Finck 
1005c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
1006c2c66affSColin Finck     {
1007c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1008c2c66affSColin Finck         goto lend;
1009c2c66affSColin Finck     }
1010c2c66affSColin Finck 
1011c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1012c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1013c2c66affSColin Finck     {
1014c2c66affSColin Finck         get_current_dir_task_t *task;
1015c2c66affSColin Finck 
1016c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpGetCurrentDirectoryProc, sizeof(*task));
1017c2c66affSColin Finck         task->directory = lpszCurrentDirectory;
1018c2c66affSColin Finck         task->directory_len = lpdwCurrentDirectory;
1019c2c66affSColin Finck 
1020c2c66affSColin Finck         r = res_to_le(INTERNET_AsyncCall(&task->hdr));
1021c2c66affSColin Finck     }
1022c2c66affSColin Finck     else
1023c2c66affSColin Finck     {
1024c2c66affSColin Finck         r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
1025c2c66affSColin Finck             lpdwCurrentDirectory);
1026c2c66affSColin Finck     }
1027c2c66affSColin Finck 
1028c2c66affSColin Finck lend:
1029c2c66affSColin Finck     if( lpwfs )
1030c2c66affSColin Finck         WININET_Release( &lpwfs->hdr );
1031c2c66affSColin Finck 
1032c2c66affSColin Finck     return r;
1033c2c66affSColin Finck }
1034c2c66affSColin Finck 
1035c2c66affSColin Finck 
1036c2c66affSColin Finck /***********************************************************************
1037c2c66affSColin Finck  *           FTP_FtpGetCurrentDirectoryW (Internal)
1038c2c66affSColin Finck  *
1039c2c66affSColin Finck  * Retrieves the current directory
1040c2c66affSColin Finck  *
1041c2c66affSColin Finck  * RETURNS
1042c2c66affSColin Finck  *    TRUE on success
1043c2c66affSColin Finck  *    FALSE on failure
1044c2c66affSColin Finck  *
1045c2c66affSColin Finck  */
FTP_FtpGetCurrentDirectoryW(ftp_session_t * lpwfs,LPWSTR lpszCurrentDirectory,LPDWORD lpdwCurrentDirectory)1046c2c66affSColin Finck static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t *lpwfs, LPWSTR lpszCurrentDirectory,
1047c2c66affSColin Finck 	LPDWORD lpdwCurrentDirectory)
1048c2c66affSColin Finck {
1049c2c66affSColin Finck     INT nResCode;
1050c2c66affSColin Finck     appinfo_t *hIC = NULL;
1051c2c66affSColin Finck     BOOL bSuccess = FALSE;
1052c2c66affSColin Finck 
1053c2c66affSColin Finck     /* Clear any error information */
1054c2c66affSColin Finck     INTERNET_SetLastError(0);
1055c2c66affSColin Finck 
1056c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1057c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
1058c2c66affSColin Finck         lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
1059c2c66affSColin Finck         goto lend;
1060c2c66affSColin Finck 
1061c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1062c2c66affSColin Finck     if (nResCode)
1063c2c66affSColin Finck     {
1064c2c66affSColin Finck         if (nResCode == 257) /* Extract directory name */
1065c2c66affSColin Finck         {
1066c2c66affSColin Finck             DWORD firstpos, lastpos, len;
1067c2c66affSColin Finck             LPWSTR lpszResponseBuffer = heap_strdupAtoW(INTERNET_GetResponseBuffer());
1068c2c66affSColin Finck 
1069c2c66affSColin Finck             for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
1070c2c66affSColin Finck             {
1071c2c66affSColin Finck                 if ('"' == lpszResponseBuffer[lastpos])
1072c2c66affSColin Finck                 {
1073c2c66affSColin Finck                     if (!firstpos)
1074c2c66affSColin Finck                         firstpos = lastpos;
1075c2c66affSColin Finck                     else
1076c2c66affSColin Finck                         break;
1077c2c66affSColin Finck                 }
1078c2c66affSColin Finck             }
1079c2c66affSColin Finck             len = lastpos - firstpos;
1080c2c66affSColin Finck             if (*lpdwCurrentDirectory >= len)
1081c2c66affSColin Finck             {
1082c2c66affSColin Finck                 memcpy(lpszCurrentDirectory, &lpszResponseBuffer[firstpos + 1], len * sizeof(WCHAR));
1083c2c66affSColin Finck                 lpszCurrentDirectory[len - 1] = 0;
1084c2c66affSColin Finck                 *lpdwCurrentDirectory = len;
1085c2c66affSColin Finck                 bSuccess = TRUE;
1086c2c66affSColin Finck             }
1087c2c66affSColin Finck             else INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
1088c2c66affSColin Finck 
1089c2c66affSColin Finck             heap_free(lpszResponseBuffer);
1090c2c66affSColin Finck         }
1091c2c66affSColin Finck         else
1092c2c66affSColin Finck             FTP_SetResponseError(nResCode);
1093c2c66affSColin Finck     }
1094c2c66affSColin Finck 
1095c2c66affSColin Finck lend:
1096c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1097c2c66affSColin Finck     {
1098c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
1099c2c66affSColin Finck 
1100c2c66affSColin Finck         iar.dwResult = bSuccess;
1101c2c66affSColin Finck         iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
1102c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1103c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
1104c2c66affSColin Finck     }
1105c2c66affSColin Finck 
1106c2c66affSColin Finck     return bSuccess;
1107c2c66affSColin Finck }
1108c2c66affSColin Finck 
1109c2c66affSColin Finck 
1110c2c66affSColin Finck /***********************************************************************
1111c2c66affSColin Finck  *           FTPFILE_Destroy(internal)
1112c2c66affSColin Finck  *
1113c2c66affSColin Finck  * Closes the file transfer handle. This also 'cleans' the data queue of
1114c2c66affSColin Finck  * the 'transfer complete' message (this is a bit of a hack though :-/ )
1115c2c66affSColin Finck  *
1116c2c66affSColin Finck  */
FTPFILE_Destroy(object_header_t * hdr)1117c2c66affSColin Finck static void FTPFILE_Destroy(object_header_t *hdr)
1118c2c66affSColin Finck {
1119c2c66affSColin Finck     ftp_file_t *lpwh = (ftp_file_t*) hdr;
1120c2c66affSColin Finck     ftp_session_t *lpwfs = lpwh->lpFtpSession;
1121c2c66affSColin Finck     INT nResCode;
1122c2c66affSColin Finck 
1123c2c66affSColin Finck     TRACE("\n");
1124c2c66affSColin Finck 
1125c2c66affSColin Finck     if (lpwh->cache_file_handle != INVALID_HANDLE_VALUE)
1126c2c66affSColin Finck         CloseHandle(lpwh->cache_file_handle);
1127c2c66affSColin Finck 
1128c2c66affSColin Finck     heap_free(lpwh->cache_file);
1129c2c66affSColin Finck 
1130c2c66affSColin Finck     if (!lpwh->session_deleted)
1131c2c66affSColin Finck         lpwfs->download_in_progress = NULL;
1132c2c66affSColin Finck 
1133c2c66affSColin Finck     if (lpwh->nDataSocket != -1)
1134c2c66affSColin Finck         closesocket(lpwh->nDataSocket);
1135c2c66affSColin Finck 
1136c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1137c2c66affSColin Finck     if (nResCode > 0 && nResCode != 226) WARN("server reports failed transfer\n");
1138c2c66affSColin Finck 
1139c2c66affSColin Finck     WININET_Release(&lpwh->lpFtpSession->hdr);
1140c2c66affSColin Finck }
1141c2c66affSColin Finck 
FTPFILE_QueryOption(object_header_t * hdr,DWORD option,void * buffer,DWORD * size,BOOL unicode)1142c2c66affSColin Finck static DWORD FTPFILE_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
1143c2c66affSColin Finck {
1144c2c66affSColin Finck     switch(option) {
1145c2c66affSColin Finck     case INTERNET_OPTION_HANDLE_TYPE:
1146c2c66affSColin Finck         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
1147c2c66affSColin Finck 
1148c2c66affSColin Finck         if (*size < sizeof(ULONG))
1149c2c66affSColin Finck             return ERROR_INSUFFICIENT_BUFFER;
1150c2c66affSColin Finck 
1151c2c66affSColin Finck         *size = sizeof(DWORD);
1152c2c66affSColin Finck         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FILE;
1153c2c66affSColin Finck         return ERROR_SUCCESS;
1154c2c66affSColin Finck     case INTERNET_OPTION_DATAFILE_NAME:
1155c2c66affSColin Finck     {
1156c2c66affSColin Finck         DWORD required;
1157c2c66affSColin Finck         ftp_file_t *file = (ftp_file_t *)hdr;
1158c2c66affSColin Finck 
1159c2c66affSColin Finck         TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
1160c2c66affSColin Finck 
1161c2c66affSColin Finck         if (!file->cache_file)
1162c2c66affSColin Finck         {
1163c2c66affSColin Finck             *size = 0;
1164c2c66affSColin Finck             return ERROR_INTERNET_ITEM_NOT_FOUND;
1165c2c66affSColin Finck         }
1166c2c66affSColin Finck         if (unicode)
1167c2c66affSColin Finck         {
1168c2c66affSColin Finck             required = (lstrlenW(file->cache_file) + 1) * sizeof(WCHAR);
1169c2c66affSColin Finck             if (*size < required)
1170c2c66affSColin Finck                 return ERROR_INSUFFICIENT_BUFFER;
1171c2c66affSColin Finck 
1172c2c66affSColin Finck             *size = required;
1173c2c66affSColin Finck             memcpy(buffer, file->cache_file, *size);
1174c2c66affSColin Finck             return ERROR_SUCCESS;
1175c2c66affSColin Finck         }
1176c2c66affSColin Finck         else
1177c2c66affSColin Finck         {
1178c2c66affSColin Finck             required = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, NULL, 0, NULL, NULL);
1179c2c66affSColin Finck             if (required > *size)
1180c2c66affSColin Finck                 return ERROR_INSUFFICIENT_BUFFER;
1181c2c66affSColin Finck 
1182c2c66affSColin Finck             *size = WideCharToMultiByte(CP_ACP, 0, file->cache_file, -1, buffer, *size, NULL, NULL);
1183c2c66affSColin Finck             return ERROR_SUCCESS;
1184c2c66affSColin Finck         }
1185c2c66affSColin Finck     }
1186c2c66affSColin Finck     }
1187c2c66affSColin Finck     return INET_QueryOption(hdr, option, buffer, size, unicode);
1188c2c66affSColin Finck }
1189c2c66affSColin Finck 
FTPFILE_ReadFile(object_header_t * hdr,void * buffer,DWORD size,DWORD * read,DWORD flags,DWORD_PTR context)1190c2c66affSColin Finck static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read,
1191c2c66affSColin Finck     DWORD flags, DWORD_PTR context)
1192c2c66affSColin Finck {
1193c2c66affSColin Finck     ftp_file_t *file = (ftp_file_t*)hdr;
1194c2c66affSColin Finck     int res;
1195c2c66affSColin Finck     DWORD error;
1196c2c66affSColin Finck 
1197c2c66affSColin Finck     if (file->nDataSocket == -1)
1198c2c66affSColin Finck         return ERROR_INTERNET_DISCONNECTED;
1199c2c66affSColin Finck 
1200c2c66affSColin Finck     /* FIXME: FTP should use NETCON_ stuff */
1201c2c66affSColin Finck     res = sock_recv(file->nDataSocket, buffer, size, MSG_WAITALL);
1202c2c66affSColin Finck     *read = res>0 ? res : 0;
1203c2c66affSColin Finck 
1204c2c66affSColin Finck     error = res >= 0 ? ERROR_SUCCESS : INTERNET_ERROR_BASE; /* FIXME */
1205c2c66affSColin Finck     if (error == ERROR_SUCCESS && file->cache_file)
1206c2c66affSColin Finck     {
1207c2c66affSColin Finck         DWORD bytes_written;
1208c2c66affSColin Finck 
1209c2c66affSColin Finck         if (!WriteFile(file->cache_file_handle, buffer, *read, &bytes_written, NULL))
1210c2c66affSColin Finck             WARN("WriteFile failed: %u\n", GetLastError());
1211c2c66affSColin Finck     }
1212c2c66affSColin Finck     return error;
1213c2c66affSColin Finck }
1214c2c66affSColin Finck 
FTPFILE_WriteFile(object_header_t * hdr,const void * buffer,DWORD size,DWORD * written)1215c2c66affSColin Finck static DWORD FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
1216c2c66affSColin Finck {
1217c2c66affSColin Finck     ftp_file_t *lpwh = (ftp_file_t*) hdr;
1218c2c66affSColin Finck     int res;
1219c2c66affSColin Finck 
1220c2c66affSColin Finck     res = sock_send(lpwh->nDataSocket, buffer, size, 0);
1221c2c66affSColin Finck 
1222c2c66affSColin Finck     *written = res>0 ? res : 0;
1223c2c66affSColin Finck     return res >= 0 ? ERROR_SUCCESS : WSAGetLastError();
1224c2c66affSColin Finck }
1225c2c66affSColin Finck 
FTP_ReceiveRequestData(ftp_file_t * file,BOOL first_notif)1226c2c66affSColin Finck static void FTP_ReceiveRequestData(ftp_file_t *file, BOOL first_notif)
1227c2c66affSColin Finck {
1228c2c66affSColin Finck     INTERNET_ASYNC_RESULT iar;
1229c2c66affSColin Finck     BYTE buffer[4096];
1230c2c66affSColin Finck     int available;
1231c2c66affSColin Finck 
1232c2c66affSColin Finck     TRACE("%p\n", file);
1233c2c66affSColin Finck 
1234c2c66affSColin Finck     available = sock_recv(file->nDataSocket, buffer, sizeof(buffer), MSG_PEEK);
1235c2c66affSColin Finck 
1236c2c66affSColin Finck     if(available != -1) {
1237c2c66affSColin Finck         iar.dwResult = (DWORD_PTR)file->hdr.hInternet;
1238c2c66affSColin Finck         iar.dwError = first_notif ? 0 : available;
1239c2c66affSColin Finck     }else {
1240c2c66affSColin Finck         iar.dwResult = 0;
1241c2c66affSColin Finck         iar.dwError = INTERNET_GetLastError();
1242c2c66affSColin Finck     }
1243c2c66affSColin Finck 
1244c2c66affSColin Finck     INTERNET_SendCallback(&file->hdr, file->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1245c2c66affSColin Finck                           sizeof(INTERNET_ASYNC_RESULT));
1246c2c66affSColin Finck }
1247c2c66affSColin Finck 
FTPFILE_AsyncQueryDataAvailableProc(task_header_t * task)1248c2c66affSColin Finck static void FTPFILE_AsyncQueryDataAvailableProc(task_header_t *task)
1249c2c66affSColin Finck {
1250c2c66affSColin Finck     ftp_file_t *file = (ftp_file_t*)task->hdr;
1251c2c66affSColin Finck 
1252c2c66affSColin Finck     FTP_ReceiveRequestData(file, FALSE);
1253c2c66affSColin Finck }
1254c2c66affSColin Finck 
FTPFILE_QueryDataAvailable(object_header_t * hdr,DWORD * available,DWORD flags,DWORD_PTR ctx)1255c2c66affSColin Finck static DWORD FTPFILE_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
1256c2c66affSColin Finck {
1257c2c66affSColin Finck     ftp_file_t *file = (ftp_file_t*) hdr;
1258c2c66affSColin Finck     ULONG unread = 0;
1259c2c66affSColin Finck     int retval;
1260c2c66affSColin Finck 
1261c2c66affSColin Finck     TRACE("(%p %p %x %lx)\n", file, available, flags, ctx);
1262c2c66affSColin Finck 
1263c2c66affSColin Finck     retval = ioctlsocket(file->nDataSocket, FIONREAD, &unread);
1264c2c66affSColin Finck     if (!retval)
1265c2c66affSColin Finck         TRACE("%d bytes of queued, but unread data\n", unread);
1266c2c66affSColin Finck 
1267c2c66affSColin Finck     *available = unread;
1268c2c66affSColin Finck 
1269c2c66affSColin Finck     if(!unread) {
1270c2c66affSColin Finck         BYTE byte;
1271c2c66affSColin Finck 
1272c2c66affSColin Finck         *available = 0;
1273c2c66affSColin Finck 
1274c2c66affSColin Finck         retval = sock_recv(file->nDataSocket, &byte, 1, MSG_PEEK);
1275c2c66affSColin Finck         if(retval > 0) {
1276c2c66affSColin Finck             task_header_t *task;
1277c2c66affSColin Finck 
1278c2c66affSColin Finck             task = alloc_async_task(&file->hdr, FTPFILE_AsyncQueryDataAvailableProc, sizeof(*task));
1279c2c66affSColin Finck             INTERNET_AsyncCall(task);
1280c2c66affSColin Finck 
1281c2c66affSColin Finck             return ERROR_IO_PENDING;
1282c2c66affSColin Finck         }
1283c2c66affSColin Finck     }
1284c2c66affSColin Finck 
1285c2c66affSColin Finck     return ERROR_SUCCESS;
1286c2c66affSColin Finck }
1287c2c66affSColin Finck 
FTPFILE_LockRequestFile(object_header_t * hdr,req_file_t ** ret)1288c2c66affSColin Finck static DWORD FTPFILE_LockRequestFile(object_header_t *hdr, req_file_t **ret)
1289c2c66affSColin Finck {
1290c2c66affSColin Finck     ftp_file_t *file = (ftp_file_t*)hdr;
1291c2c66affSColin Finck     FIXME("%p\n", file);
1292c2c66affSColin Finck     return ERROR_NOT_SUPPORTED;
1293c2c66affSColin Finck }
1294c2c66affSColin Finck 
1295c2c66affSColin Finck static const object_vtbl_t FTPFILEVtbl = {
1296c2c66affSColin Finck     FTPFILE_Destroy,
1297c2c66affSColin Finck     NULL,
1298c2c66affSColin Finck     FTPFILE_QueryOption,
1299c2c66affSColin Finck     INET_SetOption,
1300c2c66affSColin Finck     FTPFILE_ReadFile,
1301c2c66affSColin Finck     FTPFILE_WriteFile,
1302c2c66affSColin Finck     FTPFILE_QueryDataAvailable,
1303c2c66affSColin Finck     NULL,
1304c2c66affSColin Finck     FTPFILE_LockRequestFile
1305c2c66affSColin Finck };
1306c2c66affSColin Finck 
1307c2c66affSColin Finck /***********************************************************************
1308c2c66affSColin Finck  *           FTP_FtpOpenFileW (Internal)
1309c2c66affSColin Finck  *
1310c2c66affSColin Finck  * Open a remote file for writing or reading
1311c2c66affSColin Finck  *
1312c2c66affSColin Finck  * RETURNS
1313c2c66affSColin Finck  *    HINTERNET handle on success
1314c2c66affSColin Finck  *    NULL on failure
1315c2c66affSColin Finck  *
1316c2c66affSColin Finck  */
FTP_FtpOpenFileW(ftp_session_t * lpwfs,LPCWSTR lpszFileName,DWORD fdwAccess,DWORD dwFlags,DWORD_PTR dwContext)1317c2c66affSColin Finck static HINTERNET FTP_FtpOpenFileW(ftp_session_t *lpwfs,
1318c2c66affSColin Finck 	LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1319c2c66affSColin Finck 	DWORD_PTR dwContext)
1320c2c66affSColin Finck {
1321c2c66affSColin Finck     INT nDataSocket;
1322c2c66affSColin Finck     BOOL bSuccess = FALSE;
1323c2c66affSColin Finck     ftp_file_t *lpwh = NULL;
1324c2c66affSColin Finck     appinfo_t *hIC = NULL;
1325c2c66affSColin Finck 
1326c2c66affSColin Finck     TRACE("\n");
1327c2c66affSColin Finck 
1328c2c66affSColin Finck     /* Clear any error information */
1329c2c66affSColin Finck     INTERNET_SetLastError(0);
1330c2c66affSColin Finck 
1331c2c66affSColin Finck     if (GENERIC_READ == fdwAccess)
1332c2c66affSColin Finck     {
1333c2c66affSColin Finck         /* Set up socket to retrieve data */
1334c2c66affSColin Finck         bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1335c2c66affSColin Finck     }
1336c2c66affSColin Finck     else if (GENERIC_WRITE == fdwAccess)
1337c2c66affSColin Finck     {
1338c2c66affSColin Finck         /* Set up socket to send data */
1339c2c66affSColin Finck         bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1340c2c66affSColin Finck     }
1341c2c66affSColin Finck 
1342c2c66affSColin Finck     /* Get data socket to server */
1343c2c66affSColin Finck     if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1344c2c66affSColin Finck     {
1345c2c66affSColin Finck         lpwh = alloc_object(&lpwfs->hdr, &FTPFILEVtbl, sizeof(ftp_file_t));
1346c2c66affSColin Finck         lpwh->hdr.htype = WH_HFILE;
1347c2c66affSColin Finck         lpwh->hdr.dwFlags = dwFlags;
1348c2c66affSColin Finck         lpwh->hdr.dwContext = dwContext;
1349c2c66affSColin Finck         lpwh->nDataSocket = nDataSocket;
1350c2c66affSColin Finck         lpwh->cache_file = NULL;
1351c2c66affSColin Finck         lpwh->cache_file_handle = INVALID_HANDLE_VALUE;
1352c2c66affSColin Finck         lpwh->session_deleted = FALSE;
1353c2c66affSColin Finck 
1354c2c66affSColin Finck         WININET_AddRef( &lpwfs->hdr );
1355c2c66affSColin Finck         lpwh->lpFtpSession = lpwfs;
1356c2c66affSColin Finck         list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry );
1357c2c66affSColin Finck 
1358c2c66affSColin Finck 	/* Indicate that a download is currently in progress */
1359c2c66affSColin Finck 	lpwfs->download_in_progress = lpwh;
1360c2c66affSColin Finck     }
1361c2c66affSColin Finck 
1362c2c66affSColin Finck     if (lpwfs->lstnSocket != -1)
1363c2c66affSColin Finck     {
1364c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
1365c2c66affSColin Finck         lpwfs->lstnSocket = -1;
1366c2c66affSColin Finck     }
1367c2c66affSColin Finck 
1368c2c66affSColin Finck     if (bSuccess && fdwAccess == GENERIC_READ)
1369c2c66affSColin Finck     {
1370c2c66affSColin Finck         WCHAR filename[MAX_PATH + 1];
1371c2c66affSColin Finck         URL_COMPONENTSW uc;
1372c2c66affSColin Finck         DWORD len;
1373c2c66affSColin Finck 
1374c2c66affSColin Finck         memset(&uc, 0, sizeof(uc));
1375c2c66affSColin Finck         uc.dwStructSize = sizeof(uc);
1376c2c66affSColin Finck         uc.nScheme      = INTERNET_SCHEME_FTP;
1377c2c66affSColin Finck         uc.lpszHostName = lpwfs->servername;
1378c2c66affSColin Finck         uc.nPort        = lpwfs->serverport;
1379c2c66affSColin Finck         uc.lpszUserName = lpwfs->lpszUserName;
1380c2c66affSColin Finck         uc.lpszUrlPath  = heap_strdupW(lpszFileName);
1381c2c66affSColin Finck 
1382c2c66affSColin Finck         if (!InternetCreateUrlW(&uc, 0, NULL, &len) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
1383c2c66affSColin Finck         {
1384c2c66affSColin Finck             WCHAR *url = heap_alloc(len * sizeof(WCHAR));
1385c2c66affSColin Finck 
1386c2c66affSColin Finck             if (url && InternetCreateUrlW(&uc, 0, url, &len) && CreateUrlCacheEntryW(url, 0, NULL, filename, 0))
1387c2c66affSColin Finck             {
1388c2c66affSColin Finck                 lpwh->cache_file = heap_strdupW(filename);
1389c2c66affSColin Finck                 lpwh->cache_file_handle = CreateFileW(filename, GENERIC_WRITE, FILE_SHARE_READ,
1390c2c66affSColin Finck                                                       NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1391c2c66affSColin Finck                 if (lpwh->cache_file_handle == INVALID_HANDLE_VALUE)
1392c2c66affSColin Finck                 {
1393c2c66affSColin Finck                     WARN("Could not create cache file: %u\n", GetLastError());
1394c2c66affSColin Finck                     heap_free(lpwh->cache_file);
1395c2c66affSColin Finck                     lpwh->cache_file = NULL;
1396c2c66affSColin Finck                 }
1397c2c66affSColin Finck             }
1398c2c66affSColin Finck             heap_free(url);
1399c2c66affSColin Finck         }
1400c2c66affSColin Finck         heap_free(uc.lpszUrlPath);
1401c2c66affSColin Finck     }
1402c2c66affSColin Finck 
1403c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1404c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1405c2c66affSColin Finck     {
1406c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
1407c2c66affSColin Finck 
1408c2c66affSColin Finck 	if (lpwh)
1409c2c66affSColin Finck 	{
1410c2c66affSColin Finck             iar.dwResult = (DWORD_PTR)lpwh->hdr.hInternet;
1411c2c66affSColin Finck             iar.dwError = ERROR_SUCCESS;
1412c2c66affSColin Finck             INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1413c2c66affSColin Finck                 &iar, sizeof(INTERNET_ASYNC_RESULT));
1414c2c66affSColin Finck 	}
1415c2c66affSColin Finck 
1416c2c66affSColin Finck         if(bSuccess) {
1417c2c66affSColin Finck             FTP_ReceiveRequestData(lpwh, TRUE);
1418c2c66affSColin Finck         }else {
1419c2c66affSColin Finck             iar.dwResult = 0;
1420c2c66affSColin Finck             iar.dwError = INTERNET_GetLastError();
1421c2c66affSColin Finck             INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1422c2c66affSColin Finck                     &iar, sizeof(INTERNET_ASYNC_RESULT));
1423c2c66affSColin Finck         }
1424c2c66affSColin Finck     }
1425c2c66affSColin Finck 
1426c2c66affSColin Finck     if(!bSuccess)
1427c2c66affSColin Finck         return FALSE;
1428c2c66affSColin Finck 
1429c2c66affSColin Finck     return lpwh->hdr.hInternet;
1430c2c66affSColin Finck }
1431c2c66affSColin Finck 
1432c2c66affSColin Finck 
1433c2c66affSColin Finck /***********************************************************************
1434c2c66affSColin Finck  *           FtpOpenFileA (WININET.@)
1435c2c66affSColin Finck  *
1436c2c66affSColin Finck  * Open a remote file for writing or reading
1437c2c66affSColin Finck  *
1438c2c66affSColin Finck  * RETURNS
1439c2c66affSColin Finck  *    HINTERNET handle on success
1440c2c66affSColin Finck  *    NULL on failure
1441c2c66affSColin Finck  *
1442c2c66affSColin Finck  */
FtpOpenFileA(HINTERNET hFtpSession,LPCSTR lpszFileName,DWORD fdwAccess,DWORD dwFlags,DWORD_PTR dwContext)1443c2c66affSColin Finck HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
1444c2c66affSColin Finck     LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1445c2c66affSColin Finck     DWORD_PTR dwContext)
1446c2c66affSColin Finck {
1447c2c66affSColin Finck     LPWSTR lpwzFileName;
1448c2c66affSColin Finck     HINTERNET ret;
1449c2c66affSColin Finck 
1450c2c66affSColin Finck     lpwzFileName = heap_strdupAtoW(lpszFileName);
1451c2c66affSColin Finck     ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
1452c2c66affSColin Finck     heap_free(lpwzFileName);
1453c2c66affSColin Finck     return ret;
1454c2c66affSColin Finck }
1455c2c66affSColin Finck 
1456c2c66affSColin Finck typedef struct {
1457c2c66affSColin Finck     task_header_t hdr;
1458c2c66affSColin Finck     WCHAR *file_name;
1459c2c66affSColin Finck     DWORD access;
1460c2c66affSColin Finck     DWORD flags;
1461c2c66affSColin Finck     DWORD_PTR context;
1462c2c66affSColin Finck } open_file_task_t;
1463c2c66affSColin Finck 
AsyncFtpOpenFileProc(task_header_t * hdr)1464c2c66affSColin Finck static void AsyncFtpOpenFileProc(task_header_t *hdr)
1465c2c66affSColin Finck {
1466c2c66affSColin Finck     open_file_task_t *task = (open_file_task_t*)hdr;
1467c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
1468c2c66affSColin Finck 
1469c2c66affSColin Finck     TRACE("%p\n", session);
1470c2c66affSColin Finck 
1471c2c66affSColin Finck     FTP_FtpOpenFileW(session, task->file_name, task->access, task->flags, task->context);
1472c2c66affSColin Finck     heap_free(task->file_name);
1473c2c66affSColin Finck }
1474c2c66affSColin Finck 
1475c2c66affSColin Finck /***********************************************************************
1476c2c66affSColin Finck  *           FtpOpenFileW (WININET.@)
1477c2c66affSColin Finck  *
1478c2c66affSColin Finck  * Open a remote file for writing or reading
1479c2c66affSColin Finck  *
1480c2c66affSColin Finck  * RETURNS
1481c2c66affSColin Finck  *    HINTERNET handle on success
1482c2c66affSColin Finck  *    NULL on failure
1483c2c66affSColin Finck  *
1484c2c66affSColin Finck  */
FtpOpenFileW(HINTERNET hFtpSession,LPCWSTR lpszFileName,DWORD fdwAccess,DWORD dwFlags,DWORD_PTR dwContext)1485c2c66affSColin Finck HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1486c2c66affSColin Finck     LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1487c2c66affSColin Finck     DWORD_PTR dwContext)
1488c2c66affSColin Finck {
1489c2c66affSColin Finck     ftp_session_t *lpwfs;
1490c2c66affSColin Finck     appinfo_t *hIC = NULL;
1491c2c66affSColin Finck     HINTERNET r = NULL;
1492c2c66affSColin Finck 
1493c2c66affSColin Finck     TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
1494c2c66affSColin Finck         debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1495c2c66affSColin Finck 
1496c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hFtpSession );
1497c2c66affSColin Finck     if (!lpwfs)
1498c2c66affSColin Finck     {
1499c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1500c2c66affSColin Finck         return FALSE;
1501c2c66affSColin Finck     }
1502c2c66affSColin Finck 
1503c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
1504c2c66affSColin Finck     {
1505c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1506c2c66affSColin Finck         goto lend;
1507c2c66affSColin Finck     }
1508c2c66affSColin Finck 
1509c2c66affSColin Finck     if ((!lpszFileName) ||
1510c2c66affSColin Finck         ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1511c2c66affSColin Finck         ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1512c2c66affSColin Finck     {
1513c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1514c2c66affSColin Finck         goto lend;
1515c2c66affSColin Finck     }
1516c2c66affSColin Finck 
1517c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
1518c2c66affSColin Finck     {
1519c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1520c2c66affSColin Finck         goto lend;
1521c2c66affSColin Finck     }
1522c2c66affSColin Finck 
1523c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1524c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1525c2c66affSColin Finck     {
1526c2c66affSColin Finck         open_file_task_t *task;
1527c2c66affSColin Finck 
1528c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpOpenFileProc, sizeof(*task));
1529c2c66affSColin Finck         task->file_name = heap_strdupW(lpszFileName);
1530c2c66affSColin Finck         task->access = fdwAccess;
1531c2c66affSColin Finck         task->flags = dwFlags;
1532c2c66affSColin Finck         task->context = dwContext;
1533c2c66affSColin Finck 
1534c2c66affSColin Finck         INTERNET_AsyncCall(&task->hdr);
1535c2c66affSColin Finck         r = NULL;
1536c2c66affSColin Finck     }
1537c2c66affSColin Finck     else
1538c2c66affSColin Finck     {
1539c2c66affSColin Finck 	r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1540c2c66affSColin Finck     }
1541c2c66affSColin Finck 
1542c2c66affSColin Finck lend:
1543c2c66affSColin Finck     WININET_Release( &lpwfs->hdr );
1544c2c66affSColin Finck 
1545c2c66affSColin Finck     return r;
1546c2c66affSColin Finck }
1547c2c66affSColin Finck 
1548c2c66affSColin Finck 
1549c2c66affSColin Finck /***********************************************************************
1550c2c66affSColin Finck  *           FtpGetFileA (WININET.@)
1551c2c66affSColin Finck  *
1552c2c66affSColin Finck  * Retrieve file from the FTP server
1553c2c66affSColin Finck  *
1554c2c66affSColin Finck  * RETURNS
1555c2c66affSColin Finck  *    TRUE on success
1556c2c66affSColin Finck  *    FALSE on failure
1557c2c66affSColin Finck  *
1558c2c66affSColin Finck  */
FtpGetFileA(HINTERNET hInternet,LPCSTR lpszRemoteFile,LPCSTR lpszNewFile,BOOL fFailIfExists,DWORD dwLocalFlagsAttribute,DWORD dwInternetFlags,DWORD_PTR dwContext)1559c2c66affSColin Finck BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1560c2c66affSColin Finck     BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1561c2c66affSColin Finck     DWORD_PTR dwContext)
1562c2c66affSColin Finck {
1563c2c66affSColin Finck     LPWSTR lpwzRemoteFile;
1564c2c66affSColin Finck     LPWSTR lpwzNewFile;
1565c2c66affSColin Finck     BOOL ret;
1566c2c66affSColin Finck 
1567c2c66affSColin Finck     lpwzRemoteFile = heap_strdupAtoW(lpszRemoteFile);
1568c2c66affSColin Finck     lpwzNewFile = heap_strdupAtoW(lpszNewFile);
1569c2c66affSColin Finck     ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1570c2c66affSColin Finck         dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1571c2c66affSColin Finck     heap_free(lpwzRemoteFile);
1572c2c66affSColin Finck     heap_free(lpwzNewFile);
1573c2c66affSColin Finck     return ret;
1574c2c66affSColin Finck }
1575c2c66affSColin Finck 
1576c2c66affSColin Finck typedef struct {
1577c2c66affSColin Finck     task_header_t hdr;
1578c2c66affSColin Finck     WCHAR *remote_file;
1579c2c66affSColin Finck     WCHAR *new_file;
1580c2c66affSColin Finck     BOOL fail_if_exists;
1581c2c66affSColin Finck     DWORD local_attr;
1582c2c66affSColin Finck     DWORD flags;
1583c2c66affSColin Finck     DWORD_PTR context;
1584c2c66affSColin Finck } get_file_task_t;
1585c2c66affSColin Finck 
AsyncFtpGetFileProc(task_header_t * hdr)1586c2c66affSColin Finck static void AsyncFtpGetFileProc(task_header_t *hdr)
1587c2c66affSColin Finck {
1588c2c66affSColin Finck     get_file_task_t *task = (get_file_task_t*)hdr;
1589c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
1590c2c66affSColin Finck 
1591c2c66affSColin Finck     TRACE("%p\n", session);
1592c2c66affSColin Finck 
1593c2c66affSColin Finck     FTP_FtpGetFileW(session, task->remote_file, task->new_file, task->fail_if_exists,
1594c2c66affSColin Finck              task->local_attr, task->flags, task->context);
1595c2c66affSColin Finck     heap_free(task->remote_file);
1596c2c66affSColin Finck     heap_free(task->new_file);
1597c2c66affSColin Finck }
1598c2c66affSColin Finck 
1599c2c66affSColin Finck 
1600c2c66affSColin Finck /***********************************************************************
1601c2c66affSColin Finck  *           FtpGetFileW (WININET.@)
1602c2c66affSColin Finck  *
1603c2c66affSColin Finck  * Retrieve file from the FTP server
1604c2c66affSColin Finck  *
1605c2c66affSColin Finck  * RETURNS
1606c2c66affSColin Finck  *    TRUE on success
1607c2c66affSColin Finck  *    FALSE on failure
1608c2c66affSColin Finck  *
1609c2c66affSColin Finck  */
FtpGetFileW(HINTERNET hInternet,LPCWSTR lpszRemoteFile,LPCWSTR lpszNewFile,BOOL fFailIfExists,DWORD dwLocalFlagsAttribute,DWORD dwInternetFlags,DWORD_PTR dwContext)1610c2c66affSColin Finck BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1611c2c66affSColin Finck     BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1612c2c66affSColin Finck     DWORD_PTR dwContext)
1613c2c66affSColin Finck {
1614c2c66affSColin Finck     ftp_session_t *lpwfs;
1615c2c66affSColin Finck     appinfo_t *hIC = NULL;
1616c2c66affSColin Finck     BOOL r = FALSE;
1617c2c66affSColin Finck 
1618c2c66affSColin Finck     if (!lpszRemoteFile || !lpszNewFile)
1619c2c66affSColin Finck     {
1620c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1621c2c66affSColin Finck         return FALSE;
1622c2c66affSColin Finck     }
1623c2c66affSColin Finck 
1624c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hInternet );
1625c2c66affSColin Finck     if (!lpwfs)
1626c2c66affSColin Finck     {
1627c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1628c2c66affSColin Finck         return FALSE;
1629c2c66affSColin Finck     }
1630c2c66affSColin Finck 
1631c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
1632c2c66affSColin Finck     {
1633c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1634c2c66affSColin Finck         goto lend;
1635c2c66affSColin Finck     }
1636c2c66affSColin Finck 
1637c2c66affSColin Finck     if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1638c2c66affSColin Finck     {
1639c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1640c2c66affSColin Finck         goto lend;
1641c2c66affSColin Finck     }
1642c2c66affSColin Finck 
1643c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
1644c2c66affSColin Finck     {
1645c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1646c2c66affSColin Finck         goto lend;
1647c2c66affSColin Finck     }
1648c2c66affSColin Finck 
1649c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1650c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1651c2c66affSColin Finck     {
1652c2c66affSColin Finck         get_file_task_t *task;
1653c2c66affSColin Finck 
1654c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpGetFileProc, sizeof(*task));
1655c2c66affSColin Finck         task->remote_file = heap_strdupW(lpszRemoteFile);
1656c2c66affSColin Finck         task->new_file = heap_strdupW(lpszNewFile);
1657c2c66affSColin Finck         task->local_attr = dwLocalFlagsAttribute;
1658c2c66affSColin Finck         task->fail_if_exists = fFailIfExists;
1659c2c66affSColin Finck         task->flags = dwInternetFlags;
1660c2c66affSColin Finck         task->context = dwContext;
1661c2c66affSColin Finck 
1662c2c66affSColin Finck         r = res_to_le(INTERNET_AsyncCall(&task->hdr));
1663c2c66affSColin Finck     }
1664c2c66affSColin Finck     else
1665c2c66affSColin Finck     {
1666c2c66affSColin Finck         r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1667c2c66affSColin Finck            fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1668c2c66affSColin Finck     }
1669c2c66affSColin Finck 
1670c2c66affSColin Finck lend:
1671c2c66affSColin Finck     WININET_Release( &lpwfs->hdr );
1672c2c66affSColin Finck 
1673c2c66affSColin Finck     return r;
1674c2c66affSColin Finck }
1675c2c66affSColin Finck 
1676c2c66affSColin Finck 
1677c2c66affSColin Finck /***********************************************************************
1678c2c66affSColin Finck  *           FTP_FtpGetFileW (Internal)
1679c2c66affSColin Finck  *
1680c2c66affSColin Finck  * Retrieve file from the FTP server
1681c2c66affSColin Finck  *
1682c2c66affSColin Finck  * RETURNS
1683c2c66affSColin Finck  *    TRUE on success
1684c2c66affSColin Finck  *    FALSE on failure
1685c2c66affSColin Finck  *
1686c2c66affSColin Finck  */
FTP_FtpGetFileW(ftp_session_t * lpwfs,LPCWSTR lpszRemoteFile,LPCWSTR lpszNewFile,BOOL fFailIfExists,DWORD dwLocalFlagsAttribute,DWORD dwInternetFlags,DWORD_PTR dwContext)1687c2c66affSColin Finck static BOOL FTP_FtpGetFileW(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1688c2c66affSColin Finck 	BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1689c2c66affSColin Finck 	DWORD_PTR dwContext)
1690c2c66affSColin Finck {
1691c2c66affSColin Finck     BOOL bSuccess = FALSE;
1692c2c66affSColin Finck     HANDLE hFile;
1693c2c66affSColin Finck     appinfo_t *hIC = NULL;
1694c2c66affSColin Finck 
1695c2c66affSColin Finck     TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1696c2c66affSColin Finck 
1697c2c66affSColin Finck     /* Clear any error information */
1698c2c66affSColin Finck     INTERNET_SetLastError(0);
1699c2c66affSColin Finck 
1700c2c66affSColin Finck     /* Ensure we can write to lpszNewfile by opening it */
1701c2c66affSColin Finck     hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1702c2c66affSColin Finck         CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1703c2c66affSColin Finck     if (INVALID_HANDLE_VALUE == hFile)
1704c2c66affSColin Finck         return FALSE;
1705c2c66affSColin Finck 
1706c2c66affSColin Finck     /* Set up socket to retrieve data */
1707c2c66affSColin Finck     if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1708c2c66affSColin Finck     {
1709c2c66affSColin Finck         INT nDataSocket;
1710c2c66affSColin Finck 
1711c2c66affSColin Finck         /* Get data socket to server */
1712c2c66affSColin Finck         if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1713c2c66affSColin Finck         {
1714c2c66affSColin Finck             INT nResCode;
1715c2c66affSColin Finck 
1716c2c66affSColin Finck             /* Receive data */
1717c2c66affSColin Finck             FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1718c2c66affSColin Finck             closesocket(nDataSocket);
1719c2c66affSColin Finck 
1720c2c66affSColin Finck             nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1721c2c66affSColin Finck             if (nResCode)
1722c2c66affSColin Finck             {
1723c2c66affSColin Finck                 if (nResCode == 226)
1724c2c66affSColin Finck                     bSuccess = TRUE;
1725c2c66affSColin Finck                 else
1726c2c66affSColin Finck                     FTP_SetResponseError(nResCode);
1727c2c66affSColin Finck             }
1728c2c66affSColin Finck         }
1729c2c66affSColin Finck     }
1730c2c66affSColin Finck 
1731c2c66affSColin Finck     if (lpwfs->lstnSocket != -1)
1732c2c66affSColin Finck     {
1733c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
1734c2c66affSColin Finck         lpwfs->lstnSocket = -1;
1735c2c66affSColin Finck     }
1736c2c66affSColin Finck 
1737c2c66affSColin Finck     CloseHandle(hFile);
1738c2c66affSColin Finck 
1739c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1740c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1741c2c66affSColin Finck     {
1742c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
1743c2c66affSColin Finck 
1744c2c66affSColin Finck         iar.dwResult = (DWORD)bSuccess;
1745c2c66affSColin Finck         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1746c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1747c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
1748c2c66affSColin Finck     }
1749c2c66affSColin Finck 
1750c2c66affSColin Finck     if (!bSuccess) DeleteFileW(lpszNewFile);
1751c2c66affSColin Finck     return bSuccess;
1752c2c66affSColin Finck }
1753c2c66affSColin Finck 
1754c2c66affSColin Finck /***********************************************************************
1755c2c66affSColin Finck  *           FtpGetFileSize  (WININET.@)
1756c2c66affSColin Finck  */
FtpGetFileSize(HINTERNET hFile,LPDWORD lpdwFileSizeHigh)1757c2c66affSColin Finck DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1758c2c66affSColin Finck {
1759c2c66affSColin Finck     FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1760c2c66affSColin Finck 
1761c2c66affSColin Finck     if (lpdwFileSizeHigh)
1762c2c66affSColin Finck         *lpdwFileSizeHigh = 0;
1763c2c66affSColin Finck 
1764c2c66affSColin Finck     return 0;
1765c2c66affSColin Finck }
1766c2c66affSColin Finck 
1767c2c66affSColin Finck /***********************************************************************
1768c2c66affSColin Finck  *           FtpDeleteFileA  (WININET.@)
1769c2c66affSColin Finck  *
1770c2c66affSColin Finck  * Delete a file on the ftp server
1771c2c66affSColin Finck  *
1772c2c66affSColin Finck  * RETURNS
1773c2c66affSColin Finck  *    TRUE on success
1774c2c66affSColin Finck  *    FALSE on failure
1775c2c66affSColin Finck  *
1776c2c66affSColin Finck  */
FtpDeleteFileA(HINTERNET hFtpSession,LPCSTR lpszFileName)1777c2c66affSColin Finck BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1778c2c66affSColin Finck {
1779c2c66affSColin Finck     LPWSTR lpwzFileName;
1780c2c66affSColin Finck     BOOL ret;
1781c2c66affSColin Finck 
1782c2c66affSColin Finck     lpwzFileName = heap_strdupAtoW(lpszFileName);
1783c2c66affSColin Finck     ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1784c2c66affSColin Finck     heap_free(lpwzFileName);
1785c2c66affSColin Finck     return ret;
1786c2c66affSColin Finck }
1787c2c66affSColin Finck 
1788c2c66affSColin Finck typedef struct {
1789c2c66affSColin Finck     task_header_t hdr;
1790c2c66affSColin Finck     WCHAR *file_name;
1791c2c66affSColin Finck } delete_file_task_t;
1792c2c66affSColin Finck 
AsyncFtpDeleteFileProc(task_header_t * hdr)1793c2c66affSColin Finck static void AsyncFtpDeleteFileProc(task_header_t *hdr)
1794c2c66affSColin Finck {
1795c2c66affSColin Finck     delete_file_task_t *task = (delete_file_task_t*)hdr;
1796c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
1797c2c66affSColin Finck 
1798c2c66affSColin Finck     TRACE("%p\n", session);
1799c2c66affSColin Finck 
1800c2c66affSColin Finck     FTP_FtpDeleteFileW(session, task->file_name);
1801c2c66affSColin Finck     heap_free(task->file_name);
1802c2c66affSColin Finck }
1803c2c66affSColin Finck 
1804c2c66affSColin Finck /***********************************************************************
1805c2c66affSColin Finck  *           FtpDeleteFileW  (WININET.@)
1806c2c66affSColin Finck  *
1807c2c66affSColin Finck  * Delete a file on the ftp server
1808c2c66affSColin Finck  *
1809c2c66affSColin Finck  * RETURNS
1810c2c66affSColin Finck  *    TRUE on success
1811c2c66affSColin Finck  *    FALSE on failure
1812c2c66affSColin Finck  *
1813c2c66affSColin Finck  */
FtpDeleteFileW(HINTERNET hFtpSession,LPCWSTR lpszFileName)1814c2c66affSColin Finck BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1815c2c66affSColin Finck {
1816c2c66affSColin Finck     ftp_session_t *lpwfs;
1817c2c66affSColin Finck     appinfo_t *hIC = NULL;
1818c2c66affSColin Finck     BOOL r = FALSE;
1819c2c66affSColin Finck 
1820c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hFtpSession );
1821c2c66affSColin Finck     if (!lpwfs)
1822c2c66affSColin Finck     {
1823c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1824c2c66affSColin Finck         return FALSE;
1825c2c66affSColin Finck     }
1826c2c66affSColin Finck 
1827c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
1828c2c66affSColin Finck     {
1829c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1830c2c66affSColin Finck         goto lend;
1831c2c66affSColin Finck     }
1832c2c66affSColin Finck 
1833c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
1834c2c66affSColin Finck     {
1835c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1836c2c66affSColin Finck         goto lend;
1837c2c66affSColin Finck     }
1838c2c66affSColin Finck 
1839c2c66affSColin Finck     if (!lpszFileName)
1840c2c66affSColin Finck     {
1841c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1842c2c66affSColin Finck         goto lend;
1843c2c66affSColin Finck     }
1844c2c66affSColin Finck 
1845c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1846c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1847c2c66affSColin Finck     {
1848c2c66affSColin Finck         delete_file_task_t *task;
1849c2c66affSColin Finck 
1850c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpDeleteFileProc, sizeof(*task));
1851c2c66affSColin Finck         task->file_name = heap_strdupW(lpszFileName);
1852c2c66affSColin Finck 
1853c2c66affSColin Finck         r = res_to_le(INTERNET_AsyncCall(&task->hdr));
1854c2c66affSColin Finck     }
1855c2c66affSColin Finck     else
1856c2c66affSColin Finck     {
1857c2c66affSColin Finck         r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1858c2c66affSColin Finck     }
1859c2c66affSColin Finck 
1860c2c66affSColin Finck lend:
1861c2c66affSColin Finck     WININET_Release( &lpwfs->hdr );
1862c2c66affSColin Finck 
1863c2c66affSColin Finck     return r;
1864c2c66affSColin Finck }
1865c2c66affSColin Finck 
1866c2c66affSColin Finck /***********************************************************************
1867c2c66affSColin Finck  *           FTP_FtpDeleteFileW  (Internal)
1868c2c66affSColin Finck  *
1869c2c66affSColin Finck  * Delete a file on the ftp server
1870c2c66affSColin Finck  *
1871c2c66affSColin Finck  * RETURNS
1872c2c66affSColin Finck  *    TRUE on success
1873c2c66affSColin Finck  *    FALSE on failure
1874c2c66affSColin Finck  *
1875c2c66affSColin Finck  */
FTP_FtpDeleteFileW(ftp_session_t * lpwfs,LPCWSTR lpszFileName)1876c2c66affSColin Finck BOOL FTP_FtpDeleteFileW(ftp_session_t *lpwfs, LPCWSTR lpszFileName)
1877c2c66affSColin Finck {
1878c2c66affSColin Finck     INT nResCode;
1879c2c66affSColin Finck     BOOL bSuccess = FALSE;
1880c2c66affSColin Finck     appinfo_t *hIC = NULL;
1881c2c66affSColin Finck 
1882c2c66affSColin Finck     TRACE("%p\n", lpwfs);
1883c2c66affSColin Finck 
1884c2c66affSColin Finck     /* Clear any error information */
1885c2c66affSColin Finck     INTERNET_SetLastError(0);
1886c2c66affSColin Finck 
1887c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1888c2c66affSColin Finck         goto lend;
1889c2c66affSColin Finck 
1890c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1891c2c66affSColin Finck     if (nResCode)
1892c2c66affSColin Finck     {
1893c2c66affSColin Finck         if (nResCode == 250)
1894c2c66affSColin Finck             bSuccess = TRUE;
1895c2c66affSColin Finck         else
1896c2c66affSColin Finck             FTP_SetResponseError(nResCode);
1897c2c66affSColin Finck     }
1898c2c66affSColin Finck lend:
1899c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1900c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1901c2c66affSColin Finck     {
1902c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
1903c2c66affSColin Finck 
1904c2c66affSColin Finck         iar.dwResult = (DWORD)bSuccess;
1905c2c66affSColin Finck         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1906c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1907c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
1908c2c66affSColin Finck     }
1909c2c66affSColin Finck 
1910c2c66affSColin Finck     return bSuccess;
1911c2c66affSColin Finck }
1912c2c66affSColin Finck 
1913c2c66affSColin Finck 
1914c2c66affSColin Finck /***********************************************************************
1915c2c66affSColin Finck  *           FtpRemoveDirectoryA  (WININET.@)
1916c2c66affSColin Finck  *
1917c2c66affSColin Finck  * Remove a directory on the ftp server
1918c2c66affSColin Finck  *
1919c2c66affSColin Finck  * RETURNS
1920c2c66affSColin Finck  *    TRUE on success
1921c2c66affSColin Finck  *    FALSE on failure
1922c2c66affSColin Finck  *
1923c2c66affSColin Finck  */
FtpRemoveDirectoryA(HINTERNET hFtpSession,LPCSTR lpszDirectory)1924c2c66affSColin Finck BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1925c2c66affSColin Finck {
1926c2c66affSColin Finck     LPWSTR lpwzDirectory;
1927c2c66affSColin Finck     BOOL ret;
1928c2c66affSColin Finck 
1929c2c66affSColin Finck     lpwzDirectory = heap_strdupAtoW(lpszDirectory);
1930c2c66affSColin Finck     ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1931c2c66affSColin Finck     heap_free(lpwzDirectory);
1932c2c66affSColin Finck     return ret;
1933c2c66affSColin Finck }
1934c2c66affSColin Finck 
AsyncFtpRemoveDirectoryProc(task_header_t * hdr)1935c2c66affSColin Finck static void AsyncFtpRemoveDirectoryProc(task_header_t *hdr)
1936c2c66affSColin Finck {
1937c2c66affSColin Finck     directory_task_t *task = (directory_task_t*)hdr;
1938c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
1939c2c66affSColin Finck 
1940c2c66affSColin Finck     TRACE("%p\n", session);
1941c2c66affSColin Finck 
1942c2c66affSColin Finck     FTP_FtpRemoveDirectoryW(session, task->directory);
1943c2c66affSColin Finck     heap_free(task->directory);
1944c2c66affSColin Finck }
1945c2c66affSColin Finck 
1946c2c66affSColin Finck /***********************************************************************
1947c2c66affSColin Finck  *           FtpRemoveDirectoryW  (WININET.@)
1948c2c66affSColin Finck  *
1949c2c66affSColin Finck  * Remove a directory on the ftp server
1950c2c66affSColin Finck  *
1951c2c66affSColin Finck  * RETURNS
1952c2c66affSColin Finck  *    TRUE on success
1953c2c66affSColin Finck  *    FALSE on failure
1954c2c66affSColin Finck  *
1955c2c66affSColin Finck  */
FtpRemoveDirectoryW(HINTERNET hFtpSession,LPCWSTR lpszDirectory)1956c2c66affSColin Finck BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1957c2c66affSColin Finck {
1958c2c66affSColin Finck     ftp_session_t *lpwfs;
1959c2c66affSColin Finck     appinfo_t *hIC = NULL;
1960c2c66affSColin Finck     BOOL r = FALSE;
1961c2c66affSColin Finck 
1962c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hFtpSession );
1963c2c66affSColin Finck     if (!lpwfs)
1964c2c66affSColin Finck     {
1965c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1966c2c66affSColin Finck         return FALSE;
1967c2c66affSColin Finck     }
1968c2c66affSColin Finck 
1969c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
1970c2c66affSColin Finck     {
1971c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1972c2c66affSColin Finck         goto lend;
1973c2c66affSColin Finck     }
1974c2c66affSColin Finck 
1975c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
1976c2c66affSColin Finck     {
1977c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1978c2c66affSColin Finck         goto lend;
1979c2c66affSColin Finck     }
1980c2c66affSColin Finck 
1981c2c66affSColin Finck     if (!lpszDirectory)
1982c2c66affSColin Finck     {
1983c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1984c2c66affSColin Finck         goto lend;
1985c2c66affSColin Finck     }
1986c2c66affSColin Finck 
1987c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
1988c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1989c2c66affSColin Finck     {
1990c2c66affSColin Finck         directory_task_t *task;
1991c2c66affSColin Finck 
1992c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpRemoveDirectoryProc, sizeof(*task));
1993c2c66affSColin Finck         task->directory = heap_strdupW(lpszDirectory);
1994c2c66affSColin Finck 
1995c2c66affSColin Finck         r = res_to_le(INTERNET_AsyncCall(&task->hdr));
1996c2c66affSColin Finck     }
1997c2c66affSColin Finck     else
1998c2c66affSColin Finck     {
1999c2c66affSColin Finck         r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
2000c2c66affSColin Finck     }
2001c2c66affSColin Finck 
2002c2c66affSColin Finck lend:
2003c2c66affSColin Finck     WININET_Release( &lpwfs->hdr );
2004c2c66affSColin Finck 
2005c2c66affSColin Finck     return r;
2006c2c66affSColin Finck }
2007c2c66affSColin Finck 
2008c2c66affSColin Finck /***********************************************************************
2009c2c66affSColin Finck  *           FTP_FtpRemoveDirectoryW  (Internal)
2010c2c66affSColin Finck  *
2011c2c66affSColin Finck  * Remove a directory on the ftp server
2012c2c66affSColin Finck  *
2013c2c66affSColin Finck  * RETURNS
2014c2c66affSColin Finck  *    TRUE on success
2015c2c66affSColin Finck  *    FALSE on failure
2016c2c66affSColin Finck  *
2017c2c66affSColin Finck  */
FTP_FtpRemoveDirectoryW(ftp_session_t * lpwfs,LPCWSTR lpszDirectory)2018c2c66affSColin Finck BOOL FTP_FtpRemoveDirectoryW(ftp_session_t *lpwfs, LPCWSTR lpszDirectory)
2019c2c66affSColin Finck {
2020c2c66affSColin Finck     INT nResCode;
2021c2c66affSColin Finck     BOOL bSuccess = FALSE;
2022c2c66affSColin Finck     appinfo_t *hIC = NULL;
2023c2c66affSColin Finck 
2024c2c66affSColin Finck     TRACE("\n");
2025c2c66affSColin Finck 
2026c2c66affSColin Finck     /* Clear any error information */
2027c2c66affSColin Finck     INTERNET_SetLastError(0);
2028c2c66affSColin Finck 
2029c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
2030c2c66affSColin Finck         goto lend;
2031c2c66affSColin Finck 
2032c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2033c2c66affSColin Finck     if (nResCode)
2034c2c66affSColin Finck     {
2035c2c66affSColin Finck         if (nResCode == 250)
2036c2c66affSColin Finck             bSuccess = TRUE;
2037c2c66affSColin Finck         else
2038c2c66affSColin Finck             FTP_SetResponseError(nResCode);
2039c2c66affSColin Finck     }
2040c2c66affSColin Finck 
2041c2c66affSColin Finck lend:
2042c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
2043c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2044c2c66affSColin Finck     {
2045c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
2046c2c66affSColin Finck 
2047c2c66affSColin Finck         iar.dwResult = (DWORD)bSuccess;
2048c2c66affSColin Finck         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2049c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2050c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
2051c2c66affSColin Finck     }
2052c2c66affSColin Finck 
2053c2c66affSColin Finck     return bSuccess;
2054c2c66affSColin Finck }
2055c2c66affSColin Finck 
2056c2c66affSColin Finck 
2057c2c66affSColin Finck /***********************************************************************
2058c2c66affSColin Finck  *           FtpRenameFileA  (WININET.@)
2059c2c66affSColin Finck  *
2060c2c66affSColin Finck  * Rename a file on the ftp server
2061c2c66affSColin Finck  *
2062c2c66affSColin Finck  * RETURNS
2063c2c66affSColin Finck  *    TRUE on success
2064c2c66affSColin Finck  *    FALSE on failure
2065c2c66affSColin Finck  *
2066c2c66affSColin Finck  */
FtpRenameFileA(HINTERNET hFtpSession,LPCSTR lpszSrc,LPCSTR lpszDest)2067c2c66affSColin Finck BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
2068c2c66affSColin Finck {
2069c2c66affSColin Finck     LPWSTR lpwzSrc;
2070c2c66affSColin Finck     LPWSTR lpwzDest;
2071c2c66affSColin Finck     BOOL ret;
2072c2c66affSColin Finck 
2073c2c66affSColin Finck     lpwzSrc = heap_strdupAtoW(lpszSrc);
2074c2c66affSColin Finck     lpwzDest = heap_strdupAtoW(lpszDest);
2075c2c66affSColin Finck     ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
2076c2c66affSColin Finck     heap_free(lpwzSrc);
2077c2c66affSColin Finck     heap_free(lpwzDest);
2078c2c66affSColin Finck     return ret;
2079c2c66affSColin Finck }
2080c2c66affSColin Finck 
2081c2c66affSColin Finck typedef struct {
2082c2c66affSColin Finck     task_header_t hdr;
2083c2c66affSColin Finck     WCHAR *src_file;
2084c2c66affSColin Finck     WCHAR *dst_file;
2085c2c66affSColin Finck } rename_file_task_t;
2086c2c66affSColin Finck 
AsyncFtpRenameFileProc(task_header_t * hdr)2087c2c66affSColin Finck static void AsyncFtpRenameFileProc(task_header_t *hdr)
2088c2c66affSColin Finck {
2089c2c66affSColin Finck     rename_file_task_t *task = (rename_file_task_t*)hdr;
2090c2c66affSColin Finck     ftp_session_t *session = (ftp_session_t*)task->hdr.hdr;
2091c2c66affSColin Finck 
2092c2c66affSColin Finck     TRACE("%p\n", session);
2093c2c66affSColin Finck 
2094c2c66affSColin Finck     FTP_FtpRenameFileW(session, task->src_file, task->dst_file);
2095c2c66affSColin Finck     heap_free(task->src_file);
2096c2c66affSColin Finck     heap_free(task->dst_file);
2097c2c66affSColin Finck }
2098c2c66affSColin Finck 
2099c2c66affSColin Finck /***********************************************************************
2100c2c66affSColin Finck  *           FtpRenameFileW  (WININET.@)
2101c2c66affSColin Finck  *
2102c2c66affSColin Finck  * Rename a file on the ftp server
2103c2c66affSColin Finck  *
2104c2c66affSColin Finck  * RETURNS
2105c2c66affSColin Finck  *    TRUE on success
2106c2c66affSColin Finck  *    FALSE on failure
2107c2c66affSColin Finck  *
2108c2c66affSColin Finck  */
FtpRenameFileW(HINTERNET hFtpSession,LPCWSTR lpszSrc,LPCWSTR lpszDest)2109c2c66affSColin Finck BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
2110c2c66affSColin Finck {
2111c2c66affSColin Finck     ftp_session_t *lpwfs;
2112c2c66affSColin Finck     appinfo_t *hIC = NULL;
2113c2c66affSColin Finck     BOOL r = FALSE;
2114c2c66affSColin Finck 
2115c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hFtpSession );
2116c2c66affSColin Finck     if (!lpwfs)
2117c2c66affSColin Finck     {
2118c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2119c2c66affSColin Finck         return FALSE;
2120c2c66affSColin Finck     }
2121c2c66affSColin Finck 
2122c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
2123c2c66affSColin Finck     {
2124c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2125c2c66affSColin Finck         goto lend;
2126c2c66affSColin Finck     }
2127c2c66affSColin Finck 
2128c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
2129c2c66affSColin Finck     {
2130c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2131c2c66affSColin Finck         goto lend;
2132c2c66affSColin Finck     }
2133c2c66affSColin Finck 
2134c2c66affSColin Finck     if (!lpszSrc || !lpszDest)
2135c2c66affSColin Finck     {
2136c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2137c2c66affSColin Finck         goto lend;
2138c2c66affSColin Finck     }
2139c2c66affSColin Finck 
2140c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
2141c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2142c2c66affSColin Finck     {
2143c2c66affSColin Finck         rename_file_task_t *task;
2144c2c66affSColin Finck 
2145c2c66affSColin Finck         task = alloc_async_task(&lpwfs->hdr, AsyncFtpRenameFileProc, sizeof(*task));
2146c2c66affSColin Finck         task->src_file = heap_strdupW(lpszSrc);
2147c2c66affSColin Finck         task->dst_file = heap_strdupW(lpszDest);
2148c2c66affSColin Finck 
2149c2c66affSColin Finck         r = res_to_le(INTERNET_AsyncCall(&task->hdr));
2150c2c66affSColin Finck     }
2151c2c66affSColin Finck     else
2152c2c66affSColin Finck     {
2153c2c66affSColin Finck         r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
2154c2c66affSColin Finck     }
2155c2c66affSColin Finck 
2156c2c66affSColin Finck lend:
2157c2c66affSColin Finck     WININET_Release( &lpwfs->hdr );
2158c2c66affSColin Finck 
2159c2c66affSColin Finck     return r;
2160c2c66affSColin Finck }
2161c2c66affSColin Finck 
2162c2c66affSColin Finck /***********************************************************************
2163c2c66affSColin Finck  *           FTP_FtpRenameFileW  (Internal)
2164c2c66affSColin Finck  *
2165c2c66affSColin Finck  * Rename a file on the ftp server
2166c2c66affSColin Finck  *
2167c2c66affSColin Finck  * RETURNS
2168c2c66affSColin Finck  *    TRUE on success
2169c2c66affSColin Finck  *    FALSE on failure
2170c2c66affSColin Finck  *
2171c2c66affSColin Finck  */
FTP_FtpRenameFileW(ftp_session_t * lpwfs,LPCWSTR lpszSrc,LPCWSTR lpszDest)2172c2c66affSColin Finck BOOL FTP_FtpRenameFileW(ftp_session_t *lpwfs, LPCWSTR lpszSrc, LPCWSTR lpszDest)
2173c2c66affSColin Finck {
2174c2c66affSColin Finck     INT nResCode;
2175c2c66affSColin Finck     BOOL bSuccess = FALSE;
2176c2c66affSColin Finck     appinfo_t *hIC = NULL;
2177c2c66affSColin Finck 
2178c2c66affSColin Finck     TRACE("\n");
2179c2c66affSColin Finck 
2180c2c66affSColin Finck     /* Clear any error information */
2181c2c66affSColin Finck     INTERNET_SetLastError(0);
2182c2c66affSColin Finck 
2183c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
2184c2c66affSColin Finck         goto lend;
2185c2c66affSColin Finck 
2186c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2187c2c66affSColin Finck     if (nResCode == 350)
2188c2c66affSColin Finck     {
2189c2c66affSColin Finck         if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
2190c2c66affSColin Finck             goto lend;
2191c2c66affSColin Finck 
2192c2c66affSColin Finck         nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2193c2c66affSColin Finck     }
2194c2c66affSColin Finck 
2195c2c66affSColin Finck     if (nResCode == 250)
2196c2c66affSColin Finck         bSuccess = TRUE;
2197c2c66affSColin Finck     else
2198c2c66affSColin Finck         FTP_SetResponseError(nResCode);
2199c2c66affSColin Finck 
2200c2c66affSColin Finck lend:
2201c2c66affSColin Finck     hIC = lpwfs->lpAppInfo;
2202c2c66affSColin Finck     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2203c2c66affSColin Finck     {
2204c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
2205c2c66affSColin Finck 
2206c2c66affSColin Finck         iar.dwResult = (DWORD)bSuccess;
2207c2c66affSColin Finck         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2208c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2209c2c66affSColin Finck             &iar, sizeof(INTERNET_ASYNC_RESULT));
2210c2c66affSColin Finck     }
2211c2c66affSColin Finck 
2212c2c66affSColin Finck     return bSuccess;
2213c2c66affSColin Finck }
2214c2c66affSColin Finck 
2215c2c66affSColin Finck /***********************************************************************
2216c2c66affSColin Finck  *           FtpCommandA  (WININET.@)
2217c2c66affSColin Finck  */
FtpCommandA(HINTERNET hConnect,BOOL fExpectResponse,DWORD dwFlags,LPCSTR lpszCommand,DWORD_PTR dwContext,HINTERNET * phFtpCommand)2218c2c66affSColin Finck BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
2219c2c66affSColin Finck                          LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
2220c2c66affSColin Finck {
2221c2c66affSColin Finck     BOOL r;
2222c2c66affSColin Finck     WCHAR *cmdW;
2223c2c66affSColin Finck 
2224c2c66affSColin Finck     TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
2225c2c66affSColin Finck           debugstr_a(lpszCommand), dwContext, phFtpCommand);
2226c2c66affSColin Finck 
2227c2c66affSColin Finck     if (fExpectResponse)
2228c2c66affSColin Finck     {
2229c2c66affSColin Finck         FIXME("data connection not supported\n");
2230c2c66affSColin Finck         return FALSE;
2231c2c66affSColin Finck     }
2232c2c66affSColin Finck 
2233c2c66affSColin Finck     if (!lpszCommand || !lpszCommand[0])
2234c2c66affSColin Finck     {
2235c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2236c2c66affSColin Finck         return FALSE;
2237c2c66affSColin Finck     }
2238c2c66affSColin Finck 
2239c2c66affSColin Finck     if (!(cmdW = heap_strdupAtoW(lpszCommand)))
2240c2c66affSColin Finck     {
2241c2c66affSColin Finck         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2242c2c66affSColin Finck         return FALSE;
2243c2c66affSColin Finck     }
2244c2c66affSColin Finck 
2245c2c66affSColin Finck     r = FtpCommandW(hConnect, fExpectResponse, dwFlags, cmdW, dwContext, phFtpCommand);
2246c2c66affSColin Finck 
2247c2c66affSColin Finck     heap_free(cmdW);
2248c2c66affSColin Finck     return r;
2249c2c66affSColin Finck }
2250c2c66affSColin Finck 
2251c2c66affSColin Finck /***********************************************************************
2252c2c66affSColin Finck  *           FtpCommandW  (WININET.@)
2253c2c66affSColin Finck  */
FtpCommandW(HINTERNET hConnect,BOOL fExpectResponse,DWORD dwFlags,LPCWSTR lpszCommand,DWORD_PTR dwContext,HINTERNET * phFtpCommand)2254c2c66affSColin Finck BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
2255c2c66affSColin Finck                          LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
2256c2c66affSColin Finck {
2257c2c66affSColin Finck     BOOL r = FALSE;
2258c2c66affSColin Finck     ftp_session_t *lpwfs;
2259c2c66affSColin Finck     LPSTR cmd = NULL;
2260c2c66affSColin Finck     DWORD len, nBytesSent= 0;
2261c2c66affSColin Finck     INT nResCode, nRC = 0;
2262c2c66affSColin Finck 
2263c2c66affSColin Finck     TRACE("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
2264c2c66affSColin Finck            debugstr_w(lpszCommand), dwContext, phFtpCommand);
2265c2c66affSColin Finck 
2266c2c66affSColin Finck     if (!lpszCommand || !lpszCommand[0])
2267c2c66affSColin Finck     {
2268c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2269c2c66affSColin Finck         return FALSE;
2270c2c66affSColin Finck     }
2271c2c66affSColin Finck 
2272c2c66affSColin Finck     if (fExpectResponse)
2273c2c66affSColin Finck     {
2274c2c66affSColin Finck         FIXME("data connection not supported\n");
2275c2c66affSColin Finck         return FALSE;
2276c2c66affSColin Finck     }
2277c2c66affSColin Finck 
2278c2c66affSColin Finck     lpwfs = (ftp_session_t*) get_handle_object( hConnect );
2279c2c66affSColin Finck     if (!lpwfs)
2280c2c66affSColin Finck     {
2281c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INVALID_HANDLE);
2282c2c66affSColin Finck         return FALSE;
2283c2c66affSColin Finck     }
2284c2c66affSColin Finck 
2285c2c66affSColin Finck     if (WH_HFTPSESSION != lpwfs->hdr.htype)
2286c2c66affSColin Finck     {
2287c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
2288c2c66affSColin Finck         goto lend;
2289c2c66affSColin Finck     }
2290c2c66affSColin Finck 
2291c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
2292c2c66affSColin Finck     {
2293c2c66affSColin Finck         INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2294c2c66affSColin Finck         goto lend;
2295c2c66affSColin Finck     }
2296c2c66affSColin Finck 
2297c2c66affSColin Finck     len = WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, NULL, 0, NULL, NULL) + strlen(szCRLF);
2298c2c66affSColin Finck     if ((cmd = heap_alloc(len)))
2299c2c66affSColin Finck         WideCharToMultiByte(CP_ACP, 0, lpszCommand, -1, cmd, len, NULL, NULL);
2300c2c66affSColin Finck     else
2301c2c66affSColin Finck     {
2302c2c66affSColin Finck         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2303c2c66affSColin Finck         goto lend;
2304c2c66affSColin Finck     }
2305c2c66affSColin Finck 
2306c2c66affSColin Finck     strcat(cmd, szCRLF);
2307c2c66affSColin Finck     len--;
2308c2c66affSColin Finck 
2309c2c66affSColin Finck     TRACE("Sending (%s) len(%d)\n", debugstr_a(cmd), len);
2310c2c66affSColin Finck     while ((nBytesSent < len) && (nRC != -1))
2311c2c66affSColin Finck     {
2312c2c66affSColin Finck         nRC = sock_send(lpwfs->sndSocket, cmd + nBytesSent, len - nBytesSent, 0);
2313c2c66affSColin Finck         if (nRC != -1)
2314c2c66affSColin Finck         {
2315c2c66affSColin Finck             nBytesSent += nRC;
2316c2c66affSColin Finck             TRACE("Sent %d bytes\n", nRC);
2317c2c66affSColin Finck         }
2318c2c66affSColin Finck     }
2319c2c66affSColin Finck 
2320c2c66affSColin Finck     if (nBytesSent)
2321c2c66affSColin Finck     {
2322c2c66affSColin Finck         nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2323c2c66affSColin Finck         if (nResCode > 0 && nResCode < 400)
2324c2c66affSColin Finck             r = TRUE;
2325c2c66affSColin Finck         else
2326c2c66affSColin Finck             FTP_SetResponseError(nResCode);
2327c2c66affSColin Finck     }
2328c2c66affSColin Finck 
2329c2c66affSColin Finck lend:
2330c2c66affSColin Finck     WININET_Release( &lpwfs->hdr );
2331c2c66affSColin Finck     heap_free( cmd );
2332c2c66affSColin Finck     return r;
2333c2c66affSColin Finck }
2334c2c66affSColin Finck 
2335c2c66affSColin Finck 
2336c2c66affSColin Finck /***********************************************************************
2337c2c66affSColin Finck  *           FTPSESSION_Destroy (internal)
2338c2c66affSColin Finck  *
2339c2c66affSColin Finck  * Deallocate session handle
2340c2c66affSColin Finck  */
FTPSESSION_Destroy(object_header_t * hdr)2341c2c66affSColin Finck static void FTPSESSION_Destroy(object_header_t *hdr)
2342c2c66affSColin Finck {
2343c2c66affSColin Finck     ftp_session_t *lpwfs = (ftp_session_t*) hdr;
2344c2c66affSColin Finck 
2345c2c66affSColin Finck     TRACE("\n");
2346c2c66affSColin Finck 
2347c2c66affSColin Finck     WININET_Release(&lpwfs->lpAppInfo->hdr);
2348c2c66affSColin Finck 
2349c2c66affSColin Finck     heap_free(lpwfs->lpszPassword);
2350c2c66affSColin Finck     heap_free(lpwfs->lpszUserName);
2351c2c66affSColin Finck     heap_free(lpwfs->servername);
2352c2c66affSColin Finck }
2353c2c66affSColin Finck 
FTPSESSION_CloseConnection(object_header_t * hdr)2354c2c66affSColin Finck static void FTPSESSION_CloseConnection(object_header_t *hdr)
2355c2c66affSColin Finck {
2356c2c66affSColin Finck     ftp_session_t *lpwfs = (ftp_session_t*) hdr;
2357c2c66affSColin Finck 
2358c2c66affSColin Finck     TRACE("\n");
2359c2c66affSColin Finck 
2360c2c66affSColin Finck     INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2361c2c66affSColin Finck                       INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2362c2c66affSColin Finck 
2363c2c66affSColin Finck     if (lpwfs->download_in_progress != NULL)
2364c2c66affSColin Finck         lpwfs->download_in_progress->session_deleted = TRUE;
2365c2c66affSColin Finck 
2366c2c66affSColin Finck     if (lpwfs->sndSocket != -1)
2367c2c66affSColin Finck         closesocket(lpwfs->sndSocket);
2368c2c66affSColin Finck 
2369c2c66affSColin Finck     if (lpwfs->lstnSocket != -1)
2370c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
2371c2c66affSColin Finck 
2372c2c66affSColin Finck     if (lpwfs->pasvSocket != -1)
2373c2c66affSColin Finck         closesocket(lpwfs->pasvSocket);
2374c2c66affSColin Finck 
2375c2c66affSColin Finck     INTERNET_SendCallback(&lpwfs->hdr, lpwfs->hdr.dwContext,
2376c2c66affSColin Finck                       INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2377c2c66affSColin Finck }
2378c2c66affSColin Finck 
FTPSESSION_QueryOption(object_header_t * hdr,DWORD option,void * buffer,DWORD * size,BOOL unicode)2379c2c66affSColin Finck static DWORD FTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
2380c2c66affSColin Finck {
2381c2c66affSColin Finck     switch(option) {
2382c2c66affSColin Finck     case INTERNET_OPTION_HANDLE_TYPE:
2383c2c66affSColin Finck         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
2384c2c66affSColin Finck 
2385c2c66affSColin Finck         if (*size < sizeof(ULONG))
2386c2c66affSColin Finck             return ERROR_INSUFFICIENT_BUFFER;
2387c2c66affSColin Finck 
2388c2c66affSColin Finck         *size = sizeof(DWORD);
2389c2c66affSColin Finck         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_FTP;
2390c2c66affSColin Finck         return ERROR_SUCCESS;
2391c2c66affSColin Finck     }
2392c2c66affSColin Finck 
2393c2c66affSColin Finck     return INET_QueryOption(hdr, option, buffer, size, unicode);
2394c2c66affSColin Finck }
2395c2c66affSColin Finck 
2396c2c66affSColin Finck static const object_vtbl_t FTPSESSIONVtbl = {
2397c2c66affSColin Finck     FTPSESSION_Destroy,
2398c2c66affSColin Finck     FTPSESSION_CloseConnection,
2399c2c66affSColin Finck     FTPSESSION_QueryOption,
2400c2c66affSColin Finck     INET_SetOption,
2401c2c66affSColin Finck     NULL,
2402c2c66affSColin Finck     NULL,
2403c2c66affSColin Finck     NULL,
2404c2c66affSColin Finck     NULL
2405c2c66affSColin Finck };
2406c2c66affSColin Finck 
2407c2c66affSColin Finck 
2408c2c66affSColin Finck /***********************************************************************
2409c2c66affSColin Finck  *           FTP_Connect (internal)
2410c2c66affSColin Finck  *
2411c2c66affSColin Finck  * Connect to a ftp server
2412c2c66affSColin Finck  *
2413c2c66affSColin Finck  * RETURNS
2414c2c66affSColin Finck  *   HINTERNET a session handle on success
2415c2c66affSColin Finck  *   NULL on failure
2416c2c66affSColin Finck  *
2417c2c66affSColin Finck  * NOTES:
2418c2c66affSColin Finck  *
2419c2c66affSColin Finck  * Windows uses 'anonymous' as the username, when given a NULL username
2420c2c66affSColin Finck  * and a NULL password. The password is first looked up in:
2421c2c66affSColin Finck  *
2422c2c66affSColin Finck  * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
2423c2c66affSColin Finck  *
2424c2c66affSColin Finck  * If this entry is not present it uses the current username as the password.
2425c2c66affSColin Finck  *
2426c2c66affSColin Finck  */
2427c2c66affSColin Finck 
FTP_Connect(appinfo_t * hIC,LPCWSTR lpszServerName,INTERNET_PORT nServerPort,LPCWSTR lpszUserName,LPCWSTR lpszPassword,DWORD dwFlags,DWORD_PTR dwContext,DWORD dwInternalFlags)2428c2c66affSColin Finck HINTERNET FTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
2429c2c66affSColin Finck 	INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
2430c2c66affSColin Finck 	LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
2431c2c66affSColin Finck 	DWORD dwInternalFlags)
2432c2c66affSColin Finck {
2433c2c66affSColin Finck     struct sockaddr_in socketAddr;
2434c2c66affSColin Finck     INT nsocket = -1;
2435c2c66affSColin Finck     socklen_t sock_namelen;
2436c2c66affSColin Finck     BOOL bSuccess = FALSE;
2437c2c66affSColin Finck     ftp_session_t *lpwfs = NULL;
2438c2c66affSColin Finck     char szaddr[INET6_ADDRSTRLEN];
2439c2c66affSColin Finck 
2440c2c66affSColin Finck     TRACE("%p  Server(%s) Port(%d) User(%s) Paswd(%s)\n",
2441c2c66affSColin Finck 	    hIC, debugstr_w(lpszServerName),
2442c2c66affSColin Finck 	    nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
2443c2c66affSColin Finck 
2444c2c66affSColin Finck     assert( hIC->hdr.htype == WH_HINIT );
2445c2c66affSColin Finck 
2446c2c66affSColin Finck     if ((!lpszUserName || !*lpszUserName) && lpszPassword && *lpszPassword)
2447c2c66affSColin Finck     {
2448c2c66affSColin Finck 	INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
2449c2c66affSColin Finck         return NULL;
2450c2c66affSColin Finck     }
2451c2c66affSColin Finck 
2452c2c66affSColin Finck     lpwfs = alloc_object(&hIC->hdr, &FTPSESSIONVtbl, sizeof(ftp_session_t));
2453c2c66affSColin Finck     if (NULL == lpwfs)
2454c2c66affSColin Finck     {
2455c2c66affSColin Finck         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2456c2c66affSColin Finck         return NULL;
2457c2c66affSColin Finck     }
2458c2c66affSColin Finck 
2459c2c66affSColin Finck     if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
2460c2c66affSColin Finck         lpwfs->serverport = INTERNET_DEFAULT_FTP_PORT;
2461c2c66affSColin Finck     else
2462c2c66affSColin Finck         lpwfs->serverport = nServerPort;
2463c2c66affSColin Finck 
2464c2c66affSColin Finck     lpwfs->hdr.htype = WH_HFTPSESSION;
2465c2c66affSColin Finck     lpwfs->hdr.dwFlags = dwFlags;
2466c2c66affSColin Finck     lpwfs->hdr.dwContext = dwContext;
2467c2c66affSColin Finck     lpwfs->hdr.dwInternalFlags |= dwInternalFlags;
2468c2c66affSColin Finck     lpwfs->download_in_progress = NULL;
2469c2c66affSColin Finck     lpwfs->sndSocket = -1;
2470c2c66affSColin Finck     lpwfs->lstnSocket = -1;
2471c2c66affSColin Finck     lpwfs->pasvSocket = -1;
2472c2c66affSColin Finck 
2473c2c66affSColin Finck     WININET_AddRef( &hIC->hdr );
2474c2c66affSColin Finck     lpwfs->lpAppInfo = hIC;
2475c2c66affSColin Finck     list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry );
2476c2c66affSColin Finck 
2477c2c66affSColin Finck     if(hIC->proxy && hIC->accessType == INTERNET_OPEN_TYPE_PROXY) {
24785f12c8d7Swinesync         if(wcschr(hIC->proxy, ' '))
2479c2c66affSColin Finck             FIXME("Several proxies not implemented.\n");
2480c2c66affSColin Finck         if(hIC->proxyBypass)
2481c2c66affSColin Finck             FIXME("Proxy bypass is ignored.\n");
2482c2c66affSColin Finck     }
2483c2c66affSColin Finck     if (!lpszUserName || !lpszUserName[0]) {
2484c2c66affSColin Finck         HKEY key;
2485c2c66affSColin Finck         WCHAR szPassword[MAX_PATH];
2486c2c66affSColin Finck         DWORD len = sizeof(szPassword);
2487c2c66affSColin Finck 
2488*e152f78aSwinesync         lpwfs->lpszUserName = heap_strdupW(L"anonymous");
2489c2c66affSColin Finck 
2490*e152f78aSwinesync         RegOpenKeyW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", &key);
2491*e152f78aSwinesync         if (RegQueryValueExW(key, L"EmailName", NULL, NULL, (LPBYTE)szPassword, &len)) {
2492c2c66affSColin Finck             /* Nothing in the registry, get the username and use that as the password */
2493c2c66affSColin Finck             if (!GetUserNameW(szPassword, &len)) {
2494c2c66affSColin Finck                 /* Should never get here, but use an empty password as failsafe */
2495*e152f78aSwinesync                 lstrcpyW(szPassword, L"");
2496c2c66affSColin Finck             }
2497c2c66affSColin Finck         }
2498c2c66affSColin Finck         RegCloseKey(key);
2499c2c66affSColin Finck 
2500c2c66affSColin Finck         TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
2501c2c66affSColin Finck         lpwfs->lpszPassword = heap_strdupW(szPassword);
2502c2c66affSColin Finck     }
2503c2c66affSColin Finck     else {
2504c2c66affSColin Finck         lpwfs->lpszUserName = heap_strdupW(lpszUserName);
2505*e152f78aSwinesync         lpwfs->lpszPassword = heap_strdupW(lpszPassword ? lpszPassword : L"");
2506c2c66affSColin Finck     }
2507c2c66affSColin Finck     lpwfs->servername = heap_strdupW(lpszServerName);
2508c2c66affSColin Finck 
2509c2c66affSColin Finck     /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
2510c2c66affSColin Finck     if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
2511c2c66affSColin Finck     {
2512c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
2513c2c66affSColin Finck 
2514c2c66affSColin Finck         iar.dwResult = (DWORD_PTR)lpwfs->hdr.hInternet;
2515c2c66affSColin Finck         iar.dwError = ERROR_SUCCESS;
2516c2c66affSColin Finck 
2517c2c66affSColin Finck         INTERNET_SendCallback(&hIC->hdr, dwContext,
2518c2c66affSColin Finck                       INTERNET_STATUS_HANDLE_CREATED, &iar,
2519c2c66affSColin Finck                       sizeof(INTERNET_ASYNC_RESULT));
2520c2c66affSColin Finck     }
2521c2c66affSColin Finck 
2522c2c66affSColin Finck     INTERNET_SendCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
25235f12c8d7Swinesync         (LPWSTR) lpszServerName, (lstrlenW(lpszServerName)+1) * sizeof(WCHAR));
2524c2c66affSColin Finck 
2525c2c66affSColin Finck     sock_namelen = sizeof(socketAddr);
2526c2c66affSColin Finck     if (!GetAddress(lpszServerName, lpwfs->serverport, (struct sockaddr *)&socketAddr, &sock_namelen, szaddr))
2527c2c66affSColin Finck     {
2528c2c66affSColin Finck 	INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
2529c2c66affSColin Finck         goto lerror;
2530c2c66affSColin Finck     }
2531c2c66affSColin Finck 
2532c2c66affSColin Finck     if (socketAddr.sin_family != AF_INET)
2533c2c66affSColin Finck     {
2534c2c66affSColin Finck         WARN("unsupported address family %d\n", socketAddr.sin_family);
2535c2c66affSColin Finck         INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2536c2c66affSColin Finck         goto lerror;
2537c2c66affSColin Finck     }
2538c2c66affSColin Finck 
2539c2c66affSColin Finck     INTERNET_SendCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
2540c2c66affSColin Finck                       szaddr, strlen(szaddr)+1);
2541c2c66affSColin Finck 
2542c2c66affSColin Finck     init_winsock();
2543c2c66affSColin Finck     nsocket = socket(AF_INET,SOCK_STREAM,0);
2544c2c66affSColin Finck     if (nsocket == -1)
2545c2c66affSColin Finck     {
2546c2c66affSColin Finck 	INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2547c2c66affSColin Finck         goto lerror;
2548c2c66affSColin Finck     }
2549c2c66affSColin Finck 
2550c2c66affSColin Finck     INTERNET_SendCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
2551c2c66affSColin Finck                       szaddr, strlen(szaddr)+1);
2552c2c66affSColin Finck 
2553c2c66affSColin Finck     if (connect(nsocket, (struct sockaddr *)&socketAddr, sock_namelen) < 0)
2554c2c66affSColin Finck     {
2555c2c66affSColin Finck 	ERR("Unable to connect (%d)\n", WSAGetLastError());
2556c2c66affSColin Finck 	INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
2557c2c66affSColin Finck 	closesocket(nsocket);
2558c2c66affSColin Finck     }
2559c2c66affSColin Finck     else
2560c2c66affSColin Finck     {
2561c2c66affSColin Finck         TRACE("Connected to server\n");
2562c2c66affSColin Finck 	lpwfs->sndSocket = nsocket;
2563c2c66affSColin Finck         INTERNET_SendCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
2564c2c66affSColin Finck                           szaddr, strlen(szaddr)+1);
2565c2c66affSColin Finck 
2566c2c66affSColin Finck 	sock_namelen = sizeof(lpwfs->socketAddress);
2567c2c66affSColin Finck 	getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2568c2c66affSColin Finck 
2569c2c66affSColin Finck         if (FTP_ConnectToHost(lpwfs))
2570c2c66affSColin Finck         {
2571c2c66affSColin Finck             TRACE("Successfully logged into server\n");
2572c2c66affSColin Finck             bSuccess = TRUE;
2573c2c66affSColin Finck         }
2574c2c66affSColin Finck     }
2575c2c66affSColin Finck 
2576c2c66affSColin Finck lerror:
2577c2c66affSColin Finck     if (!bSuccess)
2578c2c66affSColin Finck     {
2579c2c66affSColin Finck         WININET_Release(&lpwfs->hdr);
2580c2c66affSColin Finck         return NULL;
2581c2c66affSColin Finck     }
2582c2c66affSColin Finck 
2583c2c66affSColin Finck     return lpwfs->hdr.hInternet;
2584c2c66affSColin Finck }
2585c2c66affSColin Finck 
2586c2c66affSColin Finck 
2587c2c66affSColin Finck /***********************************************************************
2588c2c66affSColin Finck  *           FTP_ConnectToHost (internal)
2589c2c66affSColin Finck  *
2590c2c66affSColin Finck  * Connect to a ftp server
2591c2c66affSColin Finck  *
2592c2c66affSColin Finck  * RETURNS
2593c2c66affSColin Finck  *   TRUE on success
2594c2c66affSColin Finck  *   NULL on failure
2595c2c66affSColin Finck  *
2596c2c66affSColin Finck  */
FTP_ConnectToHost(ftp_session_t * lpwfs)2597c2c66affSColin Finck static BOOL FTP_ConnectToHost(ftp_session_t *lpwfs)
2598c2c66affSColin Finck {
2599c2c66affSColin Finck     INT nResCode;
2600c2c66affSColin Finck     BOOL bSuccess = FALSE;
2601c2c66affSColin Finck 
2602c2c66affSColin Finck     TRACE("\n");
2603c2c66affSColin Finck     FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2604c2c66affSColin Finck 
2605c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2606c2c66affSColin Finck         goto lend;
2607c2c66affSColin Finck 
2608c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2609c2c66affSColin Finck     if (nResCode)
2610c2c66affSColin Finck     {
2611c2c66affSColin Finck         /* Login successful... */
2612c2c66affSColin Finck         if (nResCode == 230)
2613c2c66affSColin Finck             bSuccess = TRUE;
2614c2c66affSColin Finck         /* User name okay, need password... */
2615c2c66affSColin Finck         else if (nResCode == 331)
2616c2c66affSColin Finck             bSuccess = FTP_SendPassword(lpwfs);
2617c2c66affSColin Finck         /* Need account for login... */
2618c2c66affSColin Finck         else if (nResCode == 332)
2619c2c66affSColin Finck             bSuccess = FTP_SendAccount(lpwfs);
2620c2c66affSColin Finck         else
2621c2c66affSColin Finck             FTP_SetResponseError(nResCode);
2622c2c66affSColin Finck     }
2623c2c66affSColin Finck 
2624c2c66affSColin Finck     TRACE("Returning %d\n", bSuccess);
2625c2c66affSColin Finck lend:
2626c2c66affSColin Finck     return bSuccess;
2627c2c66affSColin Finck }
2628c2c66affSColin Finck 
2629c2c66affSColin Finck /***********************************************************************
2630c2c66affSColin Finck  *           FTP_GetNextLine  (internal)
2631c2c66affSColin Finck  *
2632c2c66affSColin Finck  * Parse next line in directory string listing
2633c2c66affSColin Finck  *
2634c2c66affSColin Finck  * RETURNS
2635c2c66affSColin Finck  *   Pointer to beginning of next line
2636c2c66affSColin Finck  *   NULL on failure
2637c2c66affSColin Finck  *
2638c2c66affSColin Finck  */
2639c2c66affSColin Finck 
FTP_GetNextLine(INT nSocket,LPDWORD dwLen)2640c2c66affSColin Finck static LPSTR FTP_GetNextLine(INT nSocket, LPDWORD dwLen)
2641c2c66affSColin Finck {
2642c2c66affSColin Finck     struct timeval tv = {RESPONSE_TIMEOUT,0};
2643c2c66affSColin Finck     FD_SET set;
2644c2c66affSColin Finck     INT nRecv = 0;
2645c2c66affSColin Finck     LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
2646c2c66affSColin Finck 
2647c2c66affSColin Finck     TRACE("\n");
2648c2c66affSColin Finck 
2649c2c66affSColin Finck     FD_ZERO(&set);
2650c2c66affSColin Finck     FD_SET(nSocket, &set);
2651c2c66affSColin Finck 
2652c2c66affSColin Finck     while (nRecv < MAX_REPLY_LEN)
2653c2c66affSColin Finck     {
2654c2c66affSColin Finck         if (select(nSocket+1, &set, NULL, NULL, &tv) > 0)
2655c2c66affSColin Finck         {
2656c2c66affSColin Finck             if (sock_recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
2657c2c66affSColin Finck             {
2658c2c66affSColin Finck                 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
2659c2c66affSColin Finck                 return NULL;
2660c2c66affSColin Finck             }
2661c2c66affSColin Finck 
2662c2c66affSColin Finck             if (lpszBuffer[nRecv] == '\n')
2663c2c66affSColin Finck             {
2664c2c66affSColin Finck                 lpszBuffer[nRecv] = '\0';
2665c2c66affSColin Finck                 *dwLen = nRecv - 1;
2666c2c66affSColin Finck                 TRACE(":%d %s\n", nRecv, lpszBuffer);
2667c2c66affSColin Finck                 return lpszBuffer;
2668c2c66affSColin Finck             }
2669c2c66affSColin Finck             if (lpszBuffer[nRecv] != '\r')
2670c2c66affSColin Finck                 nRecv++;
2671c2c66affSColin Finck         }
2672c2c66affSColin Finck 	else
2673c2c66affSColin Finck 	{
2674c2c66affSColin Finck             INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
2675c2c66affSColin Finck             return NULL;
2676c2c66affSColin Finck         }
2677c2c66affSColin Finck     }
2678c2c66affSColin Finck 
2679c2c66affSColin Finck     return NULL;
2680c2c66affSColin Finck }
2681c2c66affSColin Finck 
2682c2c66affSColin Finck /***********************************************************************
2683c2c66affSColin Finck  *           FTP_SendCommandA (internal)
2684c2c66affSColin Finck  *
2685c2c66affSColin Finck  * Send command to server
2686c2c66affSColin Finck  *
2687c2c66affSColin Finck  * RETURNS
2688c2c66affSColin Finck  *   TRUE on success
2689c2c66affSColin Finck  *   NULL on failure
2690c2c66affSColin Finck  *
2691c2c66affSColin Finck  */
FTP_SendCommandA(INT nSocket,FTP_COMMAND ftpCmd,LPCSTR lpszParam,INTERNET_STATUS_CALLBACK lpfnStatusCB,object_header_t * hdr,DWORD_PTR dwContext)2692c2c66affSColin Finck static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2693c2c66affSColin Finck 	INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext)
2694c2c66affSColin Finck {
2695c2c66affSColin Finck     	DWORD len;
2696c2c66affSColin Finck 	CHAR *buf;
2697c2c66affSColin Finck 	DWORD nBytesSent = 0;
2698c2c66affSColin Finck 	int nRC = 0;
2699c2c66affSColin Finck 	DWORD dwParamLen;
2700c2c66affSColin Finck 
2701c2c66affSColin Finck 	TRACE("%d: (%s) %d\n", ftpCmd, debugstr_a(lpszParam), nSocket);
2702c2c66affSColin Finck 
2703c2c66affSColin Finck 	if (lpfnStatusCB)
2704c2c66affSColin Finck         {
2705c2c66affSColin Finck             lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2706c2c66affSColin Finck         }
2707c2c66affSColin Finck 
2708c2c66affSColin Finck 	dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2709c2c66affSColin Finck 	len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2710c2c66affSColin Finck 	if (NULL == (buf = heap_alloc(len+1)))
2711c2c66affSColin Finck 	{
2712c2c66affSColin Finck 	    INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2713c2c66affSColin Finck 	    return FALSE;
2714c2c66affSColin Finck 	}
2715c2c66affSColin Finck 	sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2716c2c66affSColin Finck 		dwParamLen ? lpszParam : "", szCRLF);
2717c2c66affSColin Finck 
2718c2c66affSColin Finck 	TRACE("Sending (%s) len(%d)\n", debugstr_a(buf), len);
2719c2c66affSColin Finck 	while((nBytesSent < len) && (nRC != -1))
2720c2c66affSColin Finck 	{
2721c2c66affSColin Finck 		nRC = sock_send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2722c2c66affSColin Finck 		nBytesSent += nRC;
2723c2c66affSColin Finck 	}
2724c2c66affSColin Finck     heap_free(buf);
2725c2c66affSColin Finck 
2726c2c66affSColin Finck 	if (lpfnStatusCB)
2727c2c66affSColin Finck         {
2728c2c66affSColin Finck             lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2729c2c66affSColin Finck                          &nBytesSent, sizeof(DWORD));
2730c2c66affSColin Finck         }
2731c2c66affSColin Finck 
2732c2c66affSColin Finck 	TRACE("Sent %d bytes\n", nBytesSent);
2733c2c66affSColin Finck 	return (nRC != -1);
2734c2c66affSColin Finck }
2735c2c66affSColin Finck 
2736c2c66affSColin Finck /***********************************************************************
2737c2c66affSColin Finck  *           FTP_SendCommand (internal)
2738c2c66affSColin Finck  *
2739c2c66affSColin Finck  * Send command to server
2740c2c66affSColin Finck  *
2741c2c66affSColin Finck  * RETURNS
2742c2c66affSColin Finck  *   TRUE on success
2743c2c66affSColin Finck  *   NULL on failure
2744c2c66affSColin Finck  *
2745c2c66affSColin Finck  */
FTP_SendCommand(INT nSocket,FTP_COMMAND ftpCmd,LPCWSTR lpszParam,INTERNET_STATUS_CALLBACK lpfnStatusCB,object_header_t * hdr,DWORD_PTR dwContext)2746c2c66affSColin Finck static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2747c2c66affSColin Finck 	INTERNET_STATUS_CALLBACK lpfnStatusCB, object_header_t *hdr, DWORD_PTR dwContext)
2748c2c66affSColin Finck {
2749c2c66affSColin Finck     BOOL ret;
2750c2c66affSColin Finck     LPSTR lpszParamA = heap_strdupWtoA(lpszParam);
2751c2c66affSColin Finck     ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2752c2c66affSColin Finck     heap_free(lpszParamA);
2753c2c66affSColin Finck     return ret;
2754c2c66affSColin Finck }
2755c2c66affSColin Finck 
2756c2c66affSColin Finck /***********************************************************************
2757c2c66affSColin Finck  *           FTP_ReceiveResponse (internal)
2758c2c66affSColin Finck  *
2759c2c66affSColin Finck  * Receive response from server
2760c2c66affSColin Finck  *
2761c2c66affSColin Finck  * RETURNS
2762c2c66affSColin Finck  *   Reply code on success
2763c2c66affSColin Finck  *   0 on failure
2764c2c66affSColin Finck  *
2765c2c66affSColin Finck  */
FTP_ReceiveResponse(ftp_session_t * lpwfs,DWORD_PTR dwContext)2766c2c66affSColin Finck INT FTP_ReceiveResponse(ftp_session_t *lpwfs, DWORD_PTR dwContext)
2767c2c66affSColin Finck {
2768c2c66affSColin Finck     LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2769c2c66affSColin Finck     DWORD nRecv;
2770c2c66affSColin Finck     INT rc = 0;
2771c2c66affSColin Finck     char firstprefix[5];
2772c2c66affSColin Finck     BOOL multiline = FALSE;
2773c2c66affSColin Finck 
2774c2c66affSColin Finck     TRACE("socket(%d)\n", lpwfs->sndSocket);
2775c2c66affSColin Finck 
2776c2c66affSColin Finck     INTERNET_SendCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2777c2c66affSColin Finck 
2778c2c66affSColin Finck     while(1)
2779c2c66affSColin Finck     {
2780c2c66affSColin Finck 	if (!FTP_GetNextLine(lpwfs->sndSocket, &nRecv))
2781c2c66affSColin Finck 	    goto lerror;
2782c2c66affSColin Finck 
2783c2c66affSColin Finck         if (nRecv >= 3)
2784c2c66affSColin Finck 	{
2785c2c66affSColin Finck 	    if(!multiline)
2786c2c66affSColin Finck 	    {
2787c2c66affSColin Finck 	        if(lpszResponse[3] != '-')
2788c2c66affSColin Finck 		    break;
2789c2c66affSColin Finck 		else
2790c2c66affSColin Finck 		{  /* Start of multiline response.  Loop until we get "nnn " */
2791c2c66affSColin Finck 		    multiline = TRUE;
2792c2c66affSColin Finck 		    memcpy(firstprefix, lpszResponse, 3);
2793c2c66affSColin Finck 		    firstprefix[3] = ' ';
2794c2c66affSColin Finck 		    firstprefix[4] = '\0';
2795c2c66affSColin Finck 		}
2796c2c66affSColin Finck 	    }
2797c2c66affSColin Finck 	    else
2798c2c66affSColin Finck 	    {
2799c2c66affSColin Finck 	        if(!memcmp(firstprefix, lpszResponse, 4))
2800c2c66affSColin Finck 		    break;
2801c2c66affSColin Finck 	    }
2802c2c66affSColin Finck 	}
2803c2c66affSColin Finck     }
2804c2c66affSColin Finck 
2805c2c66affSColin Finck     if (nRecv >= 3)
2806c2c66affSColin Finck     {
2807c2c66affSColin Finck         rc = atoi(lpszResponse);
2808c2c66affSColin Finck 
2809c2c66affSColin Finck         INTERNET_SendCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2810c2c66affSColin Finck 		    &nRecv, sizeof(DWORD));
2811c2c66affSColin Finck     }
2812c2c66affSColin Finck 
2813c2c66affSColin Finck lerror:
2814c2c66affSColin Finck     TRACE("return %d\n", rc);
2815c2c66affSColin Finck     return rc;
2816c2c66affSColin Finck }
2817c2c66affSColin Finck 
2818c2c66affSColin Finck 
2819c2c66affSColin Finck /***********************************************************************
2820c2c66affSColin Finck  *           FTP_SendPassword (internal)
2821c2c66affSColin Finck  *
2822c2c66affSColin Finck  * Send password to ftp server
2823c2c66affSColin Finck  *
2824c2c66affSColin Finck  * RETURNS
2825c2c66affSColin Finck  *   TRUE on success
2826c2c66affSColin Finck  *   NULL on failure
2827c2c66affSColin Finck  *
2828c2c66affSColin Finck  */
FTP_SendPassword(ftp_session_t * lpwfs)2829c2c66affSColin Finck static BOOL FTP_SendPassword(ftp_session_t *lpwfs)
2830c2c66affSColin Finck {
2831c2c66affSColin Finck     INT nResCode;
2832c2c66affSColin Finck     BOOL bSuccess = FALSE;
2833c2c66affSColin Finck 
2834c2c66affSColin Finck     TRACE("\n");
2835c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2836c2c66affSColin Finck         goto lend;
2837c2c66affSColin Finck 
2838c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2839c2c66affSColin Finck     if (nResCode)
2840c2c66affSColin Finck     {
2841c2c66affSColin Finck         TRACE("Received reply code %d\n", nResCode);
2842c2c66affSColin Finck         /* Login successful... */
2843c2c66affSColin Finck         if (nResCode == 230)
2844c2c66affSColin Finck             bSuccess = TRUE;
2845c2c66affSColin Finck         /* Command not implemented, superfluous at the server site... */
2846c2c66affSColin Finck         /* Need account for login... */
2847c2c66affSColin Finck         else if (nResCode == 332)
2848c2c66affSColin Finck             bSuccess = FTP_SendAccount(lpwfs);
2849c2c66affSColin Finck         else
2850c2c66affSColin Finck             FTP_SetResponseError(nResCode);
2851c2c66affSColin Finck     }
2852c2c66affSColin Finck 
2853c2c66affSColin Finck lend:
2854c2c66affSColin Finck     TRACE("Returning %d\n", bSuccess);
2855c2c66affSColin Finck     return bSuccess;
2856c2c66affSColin Finck }
2857c2c66affSColin Finck 
2858c2c66affSColin Finck 
2859c2c66affSColin Finck /***********************************************************************
2860c2c66affSColin Finck  *           FTP_SendAccount (internal)
2861c2c66affSColin Finck  *
2862c2c66affSColin Finck  *
2863c2c66affSColin Finck  *
2864c2c66affSColin Finck  * RETURNS
2865c2c66affSColin Finck  *   TRUE on success
2866c2c66affSColin Finck  *   FALSE on failure
2867c2c66affSColin Finck  *
2868c2c66affSColin Finck  */
FTP_SendAccount(ftp_session_t * lpwfs)2869c2c66affSColin Finck static BOOL FTP_SendAccount(ftp_session_t *lpwfs)
2870c2c66affSColin Finck {
2871c2c66affSColin Finck     INT nResCode;
2872c2c66affSColin Finck     BOOL bSuccess = FALSE;
2873c2c66affSColin Finck 
2874c2c66affSColin Finck     TRACE("\n");
2875*e152f78aSwinesync     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, L"noaccount", 0, 0, 0))
2876c2c66affSColin Finck         goto lend;
2877c2c66affSColin Finck 
2878c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2879c2c66affSColin Finck     if (nResCode)
2880c2c66affSColin Finck         bSuccess = TRUE;
2881c2c66affSColin Finck     else
2882c2c66affSColin Finck         FTP_SetResponseError(nResCode);
2883c2c66affSColin Finck 
2884c2c66affSColin Finck lend:
2885c2c66affSColin Finck     return bSuccess;
2886c2c66affSColin Finck }
2887c2c66affSColin Finck 
2888c2c66affSColin Finck 
2889c2c66affSColin Finck /***********************************************************************
2890c2c66affSColin Finck  *           FTP_SendStore (internal)
2891c2c66affSColin Finck  *
2892c2c66affSColin Finck  * Send request to upload file to ftp server
2893c2c66affSColin Finck  *
2894c2c66affSColin Finck  * RETURNS
2895c2c66affSColin Finck  *   TRUE on success
2896c2c66affSColin Finck  *   FALSE on failure
2897c2c66affSColin Finck  *
2898c2c66affSColin Finck  */
FTP_SendStore(ftp_session_t * lpwfs,LPCWSTR lpszRemoteFile,DWORD dwType)2899c2c66affSColin Finck static BOOL FTP_SendStore(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2900c2c66affSColin Finck {
2901c2c66affSColin Finck     INT nResCode;
2902c2c66affSColin Finck     BOOL bSuccess = FALSE;
2903c2c66affSColin Finck 
2904c2c66affSColin Finck     TRACE("\n");
2905c2c66affSColin Finck     if (!FTP_InitListenSocket(lpwfs))
2906c2c66affSColin Finck         goto lend;
2907c2c66affSColin Finck 
2908c2c66affSColin Finck     if (!FTP_SendType(lpwfs, dwType))
2909c2c66affSColin Finck         goto lend;
2910c2c66affSColin Finck 
2911c2c66affSColin Finck     if (!FTP_SendPortOrPasv(lpwfs))
2912c2c66affSColin Finck         goto lend;
2913c2c66affSColin Finck 
2914c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2915c2c66affSColin Finck 	    goto lend;
2916c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2917c2c66affSColin Finck     if (nResCode)
2918c2c66affSColin Finck     {
2919c2c66affSColin Finck         if (nResCode == 150 || nResCode == 125)
2920c2c66affSColin Finck             bSuccess = TRUE;
2921c2c66affSColin Finck 	else
2922c2c66affSColin Finck             FTP_SetResponseError(nResCode);
2923c2c66affSColin Finck     }
2924c2c66affSColin Finck 
2925c2c66affSColin Finck lend:
2926c2c66affSColin Finck     if (!bSuccess && lpwfs->lstnSocket != -1)
2927c2c66affSColin Finck     {
2928c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
2929c2c66affSColin Finck         lpwfs->lstnSocket = -1;
2930c2c66affSColin Finck     }
2931c2c66affSColin Finck 
2932c2c66affSColin Finck     return bSuccess;
2933c2c66affSColin Finck }
2934c2c66affSColin Finck 
2935c2c66affSColin Finck 
2936c2c66affSColin Finck /***********************************************************************
2937c2c66affSColin Finck  *           FTP_InitListenSocket (internal)
2938c2c66affSColin Finck  *
2939c2c66affSColin Finck  * Create a socket to listen for server response
2940c2c66affSColin Finck  *
2941c2c66affSColin Finck  * RETURNS
2942c2c66affSColin Finck  *   TRUE on success
2943c2c66affSColin Finck  *   FALSE on failure
2944c2c66affSColin Finck  *
2945c2c66affSColin Finck  */
FTP_InitListenSocket(ftp_session_t * lpwfs)2946c2c66affSColin Finck static BOOL FTP_InitListenSocket(ftp_session_t *lpwfs)
2947c2c66affSColin Finck {
2948c2c66affSColin Finck     BOOL bSuccess = FALSE;
2949c2c66affSColin Finck     socklen_t namelen = sizeof(lpwfs->lstnSocketAddress);
2950c2c66affSColin Finck 
2951c2c66affSColin Finck     TRACE("\n");
2952c2c66affSColin Finck 
2953c2c66affSColin Finck     init_winsock();
2954c2c66affSColin Finck     lpwfs->lstnSocket = socket(AF_INET, SOCK_STREAM, 0);
2955c2c66affSColin Finck     if (lpwfs->lstnSocket == -1)
2956c2c66affSColin Finck     {
2957c2c66affSColin Finck         TRACE("Unable to create listening socket\n");
2958c2c66affSColin Finck             goto lend;
2959c2c66affSColin Finck     }
2960c2c66affSColin Finck 
2961c2c66affSColin Finck     /* We obtain our ip addr from the name of the command channel socket */
2962c2c66affSColin Finck     lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2963c2c66affSColin Finck 
2964c2c66affSColin Finck     /* and get the system to assign us a port */
2965c2c66affSColin Finck     lpwfs->lstnSocketAddress.sin_port = htons(0);
2966c2c66affSColin Finck 
2967c2c66affSColin Finck     if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(lpwfs->lstnSocketAddress)) == -1)
2968c2c66affSColin Finck     {
2969c2c66affSColin Finck         TRACE("Unable to bind socket\n");
2970c2c66affSColin Finck         goto lend;
2971c2c66affSColin Finck     }
2972c2c66affSColin Finck 
2973c2c66affSColin Finck     if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2974c2c66affSColin Finck     {
2975c2c66affSColin Finck         TRACE("listen failed\n");
2976c2c66affSColin Finck         goto lend;
2977c2c66affSColin Finck     }
2978c2c66affSColin Finck 
2979c2c66affSColin Finck     if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2980c2c66affSColin Finck         bSuccess = TRUE;
2981c2c66affSColin Finck 
2982c2c66affSColin Finck lend:
2983c2c66affSColin Finck     if (!bSuccess && lpwfs->lstnSocket != -1)
2984c2c66affSColin Finck     {
2985c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
2986c2c66affSColin Finck         lpwfs->lstnSocket = -1;
2987c2c66affSColin Finck     }
2988c2c66affSColin Finck 
2989c2c66affSColin Finck     return bSuccess;
2990c2c66affSColin Finck }
2991c2c66affSColin Finck 
2992c2c66affSColin Finck 
2993c2c66affSColin Finck /***********************************************************************
2994c2c66affSColin Finck  *           FTP_SendType (internal)
2995c2c66affSColin Finck  *
2996c2c66affSColin Finck  * Tell server type of data being transferred
2997c2c66affSColin Finck  *
2998c2c66affSColin Finck  * RETURNS
2999c2c66affSColin Finck  *   TRUE on success
3000c2c66affSColin Finck  *   FALSE on failure
3001c2c66affSColin Finck  *
3002c2c66affSColin Finck  * W98SE doesn't cache the type that's currently set
3003c2c66affSColin Finck  * (i.e. it sends it always),
3004c2c66affSColin Finck  * so we probably don't want to do that either.
3005c2c66affSColin Finck  */
FTP_SendType(ftp_session_t * lpwfs,DWORD dwType)3006c2c66affSColin Finck static BOOL FTP_SendType(ftp_session_t *lpwfs, DWORD dwType)
3007c2c66affSColin Finck {
3008c2c66affSColin Finck     INT nResCode;
3009*e152f78aSwinesync     WCHAR type[] = L"I";
3010c2c66affSColin Finck     BOOL bSuccess = FALSE;
3011c2c66affSColin Finck 
3012c2c66affSColin Finck     TRACE("\n");
3013c2c66affSColin Finck     if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
3014c2c66affSColin Finck         type[0] = 'A';
3015c2c66affSColin Finck 
3016c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
3017c2c66affSColin Finck         goto lend;
3018c2c66affSColin Finck 
3019c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
3020c2c66affSColin Finck     if (nResCode)
3021c2c66affSColin Finck     {
3022c2c66affSColin Finck         if (nResCode == 2)
3023c2c66affSColin Finck             bSuccess = TRUE;
3024c2c66affSColin Finck 	else
3025c2c66affSColin Finck             FTP_SetResponseError(nResCode);
3026c2c66affSColin Finck     }
3027c2c66affSColin Finck 
3028c2c66affSColin Finck lend:
3029c2c66affSColin Finck     return bSuccess;
3030c2c66affSColin Finck }
3031c2c66affSColin Finck 
3032c2c66affSColin Finck 
3033c2c66affSColin Finck #if 0  /* FIXME: should probably be used for FtpGetFileSize */
3034c2c66affSColin Finck /***********************************************************************
3035c2c66affSColin Finck  *           FTP_GetFileSize (internal)
3036c2c66affSColin Finck  *
3037c2c66affSColin Finck  * Retrieves from the server the size of the given file
3038c2c66affSColin Finck  *
3039c2c66affSColin Finck  * RETURNS
3040c2c66affSColin Finck  *   TRUE on success
3041c2c66affSColin Finck  *   FALSE on failure
3042c2c66affSColin Finck  *
3043c2c66affSColin Finck  */
3044c2c66affSColin Finck static BOOL FTP_GetFileSize(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
3045c2c66affSColin Finck {
3046c2c66affSColin Finck     INT nResCode;
3047c2c66affSColin Finck     BOOL bSuccess = FALSE;
3048c2c66affSColin Finck 
3049c2c66affSColin Finck     TRACE("\n");
3050c2c66affSColin Finck 
3051c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
3052c2c66affSColin Finck         goto lend;
3053c2c66affSColin Finck 
3054c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3055c2c66affSColin Finck     if (nResCode)
3056c2c66affSColin Finck     {
3057c2c66affSColin Finck         if (nResCode == 213) {
3058c2c66affSColin Finck 	    /* Now parses the output to get the actual file size */
3059c2c66affSColin Finck 	    int i;
3060c2c66affSColin Finck 	    LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
3061c2c66affSColin Finck 
3062c2c66affSColin Finck 	    for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
3063c2c66affSColin Finck 	    if (lpszResponseBuffer[i] == '\0') return FALSE;
3064c2c66affSColin Finck 	    *dwSize = atol(&(lpszResponseBuffer[i + 1]));
3065c2c66affSColin Finck 
3066c2c66affSColin Finck             bSuccess = TRUE;
3067c2c66affSColin Finck 	} else {
3068c2c66affSColin Finck             FTP_SetResponseError(nResCode);
3069c2c66affSColin Finck 	}
3070c2c66affSColin Finck     }
3071c2c66affSColin Finck 
3072c2c66affSColin Finck lend:
3073c2c66affSColin Finck     return bSuccess;
3074c2c66affSColin Finck }
3075c2c66affSColin Finck #endif
3076c2c66affSColin Finck 
3077c2c66affSColin Finck 
3078c2c66affSColin Finck /***********************************************************************
3079c2c66affSColin Finck  *           FTP_SendPort (internal)
3080c2c66affSColin Finck  *
3081c2c66affSColin Finck  * Tell server which port to use
3082c2c66affSColin Finck  *
3083c2c66affSColin Finck  * RETURNS
3084c2c66affSColin Finck  *   TRUE on success
3085c2c66affSColin Finck  *   FALSE on failure
3086c2c66affSColin Finck  *
3087c2c66affSColin Finck  */
FTP_SendPort(ftp_session_t * lpwfs)3088c2c66affSColin Finck static BOOL FTP_SendPort(ftp_session_t *lpwfs)
3089c2c66affSColin Finck {
3090c2c66affSColin Finck     INT nResCode;
3091c2c66affSColin Finck     WCHAR szIPAddress[64];
3092c2c66affSColin Finck     BOOL bSuccess = FALSE;
3093c2c66affSColin Finck     TRACE("\n");
3094c2c66affSColin Finck 
3095*e152f78aSwinesync     swprintf(szIPAddress, ARRAY_SIZE(szIPAddress), L"%d,%d,%d,%d,%d,%d",
3096c2c66affSColin Finck 	 lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x000000FF,
3097c2c66affSColin Finck         (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x0000FF00)>>8,
3098c2c66affSColin Finck         (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0x00FF0000)>>16,
3099c2c66affSColin Finck         (lpwfs->lstnSocketAddress.sin_addr.S_un.S_addr&0xFF000000)>>24,
3100c2c66affSColin Finck         lpwfs->lstnSocketAddress.sin_port & 0xFF,
3101c2c66affSColin Finck         (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
3102c2c66affSColin Finck 
3103c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
3104c2c66affSColin Finck         goto lend;
3105c2c66affSColin Finck 
3106c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3107c2c66affSColin Finck     if (nResCode)
3108c2c66affSColin Finck     {
3109c2c66affSColin Finck         if (nResCode == 200)
3110c2c66affSColin Finck             bSuccess = TRUE;
3111c2c66affSColin Finck         else
3112c2c66affSColin Finck             FTP_SetResponseError(nResCode);
3113c2c66affSColin Finck     }
3114c2c66affSColin Finck 
3115c2c66affSColin Finck lend:
3116c2c66affSColin Finck     return bSuccess;
3117c2c66affSColin Finck }
3118c2c66affSColin Finck 
3119c2c66affSColin Finck 
3120c2c66affSColin Finck /***********************************************************************
3121c2c66affSColin Finck  *           FTP_DoPassive (internal)
3122c2c66affSColin Finck  *
3123c2c66affSColin Finck  * Tell server that we want to do passive transfers
3124c2c66affSColin Finck  * and connect data socket
3125c2c66affSColin Finck  *
3126c2c66affSColin Finck  * RETURNS
3127c2c66affSColin Finck  *   TRUE on success
3128c2c66affSColin Finck  *   FALSE on failure
3129c2c66affSColin Finck  *
3130c2c66affSColin Finck  */
FTP_DoPassive(ftp_session_t * lpwfs)3131c2c66affSColin Finck static BOOL FTP_DoPassive(ftp_session_t *lpwfs)
3132c2c66affSColin Finck {
3133c2c66affSColin Finck     INT nResCode;
3134c2c66affSColin Finck     BOOL bSuccess = FALSE;
3135c2c66affSColin Finck 
3136c2c66affSColin Finck     TRACE("\n");
3137c2c66affSColin Finck     if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
3138c2c66affSColin Finck         goto lend;
3139c2c66affSColin Finck 
3140c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3141c2c66affSColin Finck     if (nResCode)
3142c2c66affSColin Finck     {
3143c2c66affSColin Finck         if (nResCode == 227)
3144c2c66affSColin Finck 	{
3145c2c66affSColin Finck 	    LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
3146c2c66affSColin Finck 	    LPSTR p;
3147c2c66affSColin Finck 	    int f[6];
3148c2c66affSColin Finck 	    int i;
3149c2c66affSColin Finck 	    char *pAddr, *pPort;
3150c2c66affSColin Finck 	    INT nsocket = -1;
3151c2c66affSColin Finck 	    struct sockaddr_in dataSocketAddress;
3152c2c66affSColin Finck 
3153c2c66affSColin Finck 	    p = lpszResponseBuffer+4; /* skip status code */
3154c2c66affSColin Finck 	    while (*p != '\0' && (*p < '0' || *p > '9')) p++;
3155c2c66affSColin Finck 
3156c2c66affSColin Finck 	    if (*p == '\0')
3157c2c66affSColin Finck 	    {
3158c2c66affSColin Finck 		ERR("no address found in response, aborting\n");
3159c2c66affSColin Finck 		goto lend;
3160c2c66affSColin Finck 	    }
3161c2c66affSColin Finck 
3162c2c66affSColin Finck 	    if (sscanf(p, "%d,%d,%d,%d,%d,%d",  &f[0], &f[1], &f[2], &f[3],
3163c2c66affSColin Finck 				    		&f[4], &f[5]) != 6)
3164c2c66affSColin Finck 	    {
3165c2c66affSColin Finck 		ERR("unknown response address format '%s', aborting\n", p);
3166c2c66affSColin Finck 		goto lend;
3167c2c66affSColin Finck 	    }
3168c2c66affSColin Finck 	    for (i=0; i < 6; i++)
3169c2c66affSColin Finck 		f[i] = f[i] & 0xff;
3170c2c66affSColin Finck 
3171c2c66affSColin Finck 	    dataSocketAddress = lpwfs->socketAddress;
3172c2c66affSColin Finck 	    pAddr = (char *)&(dataSocketAddress.sin_addr.S_un.S_addr);
3173c2c66affSColin Finck 	    pPort = (char *)&(dataSocketAddress.sin_port);
3174c2c66affSColin Finck             pAddr[0] = f[0];
3175c2c66affSColin Finck             pAddr[1] = f[1];
3176c2c66affSColin Finck             pAddr[2] = f[2];
3177c2c66affSColin Finck             pAddr[3] = f[3];
3178c2c66affSColin Finck 	    pPort[0] = f[4];
3179c2c66affSColin Finck 	    pPort[1] = f[5];
3180c2c66affSColin Finck 
3181c2c66affSColin Finck             nsocket = socket(AF_INET,SOCK_STREAM,0);
3182c2c66affSColin Finck             if (nsocket == -1)
3183c2c66affSColin Finck                 goto lend;
3184c2c66affSColin Finck 
3185c2c66affSColin Finck 	    if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
3186c2c66affSColin Finck             {
3187c2c66affSColin Finck 	        ERR("can't connect passive FTP data port.\n");
3188c2c66affSColin Finck                 closesocket(nsocket);
3189c2c66affSColin Finck 	        goto lend;
3190c2c66affSColin Finck             }
3191c2c66affSColin Finck 	    lpwfs->pasvSocket = nsocket;
3192c2c66affSColin Finck             bSuccess = TRUE;
3193c2c66affSColin Finck 	}
3194c2c66affSColin Finck         else
3195c2c66affSColin Finck             FTP_SetResponseError(nResCode);
3196c2c66affSColin Finck     }
3197c2c66affSColin Finck 
3198c2c66affSColin Finck lend:
3199c2c66affSColin Finck     return bSuccess;
3200c2c66affSColin Finck }
3201c2c66affSColin Finck 
3202c2c66affSColin Finck 
FTP_SendPortOrPasv(ftp_session_t * lpwfs)3203c2c66affSColin Finck static BOOL FTP_SendPortOrPasv(ftp_session_t *lpwfs)
3204c2c66affSColin Finck {
3205c2c66affSColin Finck     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
3206c2c66affSColin Finck     {
3207c2c66affSColin Finck         if (!FTP_DoPassive(lpwfs))
3208c2c66affSColin Finck             return FALSE;
3209c2c66affSColin Finck     }
3210c2c66affSColin Finck     else
3211c2c66affSColin Finck     {
3212c2c66affSColin Finck 	if (!FTP_SendPort(lpwfs))
3213c2c66affSColin Finck             return FALSE;
3214c2c66affSColin Finck     }
3215c2c66affSColin Finck     return TRUE;
3216c2c66affSColin Finck }
3217c2c66affSColin Finck 
3218c2c66affSColin Finck 
3219c2c66affSColin Finck /***********************************************************************
3220c2c66affSColin Finck  *           FTP_GetDataSocket (internal)
3221c2c66affSColin Finck  *
3222c2c66affSColin Finck  * Either accepts an incoming data socket connection from the server
3223c2c66affSColin Finck  * or just returns the already opened socket after a PASV command
3224c2c66affSColin Finck  * in case of passive FTP.
3225c2c66affSColin Finck  *
3226c2c66affSColin Finck  *
3227c2c66affSColin Finck  * RETURNS
3228c2c66affSColin Finck  *   TRUE on success
3229c2c66affSColin Finck  *   FALSE on failure
3230c2c66affSColin Finck  *
3231c2c66affSColin Finck  */
FTP_GetDataSocket(ftp_session_t * lpwfs,LPINT nDataSocket)3232c2c66affSColin Finck static BOOL FTP_GetDataSocket(ftp_session_t *lpwfs, LPINT nDataSocket)
3233c2c66affSColin Finck {
3234c2c66affSColin Finck     struct sockaddr_in saddr;
3235c2c66affSColin Finck     socklen_t addrlen = sizeof(saddr);
3236c2c66affSColin Finck 
3237c2c66affSColin Finck     TRACE("\n");
3238c2c66affSColin Finck     if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
3239c2c66affSColin Finck     {
3240c2c66affSColin Finck 	*nDataSocket = lpwfs->pasvSocket;
3241c2c66affSColin Finck 	lpwfs->pasvSocket = -1;
3242c2c66affSColin Finck     }
3243c2c66affSColin Finck     else
3244c2c66affSColin Finck     {
3245c2c66affSColin Finck         *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
3246c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
3247c2c66affSColin Finck         lpwfs->lstnSocket = -1;
3248c2c66affSColin Finck     }
3249c2c66affSColin Finck     return *nDataSocket != -1;
3250c2c66affSColin Finck }
3251c2c66affSColin Finck 
3252c2c66affSColin Finck 
3253c2c66affSColin Finck /***********************************************************************
3254c2c66affSColin Finck  *           FTP_SendData (internal)
3255c2c66affSColin Finck  *
3256c2c66affSColin Finck  * Send data to the server
3257c2c66affSColin Finck  *
3258c2c66affSColin Finck  * RETURNS
3259c2c66affSColin Finck  *   TRUE on success
3260c2c66affSColin Finck  *   FALSE on failure
3261c2c66affSColin Finck  *
3262c2c66affSColin Finck  */
FTP_SendData(ftp_session_t * lpwfs,INT nDataSocket,HANDLE hFile)3263c2c66affSColin Finck static BOOL FTP_SendData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile)
3264c2c66affSColin Finck {
3265c2c66affSColin Finck     BY_HANDLE_FILE_INFORMATION fi;
3266c2c66affSColin Finck     DWORD nBytesRead = 0;
3267c2c66affSColin Finck     DWORD nBytesSent = 0;
3268c2c66affSColin Finck     DWORD nTotalSent = 0;
3269c2c66affSColin Finck     DWORD nBytesToSend, nLen;
3270c2c66affSColin Finck     int nRC = 1;
3271c2c66affSColin Finck     time_t s_long_time, e_long_time;
3272c2c66affSColin Finck     LONG nSeconds;
3273c2c66affSColin Finck     CHAR *lpszBuffer;
3274c2c66affSColin Finck 
3275c2c66affSColin Finck     TRACE("\n");
3276c2c66affSColin Finck     lpszBuffer = heap_alloc_zero(sizeof(CHAR)*DATA_PACKET_SIZE);
3277c2c66affSColin Finck 
3278c2c66affSColin Finck     /* Get the size of the file. */
3279c2c66affSColin Finck     GetFileInformationByHandle(hFile, &fi);
3280c2c66affSColin Finck     time(&s_long_time);
3281c2c66affSColin Finck 
3282c2c66affSColin Finck     do
3283c2c66affSColin Finck     {
3284c2c66affSColin Finck         nBytesToSend = nBytesRead - nBytesSent;
3285c2c66affSColin Finck 
3286c2c66affSColin Finck         if (nBytesToSend <= 0)
3287c2c66affSColin Finck         {
3288c2c66affSColin Finck             /* Read data from file. */
3289c2c66affSColin Finck             nBytesSent = 0;
3290c2c66affSColin Finck             if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
3291c2c66affSColin Finck             ERR("Failed reading from file\n");
3292c2c66affSColin Finck 
3293c2c66affSColin Finck             if (nBytesRead > 0)
3294c2c66affSColin Finck                 nBytesToSend = nBytesRead;
3295c2c66affSColin Finck             else
3296c2c66affSColin Finck                 break;
3297c2c66affSColin Finck         }
3298c2c66affSColin Finck 
3299c2c66affSColin Finck         nLen = DATA_PACKET_SIZE < nBytesToSend ?
3300c2c66affSColin Finck             DATA_PACKET_SIZE : nBytesToSend;
3301c2c66affSColin Finck         nRC  = sock_send(nDataSocket, lpszBuffer, nLen, 0);
3302c2c66affSColin Finck 
3303c2c66affSColin Finck         if (nRC != -1)
3304c2c66affSColin Finck         {
3305c2c66affSColin Finck             nBytesSent += nRC;
3306c2c66affSColin Finck             nTotalSent += nRC;
3307c2c66affSColin Finck         }
3308c2c66affSColin Finck 
3309c2c66affSColin Finck         /* Do some computation to display the status. */
3310c2c66affSColin Finck         time(&e_long_time);
3311c2c66affSColin Finck         nSeconds = e_long_time - s_long_time;
3312c2c66affSColin Finck         if( nSeconds / 60 > 0 )
3313c2c66affSColin Finck         {
3314c2c66affSColin Finck             TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
3315c2c66affSColin Finck             nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
3316c2c66affSColin Finck             nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
3317c2c66affSColin Finck         }
3318c2c66affSColin Finck         else
3319c2c66affSColin Finck         {
3320c2c66affSColin Finck             TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
3321c2c66affSColin Finck             nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
3322c2c66affSColin Finck             (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
3323c2c66affSColin Finck         }
3324c2c66affSColin Finck     } while (nRC != -1);
3325c2c66affSColin Finck 
3326c2c66affSColin Finck     TRACE("file transfer complete!\n");
3327c2c66affSColin Finck 
3328c2c66affSColin Finck     heap_free(lpszBuffer);
3329c2c66affSColin Finck     return nTotalSent;
3330c2c66affSColin Finck }
3331c2c66affSColin Finck 
3332c2c66affSColin Finck 
3333c2c66affSColin Finck /***********************************************************************
3334c2c66affSColin Finck  *           FTP_SendRetrieve (internal)
3335c2c66affSColin Finck  *
3336c2c66affSColin Finck  * Send request to retrieve a file
3337c2c66affSColin Finck  *
3338c2c66affSColin Finck  * RETURNS
3339c2c66affSColin Finck  *   Number of bytes to be received on success
3340c2c66affSColin Finck  *   0 on failure
3341c2c66affSColin Finck  *
3342c2c66affSColin Finck  */
FTP_SendRetrieve(ftp_session_t * lpwfs,LPCWSTR lpszRemoteFile,DWORD dwType)3343c2c66affSColin Finck static BOOL FTP_SendRetrieve(ftp_session_t *lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
3344c2c66affSColin Finck {
3345c2c66affSColin Finck     INT nResCode;
3346c2c66affSColin Finck     BOOL ret;
3347c2c66affSColin Finck 
3348c2c66affSColin Finck     TRACE("\n");
3349c2c66affSColin Finck     if (!(ret = FTP_InitListenSocket(lpwfs)))
3350c2c66affSColin Finck         goto lend;
3351c2c66affSColin Finck 
3352c2c66affSColin Finck     if (!(ret = FTP_SendType(lpwfs, dwType)))
3353c2c66affSColin Finck         goto lend;
3354c2c66affSColin Finck 
3355c2c66affSColin Finck     if (!(ret = FTP_SendPortOrPasv(lpwfs)))
3356c2c66affSColin Finck         goto lend;
3357c2c66affSColin Finck 
3358c2c66affSColin Finck     if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
3359c2c66affSColin Finck         goto lend;
3360c2c66affSColin Finck 
3361c2c66affSColin Finck     nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
3362c2c66affSColin Finck     if ((nResCode != 125) && (nResCode != 150)) {
3363c2c66affSColin Finck 	/* That means that we got an error getting the file. */
3364c2c66affSColin Finck         FTP_SetResponseError(nResCode);
3365c2c66affSColin Finck 	ret = FALSE;
3366c2c66affSColin Finck     }
3367c2c66affSColin Finck 
3368c2c66affSColin Finck lend:
3369c2c66affSColin Finck     if (!ret && lpwfs->lstnSocket != -1)
3370c2c66affSColin Finck     {
3371c2c66affSColin Finck         closesocket(lpwfs->lstnSocket);
3372c2c66affSColin Finck         lpwfs->lstnSocket = -1;
3373c2c66affSColin Finck     }
3374c2c66affSColin Finck 
3375c2c66affSColin Finck     return ret;
3376c2c66affSColin Finck }
3377c2c66affSColin Finck 
3378c2c66affSColin Finck 
3379c2c66affSColin Finck /***********************************************************************
3380c2c66affSColin Finck  *           FTP_RetrieveData  (internal)
3381c2c66affSColin Finck  *
3382c2c66affSColin Finck  * Retrieve data from server
3383c2c66affSColin Finck  *
3384c2c66affSColin Finck  * RETURNS
3385c2c66affSColin Finck  *   TRUE on success
3386c2c66affSColin Finck  *   FALSE on failure
3387c2c66affSColin Finck  *
3388c2c66affSColin Finck  */
FTP_RetrieveFileData(ftp_session_t * lpwfs,INT nDataSocket,HANDLE hFile)3389c2c66affSColin Finck static BOOL FTP_RetrieveFileData(ftp_session_t *lpwfs, INT nDataSocket, HANDLE hFile)
3390c2c66affSColin Finck {
3391c2c66affSColin Finck     DWORD nBytesWritten;
3392c2c66affSColin Finck     INT nRC = 0;
3393c2c66affSColin Finck     CHAR *lpszBuffer;
3394c2c66affSColin Finck 
3395c2c66affSColin Finck     TRACE("\n");
3396c2c66affSColin Finck 
3397c2c66affSColin Finck     lpszBuffer = heap_alloc_zero(sizeof(CHAR)*DATA_PACKET_SIZE);
3398c2c66affSColin Finck     if (NULL == lpszBuffer)
3399c2c66affSColin Finck     {
3400c2c66affSColin Finck         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
3401c2c66affSColin Finck         return FALSE;
3402c2c66affSColin Finck     }
3403c2c66affSColin Finck 
3404c2c66affSColin Finck     while (nRC != -1)
3405c2c66affSColin Finck     {
3406c2c66affSColin Finck         nRC = sock_recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
3407c2c66affSColin Finck         if (nRC != -1)
3408c2c66affSColin Finck         {
3409c2c66affSColin Finck             /* other side closed socket. */
3410c2c66affSColin Finck             if (nRC == 0)
3411c2c66affSColin Finck                 goto recv_end;
3412c2c66affSColin Finck             WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
3413c2c66affSColin Finck         }
3414c2c66affSColin Finck     }
3415c2c66affSColin Finck 
3416c2c66affSColin Finck     TRACE("Data transfer complete\n");
3417c2c66affSColin Finck 
3418c2c66affSColin Finck recv_end:
3419c2c66affSColin Finck     heap_free(lpszBuffer);
3420c2c66affSColin Finck     return (nRC != -1);
3421c2c66affSColin Finck }
3422c2c66affSColin Finck 
3423c2c66affSColin Finck /***********************************************************************
3424c2c66affSColin Finck  *           FTPFINDNEXT_Destroy (internal)
3425c2c66affSColin Finck  *
3426c2c66affSColin Finck  * Deallocate session handle
3427c2c66affSColin Finck  */
FTPFINDNEXT_Destroy(object_header_t * hdr)3428c2c66affSColin Finck static void FTPFINDNEXT_Destroy(object_header_t *hdr)
3429c2c66affSColin Finck {
3430c2c66affSColin Finck     LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
3431c2c66affSColin Finck     DWORD i;
3432c2c66affSColin Finck 
3433c2c66affSColin Finck     TRACE("\n");
3434c2c66affSColin Finck 
3435c2c66affSColin Finck     WININET_Release(&lpwfn->lpFtpSession->hdr);
3436c2c66affSColin Finck 
3437c2c66affSColin Finck     for (i = 0; i < lpwfn->size; i++)
3438c2c66affSColin Finck     {
3439c2c66affSColin Finck         heap_free(lpwfn->lpafp[i].lpszName);
3440c2c66affSColin Finck     }
3441c2c66affSColin Finck     heap_free(lpwfn->lpafp);
3442c2c66affSColin Finck }
3443c2c66affSColin Finck 
FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW * find,LPVOID data)3444c2c66affSColin Finck static DWORD FTPFINDNEXT_FindNextFileProc(WININETFTPFINDNEXTW *find, LPVOID data)
3445c2c66affSColin Finck {
3446c2c66affSColin Finck     WIN32_FIND_DATAW *find_data = data;
3447c2c66affSColin Finck     DWORD res = ERROR_SUCCESS;
3448c2c66affSColin Finck 
3449c2c66affSColin Finck     TRACE("index(%d) size(%d)\n", find->index, find->size);
3450c2c66affSColin Finck 
3451c2c66affSColin Finck     ZeroMemory(find_data, sizeof(WIN32_FIND_DATAW));
3452c2c66affSColin Finck 
3453c2c66affSColin Finck     if (find->index < find->size) {
3454c2c66affSColin Finck         FTP_ConvertFileProp(&find->lpafp[find->index], find_data);
3455c2c66affSColin Finck         find->index++;
3456c2c66affSColin Finck 
3457c2c66affSColin Finck         TRACE("Name: %s\nSize: %d\n", debugstr_w(find_data->cFileName), find_data->nFileSizeLow);
3458c2c66affSColin Finck     }else {
3459c2c66affSColin Finck         res = ERROR_NO_MORE_FILES;
3460c2c66affSColin Finck     }
3461c2c66affSColin Finck 
3462c2c66affSColin Finck     if (find->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3463c2c66affSColin Finck     {
3464c2c66affSColin Finck         INTERNET_ASYNC_RESULT iar;
3465c2c66affSColin Finck 
3466c2c66affSColin Finck         iar.dwResult = (res == ERROR_SUCCESS);
3467c2c66affSColin Finck         iar.dwError = res;
3468c2c66affSColin Finck 
3469c2c66affSColin Finck         INTERNET_SendCallback(&find->hdr, find->hdr.dwContext,
3470c2c66affSColin Finck                               INTERNET_STATUS_REQUEST_COMPLETE, &iar,
3471c2c66affSColin Finck                               sizeof(INTERNET_ASYNC_RESULT));
3472c2c66affSColin Finck     }
3473c2c66affSColin Finck 
3474c2c66affSColin Finck     return res;
3475c2c66affSColin Finck }
3476c2c66affSColin Finck 
3477c2c66affSColin Finck typedef struct {
3478c2c66affSColin Finck     task_header_t hdr;
3479c2c66affSColin Finck     WIN32_FIND_DATAW *find_data;
3480c2c66affSColin Finck } find_next_task_t;
3481c2c66affSColin Finck 
FTPFINDNEXT_AsyncFindNextFileProc(task_header_t * hdr)3482c2c66affSColin Finck static void FTPFINDNEXT_AsyncFindNextFileProc(task_header_t *hdr)
3483c2c66affSColin Finck {
3484c2c66affSColin Finck     find_next_task_t *task = (find_next_task_t*)hdr;
3485c2c66affSColin Finck 
3486c2c66affSColin Finck     FTPFINDNEXT_FindNextFileProc((WININETFTPFINDNEXTW*)task->hdr.hdr, task->find_data);
3487c2c66affSColin Finck }
3488c2c66affSColin Finck 
FTPFINDNEXT_QueryOption(object_header_t * hdr,DWORD option,void * buffer,DWORD * size,BOOL unicode)3489c2c66affSColin Finck static DWORD FTPFINDNEXT_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
3490c2c66affSColin Finck {
3491c2c66affSColin Finck     switch(option) {
3492c2c66affSColin Finck     case INTERNET_OPTION_HANDLE_TYPE:
3493c2c66affSColin Finck         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
3494c2c66affSColin Finck 
3495c2c66affSColin Finck         if (*size < sizeof(ULONG))
3496c2c66affSColin Finck             return ERROR_INSUFFICIENT_BUFFER;
3497c2c66affSColin Finck 
3498c2c66affSColin Finck         *size = sizeof(DWORD);
3499c2c66affSColin Finck         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_FTP_FIND;
3500c2c66affSColin Finck         return ERROR_SUCCESS;
3501c2c66affSColin Finck     }
3502c2c66affSColin Finck 
3503c2c66affSColin Finck     return INET_QueryOption(hdr, option, buffer, size, unicode);
3504c2c66affSColin Finck }
3505c2c66affSColin Finck 
FTPFINDNEXT_FindNextFileW(object_header_t * hdr,void * data)3506c2c66affSColin Finck static DWORD FTPFINDNEXT_FindNextFileW(object_header_t *hdr, void *data)
3507c2c66affSColin Finck {
3508c2c66affSColin Finck     WININETFTPFINDNEXTW *find = (WININETFTPFINDNEXTW*)hdr;
3509c2c66affSColin Finck 
3510c2c66affSColin Finck     if (find->lpFtpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3511c2c66affSColin Finck     {
3512c2c66affSColin Finck         find_next_task_t *task;
3513c2c66affSColin Finck 
3514c2c66affSColin Finck         task = alloc_async_task(&find->hdr, FTPFINDNEXT_AsyncFindNextFileProc, sizeof(*task));
3515c2c66affSColin Finck         task->find_data = data;
3516c2c66affSColin Finck 
3517c2c66affSColin Finck         INTERNET_AsyncCall(&task->hdr);
3518c2c66affSColin Finck         return ERROR_SUCCESS;
3519c2c66affSColin Finck     }
3520c2c66affSColin Finck 
3521c2c66affSColin Finck     return FTPFINDNEXT_FindNextFileProc(find, data);
3522c2c66affSColin Finck }
3523c2c66affSColin Finck 
3524c2c66affSColin Finck static const object_vtbl_t FTPFINDNEXTVtbl = {
3525c2c66affSColin Finck     FTPFINDNEXT_Destroy,
3526c2c66affSColin Finck     NULL,
3527c2c66affSColin Finck     FTPFINDNEXT_QueryOption,
3528c2c66affSColin Finck     INET_SetOption,
3529c2c66affSColin Finck     NULL,
3530c2c66affSColin Finck     NULL,
3531c2c66affSColin Finck     NULL,
3532c2c66affSColin Finck     FTPFINDNEXT_FindNextFileW
3533c2c66affSColin Finck };
3534c2c66affSColin Finck 
3535c2c66affSColin Finck /***********************************************************************
3536c2c66affSColin Finck  *           FTP_ReceiveFileList (internal)
3537c2c66affSColin Finck  *
3538c2c66affSColin Finck  * Read file list from server
3539c2c66affSColin Finck  *
3540c2c66affSColin Finck  * RETURNS
3541c2c66affSColin Finck  *   Handle to file list on success
3542c2c66affSColin Finck  *   NULL on failure
3543c2c66affSColin Finck  *
3544c2c66affSColin Finck  */
FTP_ReceiveFileList(ftp_session_t * lpwfs,INT nSocket,LPCWSTR lpszSearchFile,LPWIN32_FIND_DATAW lpFindFileData,DWORD_PTR dwContext)3545c2c66affSColin Finck static HINTERNET FTP_ReceiveFileList(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3546c2c66affSColin Finck 	LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
3547c2c66affSColin Finck {
3548c2c66affSColin Finck     DWORD dwSize = 0;
3549c2c66affSColin Finck     LPFILEPROPERTIESW lpafp = NULL;
3550c2c66affSColin Finck     LPWININETFTPFINDNEXTW lpwfn = NULL;
3551c2c66affSColin Finck 
3552c2c66affSColin Finck     TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3553c2c66affSColin Finck 
3554c2c66affSColin Finck     if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3555c2c66affSColin Finck     {
3556c2c66affSColin Finck         if(lpFindFileData)
3557c2c66affSColin Finck             FTP_ConvertFileProp(lpafp, lpFindFileData);
3558c2c66affSColin Finck 
3559c2c66affSColin Finck         lpwfn = alloc_object(&lpwfs->hdr, &FTPFINDNEXTVtbl, sizeof(WININETFTPFINDNEXTW));
3560c2c66affSColin Finck         if (lpwfn)
3561c2c66affSColin Finck         {
3562c2c66affSColin Finck             lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3563c2c66affSColin Finck             lpwfn->hdr.dwContext = dwContext;
3564c2c66affSColin Finck             lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3565c2c66affSColin Finck             lpwfn->size = dwSize;
3566c2c66affSColin Finck             lpwfn->lpafp = lpafp;
3567c2c66affSColin Finck 
3568c2c66affSColin Finck             WININET_AddRef( &lpwfs->hdr );
3569c2c66affSColin Finck             lpwfn->lpFtpSession = lpwfs;
3570c2c66affSColin Finck             list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry );
3571c2c66affSColin Finck         }
3572c2c66affSColin Finck     }
3573c2c66affSColin Finck 
3574c2c66affSColin Finck     TRACE("Matched %d files\n", dwSize);
3575c2c66affSColin Finck     return lpwfn ? lpwfn->hdr.hInternet : NULL;
3576c2c66affSColin Finck }
3577c2c66affSColin Finck 
3578c2c66affSColin Finck 
3579c2c66affSColin Finck /***********************************************************************
3580c2c66affSColin Finck  *           FTP_ConvertFileProp (internal)
3581c2c66affSColin Finck  *
3582c2c66affSColin Finck  * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3583c2c66affSColin Finck  *
3584c2c66affSColin Finck  * RETURNS
3585c2c66affSColin Finck  *   TRUE on success
3586c2c66affSColin Finck  *   FALSE on failure
3587c2c66affSColin Finck  *
3588c2c66affSColin Finck  */
FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp,LPWIN32_FIND_DATAW lpFindFileData)3589c2c66affSColin Finck static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3590c2c66affSColin Finck {
3591c2c66affSColin Finck     BOOL bSuccess = FALSE;
3592c2c66affSColin Finck 
3593c2c66affSColin Finck     ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3594c2c66affSColin Finck 
3595c2c66affSColin Finck     if (lpafp)
3596c2c66affSColin Finck     {
3597c2c66affSColin Finck         SystemTimeToFileTime( &lpafp->tmLastModified, &lpFindFileData->ftLastAccessTime );
3598c2c66affSColin Finck 	lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3599c2c66affSColin Finck 	lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3600c2c66affSColin Finck 
3601c2c66affSColin Finck         /* Not all fields are filled in */
3602c2c66affSColin Finck         lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3603c2c66affSColin Finck         lpFindFileData->nFileSizeLow = lpafp->nSize;
3604c2c66affSColin Finck 
3605c2c66affSColin Finck 	if (lpafp->bIsDirectory)
3606c2c66affSColin Finck 	    lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3607c2c66affSColin Finck 
3608c2c66affSColin Finck         if (lpafp->lpszName)
3609c2c66affSColin Finck             lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3610c2c66affSColin Finck 
3611c2c66affSColin Finck 	bSuccess = TRUE;
3612c2c66affSColin Finck     }
3613c2c66affSColin Finck 
3614c2c66affSColin Finck     return bSuccess;
3615c2c66affSColin Finck }
3616c2c66affSColin Finck 
3617c2c66affSColin Finck /***********************************************************************
3618c2c66affSColin Finck  *           FTP_ParseNextFile (internal)
3619c2c66affSColin Finck  *
3620c2c66affSColin Finck  * Parse the next line in file listing
3621c2c66affSColin Finck  *
3622c2c66affSColin Finck  * RETURNS
3623c2c66affSColin Finck  *   TRUE on success
3624c2c66affSColin Finck  *   FALSE on failure
3625c2c66affSColin Finck  */
FTP_ParseNextFile(INT nSocket,LPCWSTR lpszSearchFile,LPFILEPROPERTIESW lpfp)3626c2c66affSColin Finck static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3627c2c66affSColin Finck {
3628c2c66affSColin Finck     static const char szSpace[] = " \t";
3629c2c66affSColin Finck     DWORD nBufLen;
3630c2c66affSColin Finck     char *pszLine;
3631c2c66affSColin Finck     char *pszToken;
3632c2c66affSColin Finck     char *pszTmp;
3633c2c66affSColin Finck     BOOL found = FALSE;
3634c2c66affSColin Finck     int i;
3635c2c66affSColin Finck 
3636c2c66affSColin Finck     lpfp->lpszName = NULL;
3637c2c66affSColin Finck     do {
3638c2c66affSColin Finck         if(!(pszLine = FTP_GetNextLine(nSocket, &nBufLen)))
3639c2c66affSColin Finck             return FALSE;
3640c2c66affSColin Finck 
3641c2c66affSColin Finck         pszToken = strtok(pszLine, szSpace);
3642c2c66affSColin Finck         /* ls format
3643c2c66affSColin Finck          * <Permissions> <NoLinks> <owner>   <group> <size> <date>  <time or year> <filename>
3644c2c66affSColin Finck          *
3645c2c66affSColin Finck          * For instance:
3646c2c66affSColin Finck          * drwx--s---     2         pcarrier  ens     512    Sep 28  1995           pcarrier
3647c2c66affSColin Finck          */
3648c2c66affSColin Finck         if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3649c2c66affSColin Finck             if(!FTP_ParsePermission(pszToken, lpfp))
3650c2c66affSColin Finck                 lpfp->bIsDirectory = FALSE;
3651c2c66affSColin Finck             for(i=0; i<=3; i++) {
3652c2c66affSColin Finck               if(!(pszToken = strtok(NULL, szSpace)))
3653c2c66affSColin Finck                   break;
3654c2c66affSColin Finck             }
3655c2c66affSColin Finck             if(!pszToken) continue;
3656c2c66affSColin Finck             if(lpfp->bIsDirectory) {
3657c2c66affSColin Finck                 TRACE("Is directory\n");
3658c2c66affSColin Finck                 lpfp->nSize = 0;
3659c2c66affSColin Finck             }
3660c2c66affSColin Finck             else {
3661c2c66affSColin Finck                 TRACE("Size: %s\n", pszToken);
3662c2c66affSColin Finck                 lpfp->nSize = atol(pszToken);
3663c2c66affSColin Finck             }
3664c2c66affSColin Finck 
3665c2c66affSColin Finck             lpfp->tmLastModified.wSecond = 0;
3666c2c66affSColin Finck             lpfp->tmLastModified.wMinute = 0;
3667c2c66affSColin Finck             lpfp->tmLastModified.wHour   = 0;
3668c2c66affSColin Finck             lpfp->tmLastModified.wDay    = 0;
3669c2c66affSColin Finck             lpfp->tmLastModified.wMonth  = 0;
3670c2c66affSColin Finck             lpfp->tmLastModified.wYear   = 0;
3671c2c66affSColin Finck 
3672c2c66affSColin Finck             /* Determine month */
3673c2c66affSColin Finck             pszToken = strtok(NULL, szSpace);
3674c2c66affSColin Finck             if(!pszToken) continue;
3675c2c66affSColin Finck             if(strlen(pszToken) >= 3) {
3676c2c66affSColin Finck                 pszToken[3] = 0;
3677c2c66affSColin Finck                 if((pszTmp = StrStrIA(szMonths, pszToken)))
3678c2c66affSColin Finck                     lpfp->tmLastModified.wMonth = ((pszTmp - szMonths) / 3)+1;
3679c2c66affSColin Finck             }
3680c2c66affSColin Finck             /* Determine day */
3681c2c66affSColin Finck             pszToken = strtok(NULL, szSpace);
3682c2c66affSColin Finck             if(!pszToken) continue;
3683c2c66affSColin Finck             lpfp->tmLastModified.wDay = atoi(pszToken);
3684c2c66affSColin Finck             /* Determine time or year */
3685c2c66affSColin Finck             pszToken = strtok(NULL, szSpace);
3686c2c66affSColin Finck             if(!pszToken) continue;
3687c2c66affSColin Finck             if((pszTmp = strchr(pszToken, ':'))) {
3688c2c66affSColin Finck                 SYSTEMTIME curr_time;
3689c2c66affSColin Finck                 *pszTmp = 0;
3690c2c66affSColin Finck                 pszTmp++;
3691c2c66affSColin Finck                 lpfp->tmLastModified.wMinute = atoi(pszTmp);
3692c2c66affSColin Finck                 lpfp->tmLastModified.wHour = atoi(pszToken);
3693c2c66affSColin Finck                 GetLocalTime( &curr_time );
3694c2c66affSColin Finck                 lpfp->tmLastModified.wYear = curr_time.wYear;
3695c2c66affSColin Finck             }
3696c2c66affSColin Finck             else {
3697c2c66affSColin Finck                 lpfp->tmLastModified.wYear = atoi(pszToken);
3698c2c66affSColin Finck                 lpfp->tmLastModified.wHour = 12;
3699c2c66affSColin Finck             }
3700c2c66affSColin Finck             TRACE("Mod time: %02d:%02d:%02d  %04d/%02d/%02d\n",
3701c2c66affSColin Finck                   lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond,
3702c2c66affSColin Finck                   lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay);
3703c2c66affSColin Finck 
3704c2c66affSColin Finck             pszToken = strtok(NULL, szSpace);
3705c2c66affSColin Finck             if(!pszToken) continue;
3706c2c66affSColin Finck             lpfp->lpszName = heap_strdupAtoW(pszToken);
3707c2c66affSColin Finck             TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3708c2c66affSColin Finck         }
3709c2c66affSColin Finck         /* NT way of parsing ... :
3710c2c66affSColin Finck 
3711c2c66affSColin Finck                 07-13-03  08:55PM       <DIR>          sakpatch
3712c2c66affSColin Finck                 05-09-03  06:02PM             12656686 2003-04-21bgm_cmd_e.rgz
3713c2c66affSColin Finck         */
3714c2c66affSColin Finck         else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3715c2c66affSColin Finck             int mon, mday, year, hour, min;
3716c2c66affSColin Finck             lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3717c2c66affSColin Finck 
3718c2c66affSColin Finck             sscanf(pszToken, "%d-%d-%d", &mon, &mday, &year);
3719c2c66affSColin Finck             lpfp->tmLastModified.wDay   = mday;
3720c2c66affSColin Finck             lpfp->tmLastModified.wMonth = mon;
3721c2c66affSColin Finck             lpfp->tmLastModified.wYear  = year;
3722c2c66affSColin Finck 
3723c2c66affSColin Finck             /* Hacky and bad Y2K protection :-) */
3724c2c66affSColin Finck             if (lpfp->tmLastModified.wYear < 70) lpfp->tmLastModified.wYear += 2000;
3725c2c66affSColin Finck 
3726c2c66affSColin Finck             pszToken = strtok(NULL, szSpace);
3727c2c66affSColin Finck             if(!pszToken) continue;
3728c2c66affSColin Finck             sscanf(pszToken, "%d:%d", &hour, &min);
3729c2c66affSColin Finck             lpfp->tmLastModified.wHour   = hour;
3730c2c66affSColin Finck             lpfp->tmLastModified.wMinute = min;
3731c2c66affSColin Finck             if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3732c2c66affSColin Finck                 lpfp->tmLastModified.wHour += 12;
3733c2c66affSColin Finck             }
3734c2c66affSColin Finck             lpfp->tmLastModified.wSecond = 0;
3735c2c66affSColin Finck 
3736c2c66affSColin Finck             TRACE("Mod time: %02d:%02d:%02d  %04d/%02d/%02d\n",
3737c2c66affSColin Finck                   lpfp->tmLastModified.wHour, lpfp->tmLastModified.wMinute, lpfp->tmLastModified.wSecond,
3738c2c66affSColin Finck                   lpfp->tmLastModified.wYear, lpfp->tmLastModified.wMonth, lpfp->tmLastModified.wDay);
3739c2c66affSColin Finck 
3740c2c66affSColin Finck             pszToken = strtok(NULL, szSpace);
3741c2c66affSColin Finck             if(!pszToken) continue;
374294937754Swinesync             if(!stricmp(pszToken, "<DIR>")) {
3743c2c66affSColin Finck                 lpfp->bIsDirectory = TRUE;
3744c2c66affSColin Finck                 lpfp->nSize = 0;
3745c2c66affSColin Finck                 TRACE("Is directory\n");
3746c2c66affSColin Finck             }
3747c2c66affSColin Finck             else {
3748c2c66affSColin Finck                 lpfp->bIsDirectory = FALSE;
3749c2c66affSColin Finck                 lpfp->nSize = atol(pszToken);
3750c2c66affSColin Finck                 TRACE("Size: %d\n", lpfp->nSize);
3751c2c66affSColin Finck             }
3752c2c66affSColin Finck 
3753c2c66affSColin Finck             pszToken = strtok(NULL, szSpace);
3754c2c66affSColin Finck             if(!pszToken) continue;
3755c2c66affSColin Finck             lpfp->lpszName = heap_strdupAtoW(pszToken);
3756c2c66affSColin Finck             TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3757c2c66affSColin Finck         }
3758c2c66affSColin Finck         /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3759c2c66affSColin Finck         else if(pszToken[0] == '+') {
3760c2c66affSColin Finck             FIXME("EPLF Format not implemented\n");
3761c2c66affSColin Finck         }
3762c2c66affSColin Finck 
3763c2c66affSColin Finck         if(lpfp->lpszName) {
3764c2c66affSColin Finck             if((lpszSearchFile == NULL) ||
3765c2c66affSColin Finck 	       (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3766c2c66affSColin Finck                 found = TRUE;
3767c2c66affSColin Finck                 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3768c2c66affSColin Finck             }
3769c2c66affSColin Finck             else {
3770c2c66affSColin Finck                 heap_free(lpfp->lpszName);
3771c2c66affSColin Finck                 lpfp->lpszName = NULL;
3772c2c66affSColin Finck             }
3773c2c66affSColin Finck         }
3774c2c66affSColin Finck     } while(!found);
3775c2c66affSColin Finck     return TRUE;
3776c2c66affSColin Finck }
3777c2c66affSColin Finck 
3778c2c66affSColin Finck /***********************************************************************
3779c2c66affSColin Finck  *           FTP_ParseDirectory (internal)
3780c2c66affSColin Finck  *
3781c2c66affSColin Finck  * Parse string of directory information
3782c2c66affSColin Finck  *
3783c2c66affSColin Finck  * RETURNS
3784c2c66affSColin Finck  *   TRUE on success
3785c2c66affSColin Finck  *   FALSE on failure
3786c2c66affSColin Finck  */
FTP_ParseDirectory(ftp_session_t * lpwfs,INT nSocket,LPCWSTR lpszSearchFile,LPFILEPROPERTIESW * lpafp,LPDWORD dwfp)3787c2c66affSColin Finck static BOOL FTP_ParseDirectory(ftp_session_t *lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3788c2c66affSColin Finck     LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3789c2c66affSColin Finck {
3790c2c66affSColin Finck     BOOL bSuccess = TRUE;
3791c2c66affSColin Finck     INT sizeFilePropArray = 500;/*20; */
3792c2c66affSColin Finck     INT indexFilePropArray = -1;
3793c2c66affSColin Finck 
3794c2c66affSColin Finck     TRACE("\n");
3795c2c66affSColin Finck 
3796c2c66affSColin Finck     /* Allocate initial file properties array */
3797c2c66affSColin Finck     *lpafp = heap_alloc_zero(sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3798c2c66affSColin Finck     if (!*lpafp)
3799c2c66affSColin Finck         return FALSE;
3800c2c66affSColin Finck 
3801c2c66affSColin Finck     do {
3802c2c66affSColin Finck         if (indexFilePropArray+1 >= sizeFilePropArray)
3803c2c66affSColin Finck         {
3804c2c66affSColin Finck             LPFILEPROPERTIESW tmpafp;
3805c2c66affSColin Finck 
3806c2c66affSColin Finck             sizeFilePropArray *= 2;
3807c2c66affSColin Finck             tmpafp = heap_realloc_zero(*lpafp, sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3808c2c66affSColin Finck             if (NULL == tmpafp)
3809c2c66affSColin Finck             {
3810c2c66affSColin Finck                 bSuccess = FALSE;
3811c2c66affSColin Finck                 break;
3812c2c66affSColin Finck             }
3813c2c66affSColin Finck 
3814c2c66affSColin Finck             *lpafp = tmpafp;
3815c2c66affSColin Finck         }
3816c2c66affSColin Finck         indexFilePropArray++;
3817c2c66affSColin Finck     } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3818c2c66affSColin Finck 
3819c2c66affSColin Finck     if (bSuccess && indexFilePropArray)
3820c2c66affSColin Finck     {
3821c2c66affSColin Finck         if (indexFilePropArray < sizeFilePropArray - 1)
3822c2c66affSColin Finck         {
3823c2c66affSColin Finck             LPFILEPROPERTIESW tmpafp;
3824c2c66affSColin Finck 
3825c2c66affSColin Finck             tmpafp = heap_realloc(*lpafp, sizeof(FILEPROPERTIESW)*indexFilePropArray);
3826c2c66affSColin Finck             if (NULL != tmpafp)
3827c2c66affSColin Finck                 *lpafp = tmpafp;
3828c2c66affSColin Finck         }
3829c2c66affSColin Finck         *dwfp = indexFilePropArray;
3830c2c66affSColin Finck     }
3831c2c66affSColin Finck     else
3832c2c66affSColin Finck     {
3833c2c66affSColin Finck         heap_free(*lpafp);
3834c2c66affSColin Finck         INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3835c2c66affSColin Finck         bSuccess = FALSE;
3836c2c66affSColin Finck     }
3837c2c66affSColin Finck 
3838c2c66affSColin Finck     return bSuccess;
3839c2c66affSColin Finck }
3840c2c66affSColin Finck 
3841c2c66affSColin Finck 
3842c2c66affSColin Finck /***********************************************************************
3843c2c66affSColin Finck  *           FTP_ParsePermission (internal)
3844c2c66affSColin Finck  *
3845c2c66affSColin Finck  * Parse permission string of directory information
3846c2c66affSColin Finck  *
3847c2c66affSColin Finck  * RETURNS
3848c2c66affSColin Finck  *   TRUE on success
3849c2c66affSColin Finck  *   FALSE on failure
3850c2c66affSColin Finck  *
3851c2c66affSColin Finck  */
FTP_ParsePermission(LPCSTR lpszPermission,LPFILEPROPERTIESW lpfp)3852c2c66affSColin Finck static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3853c2c66affSColin Finck {
3854c2c66affSColin Finck     BOOL bSuccess = TRUE;
3855c2c66affSColin Finck     unsigned short nPermission = 0;
3856c2c66affSColin Finck     INT nPos = 1;
3857c2c66affSColin Finck     INT nLast  = 9;
3858c2c66affSColin Finck 
3859c2c66affSColin Finck     TRACE("\n");
3860c2c66affSColin Finck     if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3861c2c66affSColin Finck     {
3862c2c66affSColin Finck         bSuccess = FALSE;
3863c2c66affSColin Finck         return bSuccess;
3864c2c66affSColin Finck     }
3865c2c66affSColin Finck 
3866c2c66affSColin Finck     lpfp->bIsDirectory = (*lpszPermission == 'd');
3867c2c66affSColin Finck     do
3868c2c66affSColin Finck     {
3869c2c66affSColin Finck         switch (nPos)
3870c2c66affSColin Finck         {
3871c2c66affSColin Finck             case 1:
3872c2c66affSColin Finck                 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3873c2c66affSColin Finck                 break;
3874c2c66affSColin Finck             case 2:
3875c2c66affSColin Finck                 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3876c2c66affSColin Finck                 break;
3877c2c66affSColin Finck             case 3:
3878c2c66affSColin Finck                 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3879c2c66affSColin Finck                 break;
3880c2c66affSColin Finck             case 4:
3881c2c66affSColin Finck                 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3882c2c66affSColin Finck                 break;
3883c2c66affSColin Finck             case 5:
3884c2c66affSColin Finck                 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3885c2c66affSColin Finck                 break;
3886c2c66affSColin Finck             case 6:
3887c2c66affSColin Finck                 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3888c2c66affSColin Finck                 break;
3889c2c66affSColin Finck             case 7:
3890c2c66affSColin Finck                 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3891c2c66affSColin Finck                 break;
3892c2c66affSColin Finck             case 8:
3893c2c66affSColin Finck                 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3894c2c66affSColin Finck                 break;
3895c2c66affSColin Finck             case 9:
3896c2c66affSColin Finck                 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3897c2c66affSColin Finck                 break;
3898c2c66affSColin Finck         }
3899c2c66affSColin Finck         nPos++;
3900c2c66affSColin Finck     }while (nPos <= nLast);
3901c2c66affSColin Finck 
3902c2c66affSColin Finck     lpfp->permissions = nPermission;
3903c2c66affSColin Finck     return bSuccess;
3904c2c66affSColin Finck }
3905c2c66affSColin Finck 
3906c2c66affSColin Finck 
3907c2c66affSColin Finck /***********************************************************************
3908c2c66affSColin Finck  *           FTP_SetResponseError (internal)
3909c2c66affSColin Finck  *
3910c2c66affSColin Finck  * Set the appropriate error code for a given response from the server
3911c2c66affSColin Finck  *
3912c2c66affSColin Finck  * RETURNS
3913c2c66affSColin Finck  *
3914c2c66affSColin Finck  */
FTP_SetResponseError(DWORD dwResponse)3915c2c66affSColin Finck static DWORD FTP_SetResponseError(DWORD dwResponse)
3916c2c66affSColin Finck {
3917c2c66affSColin Finck     DWORD dwCode = 0;
3918c2c66affSColin Finck 
3919c2c66affSColin Finck     switch(dwResponse)
3920c2c66affSColin Finck     {
3921c2c66affSColin Finck     case 425: /* Cannot open data connection. */
3922c2c66affSColin Finck         dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3923c2c66affSColin Finck         break;
3924c2c66affSColin Finck 
39251e7b4025Swinesync     case 426: /* Connection closed, transfer aborted. */
3926c2c66affSColin Finck         dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3927c2c66affSColin Finck         break;
3928c2c66affSColin Finck 
3929c2c66affSColin Finck     case 530: /* Not logged in. Login incorrect. */
3930c2c66affSColin Finck         dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3931c2c66affSColin Finck         break;
3932c2c66affSColin Finck 
3933c2c66affSColin Finck     case 421: /* Service not available - Server may be shutting down. */
3934c2c66affSColin Finck     case 450: /* File action not taken. File may be busy. */
3935c2c66affSColin Finck     case 451: /* Action aborted. Server error. */
3936c2c66affSColin Finck     case 452: /* Action not taken. Insufficient storage space on server. */
3937c2c66affSColin Finck     case 500: /* Syntax error. Command unrecognized. */
3938c2c66affSColin Finck     case 501: /* Syntax error. Error in parameters or arguments. */
3939c2c66affSColin Finck     case 502: /* Command not implemented. */
3940c2c66affSColin Finck     case 503: /* Bad sequence of commands. */
3941c2c66affSColin Finck     case 504: /* Command not implemented for that parameter. */
3942c2c66affSColin Finck     case 532: /* Need account for storing files */
3943c2c66affSColin Finck     case 550: /* File action not taken. File not found or no access. */
3944c2c66affSColin Finck     case 551: /* Requested action aborted. Page type unknown */
3945c2c66affSColin Finck     case 552: /* Action aborted. Exceeded storage allocation */
3946c2c66affSColin Finck     case 553: /* Action not taken. File name not allowed. */
3947c2c66affSColin Finck 
3948c2c66affSColin Finck     default:
3949c2c66affSColin Finck         dwCode = ERROR_INTERNET_EXTENDED_ERROR;
3950c2c66affSColin Finck         break;
3951c2c66affSColin Finck     }
3952c2c66affSColin Finck 
3953c2c66affSColin Finck     INTERNET_SetLastError(dwCode);
3954c2c66affSColin Finck     return dwCode;
3955c2c66affSColin Finck }
3956