msvcp: Export a couple of variables and their access function.
[wine] / dlls / wininet / ftp.c
CommitLineData
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 72WINE_DEFAULT_DEBUG_CHANNEL(wininet);
819fa8ce 73
8adbf8ce 74typedef struct _ftp_session_t ftp_session_t;
352b4212
JC
75
76typedef 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 86struct _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
102typedef 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
111typedef 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
129typedef 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 155static 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
178static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
1d2d2d6b 179static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
819fa8ce 180
067f0960 181static 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
183static BOOL FTP_SendStore(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType);
184static BOOL FTP_GetDataSocket(ftp_session_t*, LPINT nDataSocket);
185static BOOL FTP_SendData(ftp_session_t*, INT nDataSocket, HANDLE hFile);
186static INT FTP_ReceiveResponse(ftp_session_t*, DWORD_PTR dwContext);
187static BOOL FTP_SendRetrieve(ftp_session_t*, LPCWSTR lpszRemoteFile, DWORD dwType);
188static BOOL FTP_RetrieveFileData(ftp_session_t*, INT nDataSocket, HANDLE hFile);
189static BOOL FTP_InitListenSocket(ftp_session_t*);
190static BOOL FTP_ConnectToHost(ftp_session_t*);
191static BOOL FTP_SendPassword(ftp_session_t*);
192static BOOL FTP_SendAccount(ftp_session_t*);
193static BOOL FTP_SendType(ftp_session_t*, DWORD dwType);
194static BOOL FTP_SendPort(ftp_session_t*);
195static BOOL FTP_DoPassive(ftp_session_t*);
196static BOOL FTP_SendPortOrPasv(ftp_session_t*);
067f0960
RS
197static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
198static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
8adbf8ce 199static BOOL FTP_ParseDirectory(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile,
352b4212 200 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
8adbf8ce 201static HINTERNET FTP_ReceiveFileList(ftp_session_t*, INT nSocket, LPCWSTR lpszSearchFile,
352b4212 202 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext);
067f0960 203static DWORD FTP_SetResponseError(DWORD dwResponse);
66259555 204static BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData);
8adbf8ce 205static BOOL FTP_FtpPutFileW(ftp_session_t*, LPCWSTR lpszLocalFile,
352b4212 206 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext);
8adbf8ce
JC
207static BOOL FTP_FtpSetCurrentDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
208static BOOL FTP_FtpCreateDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
209static HINTERNET FTP_FtpFindFirstFileW(ftp_session_t*,
352b4212 210 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext);
8adbf8ce 211static BOOL FTP_FtpGetCurrentDirectoryW(ftp_session_t*, LPWSTR lpszCurrentDirectory,
352b4212 212 LPDWORD lpdwCurrentDirectory);
8adbf8ce
JC
213static BOOL FTP_FtpRenameFileW(ftp_session_t*, LPCWSTR lpszSrc, LPCWSTR lpszDest);
214static BOOL FTP_FtpRemoveDirectoryW(ftp_session_t*, LPCWSTR lpszDirectory);
215static BOOL FTP_FtpDeleteFileW(ftp_session_t*, LPCWSTR lpszFileName);
216static 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 */
221static 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 */
238BOOL 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
254static 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 278BOOL 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
337lend:
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 353static 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 428BOOL 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
440static 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
461BOOL 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
506lend:
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 524static 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
550lend:
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 574BOOL 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
586static 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
607BOOL 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 655lend:
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 672static 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
695lend:
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 720HINTERNET 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
740static 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 762HINTERNET 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
804lend:
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 822static 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
868lend:
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 908BOOL 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
938static 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
958BOOL 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
1018lend:
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 1036static 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
1085lend:
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 1107static 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 1132static 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 1180static 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 1204static 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 1210static 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 1216static 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 1227static 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
1249static 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 1256static 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 1296static 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 1319static 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 */
1448HINTERNET 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
1462static 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 */
1484HINTERNET 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
1544lend:
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 1561BOOL 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
1579static 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
1604BOOL 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
1667lend:
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 1684static 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
1754DWORD 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 1774BOOL 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
1785static 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
1806BOOL 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
1855lend:
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 1871BOOL 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 }
1893lend:
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 1919BOOL 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
1930static 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
1951BOOL 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
2000lend:
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 2016BOOL 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
2039lend:
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 2065BOOL 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
2079static 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
2101BOOL 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
2151lend:
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 2167BOOL 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
2195lend:
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
2213BOOL 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
2249BOOL 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
2324lend:
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 2336static 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 2349static 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 2374static 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 2391static 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 2424HINTERNET 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
2580lerror:
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 2602static 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);
2630lend:
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 2645static 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 2700static 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 2720INT 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
2767lerror:
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 2783static 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
2807lend:
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 2823static 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
2838lend:
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 2853static 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
2879lend:
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 2900static 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
2935lend:
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 2959static 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
2981lend:
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 2997static 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
3025lend:
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 3041static 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
3069lend:
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 3085static 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
3152lend:
3153 return bSuccess;
3154}
3155
3156
8adbf8ce 3157static 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 3186static 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 3217static 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 3298static 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
3323lend:
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 3344static 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
3373recv_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 3384static 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 3401static 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 3434static 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 3441static 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 3458static 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 3480static 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 3503static 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 3547static 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 3584static 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 3745static 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 3810static 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 3873static 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}