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