gdi32: Don't hold the gdi lock while creating a DC.
[wine/multimedia.git] / dlls / wininet / ftp.c
blob805ab44a2625cd08a433633c781bc4a691277498
1 /*
2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
8 * Ulrich Czekalla
9 * Noureddine Jemmali
11 * Copyright 2000 Andreas Mohr
12 * Copyright 2002 Jaco Greeff
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "config.h"
30 #include "wine/port.h"
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
40 #endif
41 #ifdef HAVE_UNISTD_H
42 # include <unistd.h>
43 #endif
44 #include <time.h>
45 #include <assert.h>
47 #include "windef.h"
48 #include "winbase.h"
49 #include "wingdi.h"
50 #include "winuser.h"
51 #include "wininet.h"
52 #include "winnls.h"
53 #include "winerror.h"
54 #include "winreg.h"
55 #include "winternl.h"
56 #include "shlwapi.h"
58 #include "wine/debug.h"
59 #include "internet.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
63 #define DATA_PACKET_SIZE 0x2000
64 #define szCRLF "\r\n"
65 #define MAX_BACKLOG 5
67 /* Testing shows that Windows only accepts dwFlags where the last
68 * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY.
70 #define FTP_CONDITION_MASK 0x0007
72 typedef enum {
73 /* FTP commands with arguments. */
74 FTP_CMD_ACCT,
75 FTP_CMD_CWD,
76 FTP_CMD_DELE,
77 FTP_CMD_MKD,
78 FTP_CMD_PASS,
79 FTP_CMD_PORT,
80 FTP_CMD_RETR,
81 FTP_CMD_RMD,
82 FTP_CMD_RNFR,
83 FTP_CMD_RNTO,
84 FTP_CMD_STOR,
85 FTP_CMD_TYPE,
86 FTP_CMD_USER,
87 FTP_CMD_SIZE,
89 /* FTP commands without arguments. */
90 FTP_CMD_ABOR,
91 FTP_CMD_LIST,
92 FTP_CMD_NLST,
93 FTP_CMD_PASV,
94 FTP_CMD_PWD,
95 FTP_CMD_QUIT,
96 } FTP_COMMAND;
98 static const CHAR *const szFtpCommands[] = {
99 "ACCT",
100 "CWD",
101 "DELE",
102 "MKD",
103 "PASS",
104 "PORT",
105 "RETR",
106 "RMD",
107 "RNFR",
108 "RNTO",
109 "STOR",
110 "TYPE",
111 "USER",
112 "SIZE",
113 "ABOR",
114 "LIST",
115 "NLST",
116 "PASV",
117 "PWD",
118 "QUIT",
121 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
122 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
124 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
125 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
126 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
127 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
128 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext);
129 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
130 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
131 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
132 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext);
133 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
134 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
135 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
136 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
137 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
140 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
141 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
142 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
143 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
144 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
145 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
146 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
147 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
148 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext);
149 static DWORD FTP_SetResponseError(DWORD dwResponse);
151 /***********************************************************************
152 * FtpPutFileA (WININET.@)
154 * Uploads a file to the FTP server
156 * RETURNS
157 * TRUE on success
158 * FALSE on failure
161 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
162 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
164 LPWSTR lpwzLocalFile;
165 LPWSTR lpwzNewRemoteFile;
166 BOOL ret;
168 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
169 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
170 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
171 dwFlags, dwContext);
172 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
173 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
174 return ret;
177 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
179 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
180 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
182 TRACE("%p\n", lpwfs);
184 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
185 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
187 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
188 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
191 /***********************************************************************
192 * FtpPutFileW (WININET.@)
194 * Uploads a file to the FTP server
196 * RETURNS
197 * TRUE on success
198 * FALSE on failure
201 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
202 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
204 LPWININETFTPSESSIONW lpwfs;
205 LPWININETAPPINFOW hIC = NULL;
206 BOOL r = FALSE;
208 if (!lpszLocalFile || !lpszNewRemoteFile)
210 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
211 return FALSE;
214 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
215 if (!lpwfs)
217 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
218 return FALSE;
221 if (WH_HFTPSESSION != lpwfs->hdr.htype)
223 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
224 goto lend;
227 if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
229 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
230 goto lend;
233 hIC = lpwfs->lpAppInfo;
234 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
236 WORKREQUEST workRequest;
237 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
239 workRequest.asyncproc = AsyncFtpPutFileProc;
240 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
241 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
242 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
243 req->dwFlags = dwFlags;
244 req->dwContext = dwContext;
246 r = INTERNET_AsyncCall(&workRequest);
248 else
250 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
251 lpszNewRemoteFile, dwFlags, dwContext);
254 lend:
255 WININET_Release( &lpwfs->hdr );
257 return r;
260 /***********************************************************************
261 * FTP_FtpPutFileW (Internal)
263 * Uploads a file to the FTP server
265 * RETURNS
266 * TRUE on success
267 * FALSE on failure
270 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
271 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
273 HANDLE hFile;
274 BOOL bSuccess = FALSE;
275 LPWININETAPPINFOW hIC = NULL;
276 INT nResCode;
278 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
280 /* Clear any error information */
281 INTERNET_SetLastError(0);
283 /* Open file to be uploaded */
284 if (INVALID_HANDLE_VALUE ==
285 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
286 /* Let CreateFile set the appropriate error */
287 return FALSE;
289 hIC = lpwfs->lpAppInfo;
291 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
293 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
295 INT nDataSocket;
297 /* Get data socket to server */
298 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
300 FTP_SendData(lpwfs, nDataSocket, hFile);
301 closesocket(nDataSocket);
302 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
303 if (nResCode)
305 if (nResCode == 226)
306 bSuccess = TRUE;
307 else
308 FTP_SetResponseError(nResCode);
313 if (lpwfs->lstnSocket != -1)
314 closesocket(lpwfs->lstnSocket);
316 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
318 INTERNET_ASYNC_RESULT iar;
320 iar.dwResult = (DWORD)bSuccess;
321 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
322 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
323 &iar, sizeof(INTERNET_ASYNC_RESULT));
326 CloseHandle(hFile);
328 return bSuccess;
332 /***********************************************************************
333 * FtpSetCurrentDirectoryA (WININET.@)
335 * Change the working directory on the FTP server
337 * RETURNS
338 * TRUE on success
339 * FALSE on failure
342 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
344 LPWSTR lpwzDirectory;
345 BOOL ret;
347 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
348 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
349 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
350 return ret;
354 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
356 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
357 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
359 TRACE("%p\n", lpwfs);
361 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
362 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
365 /***********************************************************************
366 * FtpSetCurrentDirectoryW (WININET.@)
368 * Change the working directory on the FTP server
370 * RETURNS
371 * TRUE on success
372 * FALSE on failure
375 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
377 LPWININETFTPSESSIONW lpwfs = NULL;
378 LPWININETAPPINFOW hIC = NULL;
379 BOOL r = FALSE;
381 if (!lpszDirectory)
383 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
384 goto lend;
387 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
388 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
390 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
391 goto lend;
394 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
396 hIC = lpwfs->lpAppInfo;
397 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
399 WORKREQUEST workRequest;
400 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
402 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
403 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
404 req = &workRequest.u.FtpSetCurrentDirectoryW;
405 req->lpszDirectory = WININET_strdupW(lpszDirectory);
407 r = INTERNET_AsyncCall(&workRequest);
409 else
411 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
414 lend:
415 if( lpwfs )
416 WININET_Release( &lpwfs->hdr );
418 return r;
422 /***********************************************************************
423 * FTP_FtpSetCurrentDirectoryW (Internal)
425 * Change the working directory on the FTP server
427 * RETURNS
428 * TRUE on success
429 * FALSE on failure
432 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
434 INT nResCode;
435 LPWININETAPPINFOW hIC = NULL;
436 DWORD bSuccess = FALSE;
438 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
440 /* Clear any error information */
441 INTERNET_SetLastError(0);
443 hIC = lpwfs->lpAppInfo;
444 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
445 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
446 goto lend;
448 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
450 if (nResCode)
452 if (nResCode == 250)
453 bSuccess = TRUE;
454 else
455 FTP_SetResponseError(nResCode);
458 lend:
459 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
461 INTERNET_ASYNC_RESULT iar;
463 iar.dwResult = (DWORD)bSuccess;
464 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
465 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
466 &iar, sizeof(INTERNET_ASYNC_RESULT));
468 return bSuccess;
472 /***********************************************************************
473 * FtpCreateDirectoryA (WININET.@)
475 * Create new directory on the FTP server
477 * RETURNS
478 * TRUE on success
479 * FALSE on failure
482 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
484 LPWSTR lpwzDirectory;
485 BOOL ret;
487 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
488 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
489 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
490 return ret;
494 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
496 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
497 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
499 TRACE(" %p\n", lpwfs);
501 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
502 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
505 /***********************************************************************
506 * FtpCreateDirectoryW (WININET.@)
508 * Create new directory on the FTP server
510 * RETURNS
511 * TRUE on success
512 * FALSE on failure
515 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
517 LPWININETFTPSESSIONW lpwfs;
518 LPWININETAPPINFOW hIC = NULL;
519 BOOL r = FALSE;
521 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
522 if (!lpwfs)
524 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
525 return FALSE;
528 if (WH_HFTPSESSION != lpwfs->hdr.htype)
530 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
531 goto lend;
534 if (!lpszDirectory)
536 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
537 goto lend;
540 hIC = lpwfs->lpAppInfo;
541 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
543 WORKREQUEST workRequest;
544 struct WORKREQ_FTPCREATEDIRECTORYW *req;
546 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
547 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
548 req = &workRequest.u.FtpCreateDirectoryW;
549 req->lpszDirectory = WININET_strdupW(lpszDirectory);
551 r = INTERNET_AsyncCall(&workRequest);
553 else
555 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
557 lend:
558 WININET_Release( &lpwfs->hdr );
560 return r;
564 /***********************************************************************
565 * FTP_FtpCreateDirectoryW (Internal)
567 * Create new directory on the FTP server
569 * RETURNS
570 * TRUE on success
571 * FALSE on failure
574 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
576 INT nResCode;
577 BOOL bSuccess = FALSE;
578 LPWININETAPPINFOW hIC = NULL;
580 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
582 /* Clear any error information */
583 INTERNET_SetLastError(0);
585 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
586 goto lend;
588 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
589 if (nResCode)
591 if (nResCode == 257)
592 bSuccess = TRUE;
593 else
594 FTP_SetResponseError(nResCode);
597 lend:
598 hIC = lpwfs->lpAppInfo;
599 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
601 INTERNET_ASYNC_RESULT iar;
603 iar.dwResult = (DWORD)bSuccess;
604 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
605 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
606 &iar, sizeof(INTERNET_ASYNC_RESULT));
609 return bSuccess;
612 /***********************************************************************
613 * FtpFindFirstFileA (WININET.@)
615 * Search the specified directory
617 * RETURNS
618 * HINTERNET on success
619 * NULL on failure
622 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
623 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
625 LPWSTR lpwzSearchFile;
626 WIN32_FIND_DATAW wfd;
627 LPWIN32_FIND_DATAW lpFindFileDataW;
628 HINTERNET ret;
630 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
631 lpFindFileDataW = lpFindFileData?&wfd:NULL;
632 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
633 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
635 if(lpFindFileData) {
636 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
638 return ret;
642 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
644 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
645 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
647 TRACE("%p\n", lpwfs);
649 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
650 req->lpFindFileData, req->dwFlags, req->dwContext);
651 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
654 /***********************************************************************
655 * FtpFindFirstFileW (WININET.@)
657 * Search the specified directory
659 * RETURNS
660 * HINTERNET on success
661 * NULL on failure
664 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
665 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
667 LPWININETFTPSESSIONW lpwfs;
668 LPWININETAPPINFOW hIC = NULL;
669 HINTERNET r = NULL;
671 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
672 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
674 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
675 goto lend;
678 hIC = lpwfs->lpAppInfo;
679 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
681 WORKREQUEST workRequest;
682 struct WORKREQ_FTPFINDFIRSTFILEW *req;
684 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
685 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
686 req = &workRequest.u.FtpFindFirstFileW;
687 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
688 req->lpFindFileData = lpFindFileData;
689 req->dwFlags = dwFlags;
690 req->dwContext= dwContext;
692 INTERNET_AsyncCall(&workRequest);
693 r = NULL;
695 else
697 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
698 dwFlags, dwContext);
700 lend:
701 if( lpwfs )
702 WININET_Release( &lpwfs->hdr );
704 return r;
708 /***********************************************************************
709 * FTP_FtpFindFirstFileW (Internal)
711 * Search the specified directory
713 * RETURNS
714 * HINTERNET on success
715 * NULL on failure
718 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
719 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
721 INT nResCode;
722 LPWININETAPPINFOW hIC = NULL;
723 HINTERNET hFindNext = NULL;
725 TRACE("\n");
727 /* Clear any error information */
728 INTERNET_SetLastError(0);
730 if (!FTP_InitListenSocket(lpwfs))
731 goto lend;
733 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
734 goto lend;
736 if (!FTP_SendPortOrPasv(lpwfs))
737 goto lend;
739 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
740 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
741 goto lend;
743 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
744 if (nResCode)
746 if (nResCode == 125 || nResCode == 150)
748 INT nDataSocket;
750 /* Get data socket to server */
751 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
753 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
754 closesocket(nDataSocket);
755 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
756 if (nResCode != 226 && nResCode != 250)
757 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
760 else
761 FTP_SetResponseError(nResCode);
764 lend:
765 if (lpwfs->lstnSocket != -1)
766 closesocket(lpwfs->lstnSocket);
768 hIC = lpwfs->lpAppInfo;
769 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
771 INTERNET_ASYNC_RESULT iar;
773 if (hFindNext)
775 iar.dwResult = (DWORD)hFindNext;
776 iar.dwError = ERROR_SUCCESS;
777 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
778 &iar, sizeof(INTERNET_ASYNC_RESULT));
781 iar.dwResult = (DWORD)hFindNext;
782 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
783 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
784 &iar, sizeof(INTERNET_ASYNC_RESULT));
787 return hFindNext;
791 /***********************************************************************
792 * FtpGetCurrentDirectoryA (WININET.@)
794 * Retrieves the current directory
796 * RETURNS
797 * TRUE on success
798 * FALSE on failure
801 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
802 LPDWORD lpdwCurrentDirectory)
804 WCHAR *dir = NULL;
805 DWORD len;
806 BOOL ret;
808 if(lpdwCurrentDirectory) {
809 len = *lpdwCurrentDirectory;
810 if(lpszCurrentDirectory)
812 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
813 if (NULL == dir)
815 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
816 return FALSE;
820 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
821 if(lpdwCurrentDirectory) {
822 *lpdwCurrentDirectory = len;
823 if(lpszCurrentDirectory) {
824 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
825 HeapFree(GetProcessHeap(), 0, dir);
828 return ret;
832 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
834 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
835 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
837 TRACE("%p\n", lpwfs);
839 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
842 /***********************************************************************
843 * FtpGetCurrentDirectoryW (WININET.@)
845 * Retrieves the current directory
847 * RETURNS
848 * TRUE on success
849 * FALSE on failure
852 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
853 LPDWORD lpdwCurrentDirectory)
855 LPWININETFTPSESSIONW lpwfs;
856 LPWININETAPPINFOW hIC = NULL;
857 BOOL r = FALSE;
859 TRACE("len(%d)\n", *lpdwCurrentDirectory);
861 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
862 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
864 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
865 goto lend;
868 hIC = lpwfs->lpAppInfo;
869 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
871 WORKREQUEST workRequest;
872 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
874 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
875 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
876 req = &workRequest.u.FtpGetCurrentDirectoryW;
877 req->lpszDirectory = lpszCurrentDirectory;
878 req->lpdwDirectory = lpdwCurrentDirectory;
880 r = INTERNET_AsyncCall(&workRequest);
882 else
884 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
885 lpdwCurrentDirectory);
888 lend:
889 if( lpwfs )
890 WININET_Release( &lpwfs->hdr );
892 return r;
896 /***********************************************************************
897 * FTP_FtpGetCurrentDirectoryW (Internal)
899 * Retrieves the current directory
901 * RETURNS
902 * TRUE on success
903 * FALSE on failure
906 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
907 LPDWORD lpdwCurrentDirectory)
909 INT nResCode;
910 LPWININETAPPINFOW hIC = NULL;
911 DWORD bSuccess = FALSE;
913 TRACE("len(%d)\n", *lpdwCurrentDirectory);
915 /* Clear any error information */
916 INTERNET_SetLastError(0);
918 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
920 hIC = lpwfs->lpAppInfo;
921 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
922 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
923 goto lend;
925 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
926 if (nResCode)
928 if (nResCode == 257) /* Extract directory name */
930 DWORD firstpos, lastpos, len;
931 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
933 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
935 if ('"' == lpszResponseBuffer[lastpos])
937 if (!firstpos)
938 firstpos = lastpos;
939 else
940 break;
944 len = lastpos - firstpos - 1;
945 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
946 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
947 *lpdwCurrentDirectory = len;
948 bSuccess = TRUE;
950 else
951 FTP_SetResponseError(nResCode);
954 lend:
955 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
957 INTERNET_ASYNC_RESULT iar;
959 iar.dwResult = (DWORD)bSuccess;
960 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
961 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
962 &iar, sizeof(INTERNET_ASYNC_RESULT));
965 return (DWORD) bSuccess;
968 /***********************************************************************
969 * FtpOpenFileA (WININET.@)
971 * Open a remote file for writing or reading
973 * RETURNS
974 * HINTERNET handle on success
975 * NULL on failure
978 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
979 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
980 DWORD_PTR dwContext)
982 LPWSTR lpwzFileName;
983 HINTERNET ret;
985 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
986 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
987 HeapFree(GetProcessHeap(), 0, lpwzFileName);
988 return ret;
992 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
994 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
995 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
997 TRACE("%p\n", lpwfs);
999 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1000 req->dwAccess, req->dwFlags, req->dwContext);
1001 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1004 /***********************************************************************
1005 * FtpOpenFileW (WININET.@)
1007 * Open a remote file for writing or reading
1009 * RETURNS
1010 * HINTERNET handle on success
1011 * NULL on failure
1014 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1015 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1016 DWORD_PTR dwContext)
1018 LPWININETFTPSESSIONW lpwfs;
1019 LPWININETAPPINFOW hIC = NULL;
1020 HINTERNET r = NULL;
1022 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession,
1023 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1025 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1026 if (!lpwfs)
1028 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1029 return FALSE;
1032 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1034 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1035 goto lend;
1038 if ((!lpszFileName) ||
1039 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1040 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1042 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1043 goto lend;
1046 if (lpwfs->download_in_progress != NULL) {
1047 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1048 goto lend;
1050 hIC = lpwfs->lpAppInfo;
1051 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1053 WORKREQUEST workRequest;
1054 struct WORKREQ_FTPOPENFILEW *req;
1056 workRequest.asyncproc = AsyncFtpOpenFileProc;
1057 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1058 req = &workRequest.u.FtpOpenFileW;
1059 req->lpszFilename = WININET_strdupW(lpszFileName);
1060 req->dwAccess = fdwAccess;
1061 req->dwFlags = dwFlags;
1062 req->dwContext = dwContext;
1064 INTERNET_AsyncCall(&workRequest);
1065 r = NULL;
1067 else
1069 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1072 lend:
1073 WININET_Release( &lpwfs->hdr );
1075 return r;
1079 /***********************************************************************
1080 * FTP_FtpOpenFileW (Internal)
1082 * Open a remote file for writing or reading
1084 * RETURNS
1085 * HINTERNET handle on success
1086 * NULL on failure
1089 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1090 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1091 DWORD_PTR dwContext)
1093 INT nDataSocket;
1094 BOOL bSuccess = FALSE;
1095 LPWININETFTPFILE lpwh = NULL;
1096 LPWININETAPPINFOW hIC = NULL;
1097 HINTERNET handle = NULL;
1099 TRACE("\n");
1101 /* Clear any error information */
1102 INTERNET_SetLastError(0);
1104 if (GENERIC_READ == fdwAccess)
1106 /* Set up socket to retrieve data */
1107 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1109 else if (GENERIC_WRITE == fdwAccess)
1111 /* Set up socket to send data */
1112 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1115 /* Get data socket to server */
1116 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1118 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1119 lpwh->hdr.htype = WH_HFILE;
1120 lpwh->hdr.dwFlags = dwFlags;
1121 lpwh->hdr.dwContext = dwContext;
1122 lpwh->hdr.dwRefCount = 1;
1123 lpwh->hdr.close_connection = NULL;
1124 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1125 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1126 lpwh->nDataSocket = nDataSocket;
1127 lpwh->session_deleted = FALSE;
1129 WININET_AddRef( &lpwfs->hdr );
1130 lpwh->lpFtpSession = lpwfs;
1131 list_add_head( &lpwfs->hdr.children, &lpwh->hdr.entry );
1133 handle = WININET_AllocHandle( &lpwh->hdr );
1134 if( !handle )
1135 goto lend;
1137 /* Indicate that a download is currently in progress */
1138 lpwfs->download_in_progress = lpwh;
1141 if (lpwfs->lstnSocket != -1)
1142 closesocket(lpwfs->lstnSocket);
1144 hIC = lpwfs->lpAppInfo;
1145 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1147 INTERNET_ASYNC_RESULT iar;
1149 if (lpwh)
1151 iar.dwResult = (DWORD)handle;
1152 iar.dwError = ERROR_SUCCESS;
1153 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1154 &iar, sizeof(INTERNET_ASYNC_RESULT));
1157 iar.dwResult = (DWORD)bSuccess;
1158 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1159 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1160 &iar, sizeof(INTERNET_ASYNC_RESULT));
1163 lend:
1164 if( lpwh )
1165 WININET_Release( &lpwh->hdr );
1167 return handle;
1171 /***********************************************************************
1172 * FtpGetFileA (WININET.@)
1174 * Retrieve file from the FTP server
1176 * RETURNS
1177 * TRUE on success
1178 * FALSE on failure
1181 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1182 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1183 DWORD_PTR dwContext)
1185 LPWSTR lpwzRemoteFile;
1186 LPWSTR lpwzNewFile;
1187 BOOL ret;
1189 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1190 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1191 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1192 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1193 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1194 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1195 return ret;
1199 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1201 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1202 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1204 TRACE("%p\n", lpwfs);
1206 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1207 req->lpszNewFile, req->fFailIfExists,
1208 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1209 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1210 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1214 /***********************************************************************
1215 * FtpGetFileW (WININET.@)
1217 * Retrieve file from the FTP server
1219 * RETURNS
1220 * TRUE on success
1221 * FALSE on failure
1224 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1225 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1226 DWORD_PTR dwContext)
1228 LPWININETFTPSESSIONW lpwfs;
1229 LPWININETAPPINFOW hIC = NULL;
1230 BOOL r = FALSE;
1232 if (!lpszRemoteFile || !lpszNewFile)
1234 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1235 return FALSE;
1238 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1239 if (!lpwfs)
1241 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1242 return FALSE;
1245 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1247 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1248 goto lend;
1251 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1253 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1254 goto lend;
1257 if (lpwfs->download_in_progress != NULL) {
1258 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1259 goto lend;
1262 hIC = lpwfs->lpAppInfo;
1263 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1265 WORKREQUEST workRequest;
1266 struct WORKREQ_FTPGETFILEW *req;
1268 workRequest.asyncproc = AsyncFtpGetFileProc;
1269 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1270 req = &workRequest.u.FtpGetFileW;
1271 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1272 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1273 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1274 req->fFailIfExists = fFailIfExists;
1275 req->dwFlags = dwInternetFlags;
1276 req->dwContext = dwContext;
1278 r = INTERNET_AsyncCall(&workRequest);
1280 else
1282 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1283 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1286 lend:
1287 WININET_Release( &lpwfs->hdr );
1289 return r;
1293 /***********************************************************************
1294 * FTP_FtpGetFileW (Internal)
1296 * Retrieve file from the FTP server
1298 * RETURNS
1299 * TRUE on success
1300 * FALSE on failure
1303 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1304 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1305 DWORD_PTR dwContext)
1307 BOOL bSuccess = FALSE;
1308 HANDLE hFile;
1309 LPWININETAPPINFOW hIC = NULL;
1311 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1313 /* Clear any error information */
1314 INTERNET_SetLastError(0);
1316 /* Ensure we can write to lpszNewfile by opening it */
1317 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1318 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1319 if (INVALID_HANDLE_VALUE == hFile)
1320 return FALSE;
1322 /* Set up socket to retrieve data */
1323 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1325 INT nDataSocket;
1327 /* Get data socket to server */
1328 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1330 INT nResCode;
1332 /* Receive data */
1333 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1334 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1335 if (nResCode)
1337 if (nResCode == 226)
1338 bSuccess = TRUE;
1339 else
1340 FTP_SetResponseError(nResCode);
1342 closesocket(nDataSocket);
1346 if (lpwfs->lstnSocket != -1)
1347 closesocket(lpwfs->lstnSocket);
1349 CloseHandle(hFile);
1351 hIC = lpwfs->lpAppInfo;
1352 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1354 INTERNET_ASYNC_RESULT iar;
1356 iar.dwResult = (DWORD)bSuccess;
1357 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1358 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1359 &iar, sizeof(INTERNET_ASYNC_RESULT));
1362 return bSuccess;
1365 /***********************************************************************
1366 * FtpGetFileSize (WININET.@)
1368 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1370 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1372 if (lpdwFileSizeHigh)
1373 *lpdwFileSizeHigh = 0;
1375 return 0;
1378 /***********************************************************************
1379 * FtpDeleteFileA (WININET.@)
1381 * Delete a file on the ftp server
1383 * RETURNS
1384 * TRUE on success
1385 * FALSE on failure
1388 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1390 LPWSTR lpwzFileName;
1391 BOOL ret;
1393 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1394 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1395 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1396 return ret;
1399 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1401 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1402 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1404 TRACE("%p\n", lpwfs);
1406 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1407 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1410 /***********************************************************************
1411 * FtpDeleteFileW (WININET.@)
1413 * Delete a file on the ftp server
1415 * RETURNS
1416 * TRUE on success
1417 * FALSE on failure
1420 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1422 LPWININETFTPSESSIONW lpwfs;
1423 LPWININETAPPINFOW hIC = NULL;
1424 BOOL r = FALSE;
1426 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1427 if (!lpwfs)
1429 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1430 return FALSE;
1433 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1435 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1436 goto lend;
1439 if (!lpszFileName)
1441 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1442 goto lend;
1445 hIC = lpwfs->lpAppInfo;
1446 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1448 WORKREQUEST workRequest;
1449 struct WORKREQ_FTPDELETEFILEW *req;
1451 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1452 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1453 req = &workRequest.u.FtpDeleteFileW;
1454 req->lpszFilename = WININET_strdupW(lpszFileName);
1456 r = INTERNET_AsyncCall(&workRequest);
1458 else
1460 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1463 lend:
1464 WININET_Release( &lpwfs->hdr );
1466 return r;
1469 /***********************************************************************
1470 * FTP_FtpDeleteFileW (Internal)
1472 * Delete a file on the ftp server
1474 * RETURNS
1475 * TRUE on success
1476 * FALSE on failure
1479 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1481 INT nResCode;
1482 BOOL bSuccess = FALSE;
1483 LPWININETAPPINFOW hIC = NULL;
1485 TRACE("%p\n", lpwfs);
1487 /* Clear any error information */
1488 INTERNET_SetLastError(0);
1490 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1491 goto lend;
1493 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1494 if (nResCode)
1496 if (nResCode == 250)
1497 bSuccess = TRUE;
1498 else
1499 FTP_SetResponseError(nResCode);
1501 lend:
1502 hIC = lpwfs->lpAppInfo;
1503 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1505 INTERNET_ASYNC_RESULT iar;
1507 iar.dwResult = (DWORD)bSuccess;
1508 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1509 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1510 &iar, sizeof(INTERNET_ASYNC_RESULT));
1513 return bSuccess;
1517 /***********************************************************************
1518 * FtpRemoveDirectoryA (WININET.@)
1520 * Remove a directory on the ftp server
1522 * RETURNS
1523 * TRUE on success
1524 * FALSE on failure
1527 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1529 LPWSTR lpwzDirectory;
1530 BOOL ret;
1532 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1533 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1534 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1535 return ret;
1538 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1540 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1541 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1543 TRACE("%p\n", lpwfs);
1545 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1546 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1549 /***********************************************************************
1550 * FtpRemoveDirectoryW (WININET.@)
1552 * Remove a directory on the ftp server
1554 * RETURNS
1555 * TRUE on success
1556 * FALSE on failure
1559 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1561 LPWININETFTPSESSIONW lpwfs;
1562 LPWININETAPPINFOW hIC = NULL;
1563 BOOL r = FALSE;
1565 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1566 if (!lpwfs)
1568 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1569 return FALSE;
1572 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1574 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1575 goto lend;
1578 if (!lpszDirectory)
1580 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1581 goto lend;
1584 hIC = lpwfs->lpAppInfo;
1585 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1587 WORKREQUEST workRequest;
1588 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1590 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1591 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1592 req = &workRequest.u.FtpRemoveDirectoryW;
1593 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1595 r = INTERNET_AsyncCall(&workRequest);
1597 else
1599 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1602 lend:
1603 WININET_Release( &lpwfs->hdr );
1605 return r;
1608 /***********************************************************************
1609 * FTP_FtpRemoveDirectoryW (Internal)
1611 * Remove a directory on the ftp server
1613 * RETURNS
1614 * TRUE on success
1615 * FALSE on failure
1618 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1620 INT nResCode;
1621 BOOL bSuccess = FALSE;
1622 LPWININETAPPINFOW hIC = NULL;
1624 TRACE("\n");
1626 /* Clear any error information */
1627 INTERNET_SetLastError(0);
1629 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1630 goto lend;
1632 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1633 if (nResCode)
1635 if (nResCode == 250)
1636 bSuccess = TRUE;
1637 else
1638 FTP_SetResponseError(nResCode);
1641 lend:
1642 hIC = lpwfs->lpAppInfo;
1643 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1645 INTERNET_ASYNC_RESULT iar;
1647 iar.dwResult = (DWORD)bSuccess;
1648 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1649 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1650 &iar, sizeof(INTERNET_ASYNC_RESULT));
1653 return bSuccess;
1657 /***********************************************************************
1658 * FtpRenameFileA (WININET.@)
1660 * Rename a file on the ftp server
1662 * RETURNS
1663 * TRUE on success
1664 * FALSE on failure
1667 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1669 LPWSTR lpwzSrc;
1670 LPWSTR lpwzDest;
1671 BOOL ret;
1673 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1674 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1675 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1676 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1677 HeapFree(GetProcessHeap(), 0, lpwzDest);
1678 return ret;
1681 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1683 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1684 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1686 TRACE("%p\n", lpwfs);
1688 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1689 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1690 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1693 /***********************************************************************
1694 * FtpRenameFileW (WININET.@)
1696 * Rename a file on the ftp server
1698 * RETURNS
1699 * TRUE on success
1700 * FALSE on failure
1703 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1705 LPWININETFTPSESSIONW lpwfs;
1706 LPWININETAPPINFOW hIC = NULL;
1707 BOOL r = FALSE;
1709 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1710 if (!lpwfs)
1712 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1713 return FALSE;
1716 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1718 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1719 goto lend;
1722 if (!lpszSrc || !lpszDest)
1724 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1725 goto lend;
1728 hIC = lpwfs->lpAppInfo;
1729 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1731 WORKREQUEST workRequest;
1732 struct WORKREQ_FTPRENAMEFILEW *req;
1734 workRequest.asyncproc = AsyncFtpRenameFileProc;
1735 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1736 req = &workRequest.u.FtpRenameFileW;
1737 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1738 req->lpszDestFile = WININET_strdupW(lpszDest);
1740 r = INTERNET_AsyncCall(&workRequest);
1742 else
1744 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1747 lend:
1748 WININET_Release( &lpwfs->hdr );
1750 return r;
1753 /***********************************************************************
1754 * FTP_FtpRenameFileW (Internal)
1756 * Rename a file on the ftp server
1758 * RETURNS
1759 * TRUE on success
1760 * FALSE on failure
1763 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1764 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1766 INT nResCode;
1767 BOOL bSuccess = FALSE;
1768 LPWININETAPPINFOW hIC = NULL;
1770 TRACE("\n");
1772 /* Clear any error information */
1773 INTERNET_SetLastError(0);
1775 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1776 goto lend;
1778 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1779 if (nResCode == 350)
1781 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1782 goto lend;
1784 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1787 if (nResCode == 250)
1788 bSuccess = TRUE;
1789 else
1790 FTP_SetResponseError(nResCode);
1792 lend:
1793 hIC = lpwfs->lpAppInfo;
1794 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1796 INTERNET_ASYNC_RESULT iar;
1798 iar.dwResult = (DWORD)bSuccess;
1799 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1800 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1801 &iar, sizeof(INTERNET_ASYNC_RESULT));
1804 return bSuccess;
1807 /***********************************************************************
1808 * FtpCommandA (WININET.@)
1810 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1811 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1813 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1814 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1816 return TRUE;
1819 /***********************************************************************
1820 * FtpCommandW (WININET.@)
1822 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1823 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1825 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1826 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1828 return TRUE;
1831 /***********************************************************************
1832 * FTP_Connect (internal)
1834 * Connect to a ftp server
1836 * RETURNS
1837 * HINTERNET a session handle on success
1838 * NULL on failure
1840 * NOTES:
1842 * Windows uses 'anonymous' as the username, when given a NULL username
1843 * and a NULL password. The password is first looked up in:
1845 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1847 * If this entry is not present it uses the current username as the password.
1851 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1852 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1853 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
1854 DWORD dwInternalFlags)
1856 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1857 'M','i','c','r','o','s','o','f','t','\\',
1858 'W','i','n','d','o','w','s','\\',
1859 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1860 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1861 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1862 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1863 static const WCHAR szEmpty[] = {'\0'};
1864 struct sockaddr_in socketAddr;
1865 INT nsocket = -1;
1866 UINT sock_namelen;
1867 BOOL bSuccess = FALSE;
1868 LPWININETFTPSESSIONW lpwfs = NULL;
1869 HINTERNET handle = NULL;
1871 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1872 hIC, debugstr_w(lpszServerName),
1873 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1875 assert( hIC->hdr.htype == WH_HINIT );
1877 if (NULL == lpszUserName && NULL != lpszPassword)
1879 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1880 goto lerror;
1883 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1884 if (NULL == lpwfs)
1886 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1887 goto lerror;
1890 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1891 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1893 lpwfs->hdr.htype = WH_HFTPSESSION;
1894 lpwfs->hdr.dwFlags = dwFlags;
1895 lpwfs->hdr.dwContext = dwContext;
1896 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1897 lpwfs->hdr.dwRefCount = 1;
1898 /* FIXME: Native sends INTERNET_STATUS_CLOSING_CONNECTION and
1899 * INTERNET_STATUS_CONNECTION_CLOSED, need an equivalent FTP_CloseConnection
1900 * function */
1901 lpwfs->hdr.close_connection = NULL;
1902 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1903 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1904 lpwfs->download_in_progress = NULL;
1906 WININET_AddRef( &hIC->hdr );
1907 lpwfs->lpAppInfo = hIC;
1908 list_add_head( &hIC->hdr.children, &lpwfs->hdr.entry );
1910 handle = WININET_AllocHandle( &lpwfs->hdr );
1911 if( !handle )
1913 ERR("Failed to alloc handle\n");
1914 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1915 goto lerror;
1918 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1919 if(strchrW(hIC->lpszProxy, ' '))
1920 FIXME("Several proxies not implemented.\n");
1921 if(hIC->lpszProxyBypass)
1922 FIXME("Proxy bypass is ignored.\n");
1924 if ( !lpszUserName) {
1925 HKEY key;
1926 WCHAR szPassword[MAX_PATH];
1927 DWORD len = sizeof(szPassword);
1929 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1931 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1932 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1933 /* Nothing in the registry, get the username and use that as the password */
1934 if (!GetUserNameW(szPassword, &len)) {
1935 /* Should never get here, but use an empty password as failsafe */
1936 strcpyW(szPassword, szEmpty);
1939 RegCloseKey(key);
1941 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1942 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1944 else {
1945 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1947 if (lpszPassword)
1948 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1949 else
1950 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1953 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1954 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1956 INTERNET_ASYNC_RESULT iar;
1958 iar.dwResult = (DWORD)handle;
1959 iar.dwError = ERROR_SUCCESS;
1961 SendAsyncCallback(&hIC->hdr, dwContext,
1962 INTERNET_STATUS_HANDLE_CREATED, &iar,
1963 sizeof(INTERNET_ASYNC_RESULT));
1966 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1967 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1969 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1971 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1972 goto lerror;
1975 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1976 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1978 nsocket = socket(AF_INET,SOCK_STREAM,0);
1979 if (nsocket == -1)
1981 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1982 goto lerror;
1985 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1986 &socketAddr, sizeof(struct sockaddr_in));
1988 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1990 ERR("Unable to connect (%s)\n", strerror(errno));
1991 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1993 else
1995 TRACE("Connected to server\n");
1996 lpwfs->sndSocket = nsocket;
1997 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1998 &socketAddr, sizeof(struct sockaddr_in));
2000 sock_namelen = sizeof(lpwfs->socketAddress);
2001 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2003 if (FTP_ConnectToHost(lpwfs))
2005 TRACE("Successfully logged into server\n");
2006 bSuccess = TRUE;
2010 lerror:
2011 if (!bSuccess && nsocket != -1)
2012 closesocket(nsocket);
2014 if (!bSuccess && lpwfs)
2016 HeapFree(GetProcessHeap(), 0, lpwfs);
2017 WININET_FreeHandle( handle );
2018 handle = NULL;
2019 lpwfs = NULL;
2022 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2024 INTERNET_ASYNC_RESULT iar;
2026 iar.dwResult = (DWORD)lpwfs;
2027 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2028 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2029 &iar, sizeof(INTERNET_ASYNC_RESULT));
2032 return handle;
2036 /***********************************************************************
2037 * FTP_ConnectToHost (internal)
2039 * Connect to a ftp server
2041 * RETURNS
2042 * TRUE on success
2043 * NULL on failure
2046 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2048 INT nResCode;
2049 BOOL bSuccess = FALSE;
2051 TRACE("\n");
2052 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2054 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2055 goto lend;
2057 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2058 if (nResCode)
2060 /* Login successful... */
2061 if (nResCode == 230)
2062 bSuccess = TRUE;
2063 /* User name okay, need password... */
2064 else if (nResCode == 331)
2065 bSuccess = FTP_SendPassword(lpwfs);
2066 /* Need account for login... */
2067 else if (nResCode == 332)
2068 bSuccess = FTP_SendAccount(lpwfs);
2069 else
2070 FTP_SetResponseError(nResCode);
2073 TRACE("Returning %d\n", bSuccess);
2074 lend:
2075 return bSuccess;
2079 /***********************************************************************
2080 * FTP_SendCommandA (internal)
2082 * Send command to server
2084 * RETURNS
2085 * TRUE on success
2086 * NULL on failure
2089 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2090 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2092 DWORD len;
2093 CHAR *buf;
2094 DWORD nBytesSent = 0;
2095 int nRC = 0;
2096 DWORD dwParamLen;
2098 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2100 if (lpfnStatusCB)
2102 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2105 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2106 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2107 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2109 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2110 return FALSE;
2112 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2113 dwParamLen ? lpszParam : "", szCRLF);
2115 TRACE("Sending (%s) len(%d)\n", buf, len);
2116 while((nBytesSent < len) && (nRC != -1))
2118 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2119 nBytesSent += nRC;
2122 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2124 if (lpfnStatusCB)
2126 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2127 &nBytesSent, sizeof(DWORD));
2130 TRACE("Sent %d bytes\n", nBytesSent);
2131 return (nRC != -1);
2134 /***********************************************************************
2135 * FTP_SendCommand (internal)
2137 * Send command to server
2139 * RETURNS
2140 * TRUE on success
2141 * NULL on failure
2144 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2145 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2147 BOOL ret;
2148 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2149 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2150 HeapFree(GetProcessHeap(), 0, lpszParamA);
2151 return ret;
2154 /***********************************************************************
2155 * FTP_ReceiveResponse (internal)
2157 * Receive response from server
2159 * RETURNS
2160 * Reply code on success
2161 * 0 on failure
2164 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext)
2166 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2167 DWORD nRecv;
2168 INT rc = 0;
2169 char firstprefix[5];
2170 BOOL multiline = FALSE;
2171 LPWININETAPPINFOW hIC = NULL;
2173 TRACE("socket(%d)\n", lpwfs->sndSocket);
2175 hIC = lpwfs->lpAppInfo;
2176 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2178 while(1)
2180 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2181 goto lerror;
2183 if (nRecv >= 3)
2185 if(!multiline)
2187 if(lpszResponse[3] != '-')
2188 break;
2189 else
2190 { /* Start of multiline repsonse. Loop until we get "nnn " */
2191 multiline = TRUE;
2192 memcpy(firstprefix, lpszResponse, 3);
2193 firstprefix[3] = ' ';
2194 firstprefix[4] = '\0';
2197 else
2199 if(!memcmp(firstprefix, lpszResponse, 4))
2200 break;
2205 if (nRecv >= 3)
2207 rc = atoi(lpszResponse);
2209 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2210 &nRecv, sizeof(DWORD));
2213 lerror:
2214 TRACE("return %d\n", rc);
2215 return rc;
2219 /***********************************************************************
2220 * FTP_SendPassword (internal)
2222 * Send password to ftp server
2224 * RETURNS
2225 * TRUE on success
2226 * NULL on failure
2229 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2231 INT nResCode;
2232 BOOL bSuccess = FALSE;
2234 TRACE("\n");
2235 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2236 goto lend;
2238 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2239 if (nResCode)
2241 TRACE("Received reply code %d\n", nResCode);
2242 /* Login successful... */
2243 if (nResCode == 230)
2244 bSuccess = TRUE;
2245 /* Command not implemented, superfluous at the server site... */
2246 /* Need account for login... */
2247 else if (nResCode == 332)
2248 bSuccess = FTP_SendAccount(lpwfs);
2249 else
2250 FTP_SetResponseError(nResCode);
2253 lend:
2254 TRACE("Returning %d\n", bSuccess);
2255 return bSuccess;
2259 /***********************************************************************
2260 * FTP_SendAccount (internal)
2264 * RETURNS
2265 * TRUE on success
2266 * FALSE on failure
2269 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2271 INT nResCode;
2272 BOOL bSuccess = FALSE;
2274 TRACE("\n");
2275 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2276 goto lend;
2278 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2279 if (nResCode)
2280 bSuccess = TRUE;
2281 else
2282 FTP_SetResponseError(nResCode);
2284 lend:
2285 return bSuccess;
2289 /***********************************************************************
2290 * FTP_SendStore (internal)
2292 * Send request to upload file to ftp server
2294 * RETURNS
2295 * TRUE on success
2296 * FALSE on failure
2299 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2301 INT nResCode;
2302 BOOL bSuccess = FALSE;
2304 TRACE("\n");
2305 if (!FTP_InitListenSocket(lpwfs))
2306 goto lend;
2308 if (!FTP_SendType(lpwfs, dwType))
2309 goto lend;
2311 if (!FTP_SendPortOrPasv(lpwfs))
2312 goto lend;
2314 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2315 goto lend;
2316 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2317 if (nResCode)
2319 if (nResCode == 150 || nResCode == 125)
2320 bSuccess = TRUE;
2321 else
2322 FTP_SetResponseError(nResCode);
2325 lend:
2326 if (!bSuccess && lpwfs->lstnSocket != -1)
2328 closesocket(lpwfs->lstnSocket);
2329 lpwfs->lstnSocket = -1;
2332 return bSuccess;
2336 /***********************************************************************
2337 * FTP_InitListenSocket (internal)
2339 * Create a socket to listen for server response
2341 * RETURNS
2342 * TRUE on success
2343 * FALSE on failure
2346 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2348 BOOL bSuccess = FALSE;
2349 socklen_t namelen = sizeof(struct sockaddr_in);
2351 TRACE("\n");
2353 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2354 if (lpwfs->lstnSocket == -1)
2356 TRACE("Unable to create listening socket\n");
2357 goto lend;
2360 /* We obtain our ip addr from the name of the command channel socket */
2361 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2363 /* and get the system to assign us a port */
2364 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2366 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2368 TRACE("Unable to bind socket\n");
2369 goto lend;
2372 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2374 TRACE("listen failed\n");
2375 goto lend;
2378 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2379 bSuccess = TRUE;
2381 lend:
2382 if (!bSuccess && lpwfs->lstnSocket != -1)
2384 closesocket(lpwfs->lstnSocket);
2385 lpwfs->lstnSocket = -1;
2388 return bSuccess;
2392 /***********************************************************************
2393 * FTP_SendType (internal)
2395 * Tell server type of data being transferred
2397 * RETURNS
2398 * TRUE on success
2399 * FALSE on failure
2401 * W98SE doesn't cache the type that's currently set
2402 * (i.e. it sends it always),
2403 * so we probably don't want to do that either.
2405 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2407 INT nResCode;
2408 WCHAR type[] = { 'I','\0' };
2409 BOOL bSuccess = FALSE;
2411 TRACE("\n");
2412 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2413 type[0] = 'A';
2415 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2416 goto lend;
2418 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2419 if (nResCode)
2421 if (nResCode == 2)
2422 bSuccess = TRUE;
2423 else
2424 FTP_SetResponseError(nResCode);
2427 lend:
2428 return bSuccess;
2432 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2433 /***********************************************************************
2434 * FTP_GetFileSize (internal)
2436 * Retrieves from the server the size of the given file
2438 * RETURNS
2439 * TRUE on success
2440 * FALSE on failure
2443 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2445 INT nResCode;
2446 BOOL bSuccess = FALSE;
2448 TRACE("\n");
2450 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2451 goto lend;
2453 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2454 if (nResCode)
2456 if (nResCode == 213) {
2457 /* Now parses the output to get the actual file size */
2458 int i;
2459 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2461 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2462 if (lpszResponseBuffer[i] == '\0') return FALSE;
2463 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2465 bSuccess = TRUE;
2466 } else {
2467 FTP_SetResponseError(nResCode);
2471 lend:
2472 return bSuccess;
2474 #endif
2477 /***********************************************************************
2478 * FTP_SendPort (internal)
2480 * Tell server which port to use
2482 * RETURNS
2483 * TRUE on success
2484 * FALSE on failure
2487 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2489 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2490 INT nResCode;
2491 WCHAR szIPAddress[64];
2492 BOOL bSuccess = FALSE;
2493 TRACE("\n");
2495 sprintfW(szIPAddress, szIPFormat,
2496 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2497 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2498 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2499 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2500 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2501 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2503 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2504 goto lend;
2506 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2507 if (nResCode)
2509 if (nResCode == 200)
2510 bSuccess = TRUE;
2511 else
2512 FTP_SetResponseError(nResCode);
2515 lend:
2516 return bSuccess;
2520 /***********************************************************************
2521 * FTP_DoPassive (internal)
2523 * Tell server that we want to do passive transfers
2524 * and connect data socket
2526 * RETURNS
2527 * TRUE on success
2528 * FALSE on failure
2531 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2533 INT nResCode;
2534 BOOL bSuccess = FALSE;
2536 TRACE("\n");
2537 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2538 goto lend;
2540 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2541 if (nResCode)
2543 if (nResCode == 227)
2545 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2546 LPSTR p;
2547 int f[6];
2548 int i;
2549 char *pAddr, *pPort;
2550 INT nsocket = -1;
2551 struct sockaddr_in dataSocketAddress;
2553 p = lpszResponseBuffer+4; /* skip status code */
2554 while (*p != '\0' && (*p < '0' || *p > '9')) p++;
2556 if (*p == '\0')
2558 ERR("no address found in response, aborting\n");
2559 goto lend;
2562 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2563 &f[4], &f[5]) != 6)
2565 ERR("unknown response address format '%s', aborting\n", p);
2566 goto lend;
2568 for (i=0; i < 6; i++)
2569 f[i] = f[i] & 0xff;
2571 dataSocketAddress = lpwfs->socketAddress;
2572 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2573 pPort = (char *)&(dataSocketAddress.sin_port);
2574 pAddr[0] = f[0];
2575 pAddr[1] = f[1];
2576 pAddr[2] = f[2];
2577 pAddr[3] = f[3];
2578 pPort[0] = f[4];
2579 pPort[1] = f[5];
2581 nsocket = socket(AF_INET,SOCK_STREAM,0);
2582 if (nsocket == -1)
2583 goto lend;
2585 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2587 ERR("can't connect passive FTP data port.\n");
2588 closesocket(nsocket);
2589 goto lend;
2591 lpwfs->pasvSocket = nsocket;
2592 bSuccess = TRUE;
2594 else
2595 FTP_SetResponseError(nResCode);
2598 lend:
2599 return bSuccess;
2603 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2605 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2607 if (!FTP_DoPassive(lpwfs))
2608 return FALSE;
2610 else
2612 if (!FTP_SendPort(lpwfs))
2613 return FALSE;
2615 return TRUE;
2619 /***********************************************************************
2620 * FTP_GetDataSocket (internal)
2622 * Either accepts an incoming data socket connection from the server
2623 * or just returns the already opened socket after a PASV command
2624 * in case of passive FTP.
2627 * RETURNS
2628 * TRUE on success
2629 * FALSE on failure
2632 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2634 struct sockaddr_in saddr;
2635 socklen_t addrlen = sizeof(struct sockaddr);
2637 TRACE("\n");
2638 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2640 *nDataSocket = lpwfs->pasvSocket;
2642 else
2644 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2645 closesocket(lpwfs->lstnSocket);
2646 lpwfs->lstnSocket = -1;
2648 return *nDataSocket != -1;
2652 /***********************************************************************
2653 * FTP_SendData (internal)
2655 * Send data to the server
2657 * RETURNS
2658 * TRUE on success
2659 * FALSE on failure
2662 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2664 BY_HANDLE_FILE_INFORMATION fi;
2665 DWORD nBytesRead = 0;
2666 DWORD nBytesSent = 0;
2667 DWORD nTotalSent = 0;
2668 DWORD nBytesToSend, nLen;
2669 int nRC = 1;
2670 time_t s_long_time, e_long_time;
2671 LONG nSeconds;
2672 CHAR *lpszBuffer;
2674 TRACE("\n");
2675 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2677 /* Get the size of the file. */
2678 GetFileInformationByHandle(hFile, &fi);
2679 time(&s_long_time);
2683 nBytesToSend = nBytesRead - nBytesSent;
2685 if (nBytesToSend <= 0)
2687 /* Read data from file. */
2688 nBytesSent = 0;
2689 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2690 ERR("Failed reading from file\n");
2692 if (nBytesRead > 0)
2693 nBytesToSend = nBytesRead;
2694 else
2695 break;
2698 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2699 DATA_PACKET_SIZE : nBytesToSend;
2700 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2702 if (nRC != -1)
2704 nBytesSent += nRC;
2705 nTotalSent += nRC;
2708 /* Do some computation to display the status. */
2709 time(&e_long_time);
2710 nSeconds = e_long_time - s_long_time;
2711 if( nSeconds / 60 > 0 )
2713 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2714 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2715 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2717 else
2719 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2720 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2721 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2723 } while (nRC != -1);
2725 TRACE("file transfer complete!\n");
2727 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2729 return nTotalSent;
2733 /***********************************************************************
2734 * FTP_SendRetrieve (internal)
2736 * Send request to retrieve a file
2738 * RETURNS
2739 * Number of bytes to be received on success
2740 * 0 on failure
2743 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2745 INT nResCode;
2746 BOOL ret;
2748 TRACE("\n");
2749 if (!(ret = FTP_InitListenSocket(lpwfs)))
2750 goto lend;
2752 if (!(ret = FTP_SendType(lpwfs, dwType)))
2753 goto lend;
2755 if (!(ret = FTP_SendPortOrPasv(lpwfs)))
2756 goto lend;
2758 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
2759 goto lend;
2761 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2762 if ((nResCode != 125) && (nResCode != 150)) {
2763 /* That means that we got an error getting the file. */
2764 FTP_SetResponseError(nResCode);
2765 ret = FALSE;
2768 lend:
2769 if (!ret && lpwfs->lstnSocket != -1)
2771 closesocket(lpwfs->lstnSocket);
2772 lpwfs->lstnSocket = -1;
2775 return ret;
2779 /***********************************************************************
2780 * FTP_RetrieveData (internal)
2782 * Retrieve data from server
2784 * RETURNS
2785 * TRUE on success
2786 * FALSE on failure
2789 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2791 DWORD nBytesWritten;
2792 DWORD nBytesReceived = 0;
2793 INT nRC = 0;
2794 CHAR *lpszBuffer;
2796 TRACE("\n");
2798 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2799 if (NULL == lpszBuffer)
2801 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2802 return FALSE;
2805 while (nRC != -1)
2807 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2808 if (nRC != -1)
2810 /* other side closed socket. */
2811 if (nRC == 0)
2812 goto recv_end;
2813 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2814 nBytesReceived += nRC;
2818 TRACE("Data transfer complete\n");
2820 recv_end:
2821 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2823 return (nRC != -1);
2827 /***********************************************************************
2828 * FTP_CloseSessionHandle (internal)
2830 * Deallocate session handle
2832 * RETURNS
2833 * TRUE on success
2834 * FALSE on failure
2837 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2839 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2841 TRACE("\n");
2843 WININET_Release(&lpwfs->lpAppInfo->hdr);
2845 if (lpwfs->download_in_progress != NULL)
2846 lpwfs->download_in_progress->session_deleted = TRUE;
2848 if (lpwfs->sndSocket != -1)
2849 closesocket(lpwfs->sndSocket);
2851 if (lpwfs->lstnSocket != -1)
2852 closesocket(lpwfs->lstnSocket);
2854 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2855 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2856 HeapFree(GetProcessHeap(), 0, lpwfs);
2860 /***********************************************************************
2861 * FTP_FindNextFileW (Internal)
2863 * Continues a file search from a previous call to FindFirstFile
2865 * RETURNS
2866 * TRUE on success
2867 * FALSE on failure
2870 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2872 BOOL bSuccess = TRUE;
2873 LPWIN32_FIND_DATAW lpFindFileData;
2875 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2877 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2879 /* Clear any error information */
2880 INTERNET_SetLastError(0);
2882 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2883 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2885 if (lpwh->index >= lpwh->size)
2887 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2888 bSuccess = FALSE;
2889 goto lend;
2892 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2893 lpwh->index++;
2895 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2897 lend:
2899 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2901 INTERNET_ASYNC_RESULT iar;
2903 iar.dwResult = (DWORD)bSuccess;
2904 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2905 INTERNET_GetLastError();
2907 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2908 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2909 sizeof(INTERNET_ASYNC_RESULT));
2912 return bSuccess;
2916 /***********************************************************************
2917 * FTP_CloseFindNextHandle (internal)
2919 * Deallocate session handle
2921 * RETURNS
2922 * TRUE on success
2923 * FALSE on failure
2926 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2928 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2929 DWORD i;
2931 TRACE("\n");
2933 WININET_Release(&lpwfn->lpFtpSession->hdr);
2935 for (i = 0; i < lpwfn->size; i++)
2937 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2940 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2941 HeapFree(GetProcessHeap(), 0, lpwfn);
2944 /***********************************************************************
2945 * FTP_CloseFileTransferHandle (internal)
2947 * Closes the file transfer handle. This also 'cleans' the data queue of
2948 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2951 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2953 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2954 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2955 INT nResCode;
2957 TRACE("\n");
2959 WININET_Release(&lpwh->lpFtpSession->hdr);
2961 if (!lpwh->session_deleted)
2962 lpwfs->download_in_progress = NULL;
2964 /* This just serves to flush the control socket of any spurrious lines written
2965 to it (like '226 Transfer complete.').
2967 Wonder what to do if the server sends us an error code though...
2969 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2971 if (lpwh->nDataSocket != -1)
2972 closesocket(lpwh->nDataSocket);
2974 HeapFree(GetProcessHeap(), 0, lpwh);
2977 /***********************************************************************
2978 * FTP_ReceiveFileList (internal)
2980 * Read file list from server
2982 * RETURNS
2983 * Handle to file list on success
2984 * NULL on failure
2987 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2988 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
2990 DWORD dwSize = 0;
2991 LPFILEPROPERTIESW lpafp = NULL;
2992 LPWININETFTPFINDNEXTW lpwfn = NULL;
2993 HINTERNET handle = 0;
2995 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2997 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2999 if(lpFindFileData)
3000 FTP_ConvertFileProp(lpafp, lpFindFileData);
3002 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3003 if (lpwfn)
3005 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3006 lpwfn->hdr.dwContext = dwContext;
3007 lpwfn->hdr.dwRefCount = 1;
3008 lpwfn->hdr.close_connection = NULL;
3009 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3010 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3011 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3012 lpwfn->size = dwSize;
3013 lpwfn->lpafp = lpafp;
3015 WININET_AddRef( &lpwfs->hdr );
3016 lpwfn->lpFtpSession = lpwfs;
3017 list_add_head( &lpwfs->hdr.children, &lpwfn->hdr.entry );
3019 handle = WININET_AllocHandle( &lpwfn->hdr );
3023 if( lpwfn )
3024 WININET_Release( &lpwfn->hdr );
3026 TRACE("Matched %d files\n", dwSize);
3027 return handle;
3031 /***********************************************************************
3032 * FTP_ConvertFileProp (internal)
3034 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3036 * RETURNS
3037 * TRUE on success
3038 * FALSE on failure
3041 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3043 BOOL bSuccess = FALSE;
3045 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3047 if (lpafp)
3049 /* Convert 'Unix' time to Windows time */
3050 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3051 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3052 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3053 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3055 /* Not all fields are filled in */
3056 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3057 lpFindFileData->nFileSizeLow = lpafp->nSize;
3059 if (lpafp->bIsDirectory)
3060 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3062 if (lpafp->lpszName)
3063 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3065 bSuccess = TRUE;
3068 return bSuccess;
3071 /***********************************************************************
3072 * FTP_ParseNextFile (internal)
3074 * Parse the next line in file listing
3076 * RETURNS
3077 * TRUE on success
3078 * FALSE on failure
3080 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3082 static const char szSpace[] = " \t";
3083 DWORD nBufLen;
3084 char *pszLine;
3085 char *pszToken;
3086 char *pszTmp;
3087 BOOL found = FALSE;
3088 int i;
3090 lpfp->lpszName = NULL;
3091 do {
3092 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3093 return FALSE;
3095 pszToken = strtok(pszLine, szSpace);
3096 /* ls format
3097 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3099 * For instance:
3100 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3102 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3103 if(!FTP_ParsePermission(pszToken, lpfp))
3104 lpfp->bIsDirectory = FALSE;
3105 for(i=0; i<=3; i++) {
3106 if(!(pszToken = strtok(NULL, szSpace)))
3107 break;
3109 if(!pszToken) continue;
3110 if(lpfp->bIsDirectory) {
3111 TRACE("Is directory\n");
3112 lpfp->nSize = 0;
3114 else {
3115 TRACE("Size: %s\n", pszToken);
3116 lpfp->nSize = atol(pszToken);
3119 lpfp->tmLastModified.tm_sec = 0;
3120 lpfp->tmLastModified.tm_min = 0;
3121 lpfp->tmLastModified.tm_hour = 0;
3122 lpfp->tmLastModified.tm_mday = 0;
3123 lpfp->tmLastModified.tm_mon = 0;
3124 lpfp->tmLastModified.tm_year = 0;
3126 /* Determine month */
3127 pszToken = strtok(NULL, szSpace);
3128 if(!pszToken) continue;
3129 if(strlen(pszToken) >= 3) {
3130 pszToken[3] = 0;
3131 if((pszTmp = StrStrIA(szMonths, pszToken)))
3132 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3134 /* Determine day */
3135 pszToken = strtok(NULL, szSpace);
3136 if(!pszToken) continue;
3137 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3138 /* Determine time or year */
3139 pszToken = strtok(NULL, szSpace);
3140 if(!pszToken) continue;
3141 if((pszTmp = strchr(pszToken, ':'))) {
3142 struct tm* apTM;
3143 time_t aTime;
3144 *pszTmp = 0;
3145 pszTmp++;
3146 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3147 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3148 time(&aTime);
3149 apTM = localtime(&aTime);
3150 lpfp->tmLastModified.tm_year = apTM->tm_year;
3152 else {
3153 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3154 lpfp->tmLastModified.tm_hour = 12;
3156 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3157 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3158 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3159 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3161 pszToken = strtok(NULL, szSpace);
3162 if(!pszToken) continue;
3163 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3164 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3166 /* NT way of parsing ... :
3168 07-13-03 08:55PM <DIR> sakpatch
3169 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3171 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3172 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3174 sscanf(pszToken, "%d-%d-%d",
3175 &lpfp->tmLastModified.tm_mon,
3176 &lpfp->tmLastModified.tm_mday,
3177 &lpfp->tmLastModified.tm_year);
3179 /* Hacky and bad Y2K protection :-) */
3180 if (lpfp->tmLastModified.tm_year < 70)
3181 lpfp->tmLastModified.tm_year += 100;
3183 pszToken = strtok(NULL, szSpace);
3184 if(!pszToken) continue;
3185 sscanf(pszToken, "%d:%d",
3186 &lpfp->tmLastModified.tm_hour,
3187 &lpfp->tmLastModified.tm_min);
3188 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3189 lpfp->tmLastModified.tm_hour += 12;
3191 lpfp->tmLastModified.tm_sec = 0;
3193 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3194 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3195 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3196 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3198 pszToken = strtok(NULL, szSpace);
3199 if(!pszToken) continue;
3200 if(!strcasecmp(pszToken, "<DIR>")) {
3201 lpfp->bIsDirectory = TRUE;
3202 lpfp->nSize = 0;
3203 TRACE("Is directory\n");
3205 else {
3206 lpfp->bIsDirectory = FALSE;
3207 lpfp->nSize = atol(pszToken);
3208 TRACE("Size: %d\n", lpfp->nSize);
3211 pszToken = strtok(NULL, szSpace);
3212 if(!pszToken) continue;
3213 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3214 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3216 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3217 else if(pszToken[0] == '+') {
3218 FIXME("EPLF Format not implemented\n");
3221 if(lpfp->lpszName) {
3222 if((lpszSearchFile == NULL) ||
3223 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3224 found = TRUE;
3225 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3227 else {
3228 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3229 lpfp->lpszName = NULL;
3232 } while(!found);
3233 return TRUE;
3236 /***********************************************************************
3237 * FTP_ParseDirectory (internal)
3239 * Parse string of directory information
3241 * RETURNS
3242 * TRUE on success
3243 * FALSE on failure
3245 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3246 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3248 BOOL bSuccess = TRUE;
3249 INT sizeFilePropArray = 500;/*20; */
3250 INT indexFilePropArray = -1;
3252 TRACE("\n");
3254 /* Allocate intial file properties array */
3255 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3256 if (!*lpafp)
3257 return FALSE;
3259 do {
3260 if (indexFilePropArray+1 >= sizeFilePropArray)
3262 LPFILEPROPERTIESW tmpafp;
3264 sizeFilePropArray *= 2;
3265 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3266 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3267 if (NULL == tmpafp)
3269 bSuccess = FALSE;
3270 break;
3273 *lpafp = tmpafp;
3275 indexFilePropArray++;
3276 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3278 if (bSuccess && indexFilePropArray)
3280 if (indexFilePropArray < sizeFilePropArray - 1)
3282 LPFILEPROPERTIESW tmpafp;
3284 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3285 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3286 if (NULL == tmpafp)
3287 *lpafp = tmpafp;
3289 *dwfp = indexFilePropArray;
3291 else
3293 HeapFree(GetProcessHeap(), 0, *lpafp);
3294 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3295 bSuccess = FALSE;
3298 return bSuccess;
3302 /***********************************************************************
3303 * FTP_ParsePermission (internal)
3305 * Parse permission string of directory information
3307 * RETURNS
3308 * TRUE on success
3309 * FALSE on failure
3312 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3314 BOOL bSuccess = TRUE;
3315 unsigned short nPermission = 0;
3316 INT nPos = 1;
3317 INT nLast = 9;
3319 TRACE("\n");
3320 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3322 bSuccess = FALSE;
3323 return bSuccess;
3326 lpfp->bIsDirectory = (*lpszPermission == 'd');
3329 switch (nPos)
3331 case 1:
3332 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3333 break;
3334 case 2:
3335 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3336 break;
3337 case 3:
3338 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3339 break;
3340 case 4:
3341 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3342 break;
3343 case 5:
3344 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3345 break;
3346 case 6:
3347 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3348 break;
3349 case 7:
3350 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3351 break;
3352 case 8:
3353 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3354 break;
3355 case 9:
3356 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3357 break;
3359 nPos++;
3360 }while (nPos <= nLast);
3362 lpfp->permissions = nPermission;
3363 return bSuccess;
3367 /***********************************************************************
3368 * FTP_SetResponseError (internal)
3370 * Set the appropriate error code for a given response from the server
3372 * RETURNS
3375 static DWORD FTP_SetResponseError(DWORD dwResponse)
3377 DWORD dwCode = 0;
3379 switch(dwResponse)
3381 case 421: /* Service not available - Server may be shutting down. */
3382 dwCode = ERROR_INTERNET_TIMEOUT;
3383 break;
3385 case 425: /* Cannot open data connection. */
3386 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3387 break;
3389 case 426: /* Connection closed, transer aborted. */
3390 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3391 break;
3393 case 500: /* Syntax error. Command unrecognized. */
3394 case 501: /* Syntax error. Error in parameters or arguments. */
3395 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3396 break;
3398 case 530: /* Not logged in. Login incorrect. */
3399 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3400 break;
3402 case 550: /* File action not taken. File not found or no access. */
3403 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3404 break;
3406 case 450: /* File action not taken. File may be busy. */
3407 case 451: /* Action aborted. Server error. */
3408 case 452: /* Action not taken. Insufficient storage space on server. */
3409 case 502: /* Command not implemented. */
3410 case 503: /* Bad sequence of commands. */
3411 case 504: /* Command not implemented for that parameter. */
3412 case 532: /* Need account for storing files */
3413 case 551: /* Requested action aborted. Page type unknown */
3414 case 552: /* Action aborted. Exceeded storage allocation */
3415 case 553: /* Action not taken. File name not allowed. */
3417 default:
3418 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3419 break;
3422 INTERNET_SetLastError(dwCode);
3423 return dwCode;