2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
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
30 #include "wine/port.h"
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
58 #include "wine/debug.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
63 #define DATA_PACKET_SIZE 0x2000
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
73 /* FTP commands with arguments. */
89 /* FTP commands without arguments. */
98 static const CHAR *const szFtpCommands[] = {
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
161 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
162 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
164 LPWSTR lpwzLocalFile;
165 LPWSTR lpwzNewRemoteFile;
168 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
169 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
170 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
172 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
173 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
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
201 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
202 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
204 LPWININETFTPSESSIONW lpwfs;
205 LPWININETAPPINFOW hIC = NULL;
208 if (!lpszLocalFile || !lpszNewRemoteFile)
210 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
214 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
217 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
221 if (WH_HFTPSESSION != lpwfs->hdr.htype)
223 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
227 if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
229 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
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);
250 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
251 lpszNewRemoteFile, dwFlags, dwContext);
255 WININET_Release( &lpwfs->hdr );
260 /***********************************************************************
261 * FTP_FtpPutFileW (Internal)
263 * Uploads a file to the FTP server
270 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
271 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD_PTR dwContext)
274 BOOL bSuccess = FALSE;
275 LPWININETAPPINFOW hIC = NULL;
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 */
289 hIC = lpwfs->lpAppInfo;
291 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
293 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
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);
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));
332 /***********************************************************************
333 * FtpSetCurrentDirectoryA (WININET.@)
335 * Change the working directory on the FTP server
342 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
344 LPWSTR lpwzDirectory;
347 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
348 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
349 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
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
375 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
377 LPWININETFTPSESSIONW lpwfs = NULL;
378 LPWININETAPPINFOW hIC = NULL;
383 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
387 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
388 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
390 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
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);
411 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
416 WININET_Release( &lpwfs->hdr );
422 /***********************************************************************
423 * FTP_FtpSetCurrentDirectoryW (Internal)
425 * Change the working directory on the FTP server
432 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
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))
448 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
455 FTP_SetResponseError(nResCode);
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));
472 /***********************************************************************
473 * FtpCreateDirectoryA (WININET.@)
475 * Create new directory on the FTP server
482 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
484 LPWSTR lpwzDirectory;
487 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
488 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
489 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
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
515 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
517 LPWININETFTPSESSIONW lpwfs;
518 LPWININETAPPINFOW hIC = NULL;
521 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
524 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
528 if (WH_HFTPSESSION != lpwfs->hdr.htype)
530 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
536 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
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);
555 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
558 WININET_Release( &lpwfs->hdr );
564 /***********************************************************************
565 * FTP_FtpCreateDirectoryW (Internal)
567 * Create new directory on the FTP server
574 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
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))
588 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
594 FTP_SetResponseError(nResCode);
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));
612 /***********************************************************************
613 * FtpFindFirstFileA (WININET.@)
615 * Search the specified directory
618 * HINTERNET on success
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;
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);
636 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
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
660 * HINTERNET on success
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;
671 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
672 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
674 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
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);
697 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
702 WININET_Release( &lpwfs->hdr );
708 /***********************************************************************
709 * FTP_FtpFindFirstFileW (Internal)
711 * Search the specified directory
714 * HINTERNET on success
718 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
719 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD_PTR dwContext)
722 LPWININETAPPINFOW hIC = NULL;
723 HINTERNET hFindNext = NULL;
727 /* Clear any error information */
728 INTERNET_SetLastError(0);
730 if (!FTP_InitListenSocket(lpwfs))
733 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
736 if (!FTP_SendPortOrPasv(lpwfs))
739 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
740 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
743 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
746 if (nResCode == 125 || nResCode == 150)
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);
761 FTP_SetResponseError(nResCode);
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;
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));
791 /***********************************************************************
792 * FtpGetCurrentDirectoryA (WININET.@)
794 * Retrieves the current directory
801 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
802 LPDWORD lpdwCurrentDirectory)
808 if(lpdwCurrentDirectory) {
809 len = *lpdwCurrentDirectory;
810 if(lpszCurrentDirectory)
812 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
815 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
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);
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
852 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
853 LPDWORD lpdwCurrentDirectory)
855 LPWININETFTPSESSIONW lpwfs;
856 LPWININETAPPINFOW hIC = NULL;
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);
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);
884 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
885 lpdwCurrentDirectory);
890 WININET_Release( &lpwfs->hdr );
896 /***********************************************************************
897 * FTP_FtpGetCurrentDirectoryW (Internal)
899 * Retrieves the current directory
906 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
907 LPDWORD lpdwCurrentDirectory)
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))
925 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
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])
944 len = lastpos - firstpos - 1;
945 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
946 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
947 *lpdwCurrentDirectory = len;
951 FTP_SetResponseError(nResCode);
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
974 * HINTERNET handle on success
978 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
979 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
985 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
986 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
987 HeapFree(GetProcessHeap(), 0, lpwzFileName);
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
1010 * HINTERNET handle on success
1014 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1015 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1016 DWORD_PTR dwContext)
1018 LPWININETFTPSESSIONW lpwfs;
1019 LPWININETAPPINFOW hIC = 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 );
1028 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1032 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1034 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
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);
1046 if (lpwfs->download_in_progress != NULL) {
1047 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
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);
1069 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1073 WININET_Release( &lpwfs->hdr );
1079 /***********************************************************************
1080 * FTP_FtpOpenFileW (Internal)
1082 * Open a remote file for writing or reading
1085 * HINTERNET handle on success
1089 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1090 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1091 DWORD_PTR dwContext)
1094 BOOL bSuccess = FALSE;
1095 LPWININETFTPFILE lpwh = NULL;
1096 LPWININETAPPINFOW hIC = NULL;
1097 HINTERNET handle = NULL;
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;
1132 handle = WININET_AllocHandle( &lpwh->hdr );
1136 /* Indicate that a download is currently in progress */
1137 lpwfs->download_in_progress = lpwh;
1140 if (lpwfs->lstnSocket != -1)
1141 closesocket(lpwfs->lstnSocket);
1143 hIC = lpwfs->lpAppInfo;
1144 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1146 INTERNET_ASYNC_RESULT iar;
1150 iar.dwResult = (DWORD)handle;
1151 iar.dwError = ERROR_SUCCESS;
1152 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1153 &iar, sizeof(INTERNET_ASYNC_RESULT));
1156 iar.dwResult = (DWORD)bSuccess;
1157 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1158 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1159 &iar, sizeof(INTERNET_ASYNC_RESULT));
1164 WININET_Release( &lpwh->hdr );
1170 /***********************************************************************
1171 * FtpGetFileA (WININET.@)
1173 * Retrieve file from the FTP server
1180 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1181 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1182 DWORD_PTR dwContext)
1184 LPWSTR lpwzRemoteFile;
1188 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1189 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1190 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1191 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1192 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1193 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1198 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1200 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1201 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1203 TRACE("%p\n", lpwfs);
1205 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1206 req->lpszNewFile, req->fFailIfExists,
1207 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1208 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1209 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1213 /***********************************************************************
1214 * FtpGetFileW (WININET.@)
1216 * Retrieve file from the FTP server
1223 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1224 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1225 DWORD_PTR dwContext)
1227 LPWININETFTPSESSIONW lpwfs;
1228 LPWININETAPPINFOW hIC = NULL;
1231 if (!lpszRemoteFile || !lpszNewFile)
1233 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1237 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1240 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1244 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1246 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1250 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1252 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1256 if (lpwfs->download_in_progress != NULL) {
1257 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1261 hIC = lpwfs->lpAppInfo;
1262 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1264 WORKREQUEST workRequest;
1265 struct WORKREQ_FTPGETFILEW *req;
1267 workRequest.asyncproc = AsyncFtpGetFileProc;
1268 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1269 req = &workRequest.u.FtpGetFileW;
1270 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1271 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1272 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1273 req->fFailIfExists = fFailIfExists;
1274 req->dwFlags = dwInternetFlags;
1275 req->dwContext = dwContext;
1277 r = INTERNET_AsyncCall(&workRequest);
1281 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1282 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1286 WININET_Release( &lpwfs->hdr );
1292 /***********************************************************************
1293 * FTP_FtpGetFileW (Internal)
1295 * Retrieve file from the FTP server
1302 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1303 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1304 DWORD_PTR dwContext)
1306 BOOL bSuccess = FALSE;
1308 LPWININETAPPINFOW hIC = NULL;
1310 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1312 /* Clear any error information */
1313 INTERNET_SetLastError(0);
1315 /* Ensure we can write to lpszNewfile by opening it */
1316 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1317 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1318 if (INVALID_HANDLE_VALUE == hFile)
1321 /* Set up socket to retrieve data */
1322 if (FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags))
1326 /* Get data socket to server */
1327 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1332 FTP_RetrieveFileData(lpwfs, nDataSocket, hFile);
1333 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1336 if (nResCode == 226)
1339 FTP_SetResponseError(nResCode);
1341 closesocket(nDataSocket);
1345 if (lpwfs->lstnSocket != -1)
1346 closesocket(lpwfs->lstnSocket);
1350 hIC = lpwfs->lpAppInfo;
1351 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1353 INTERNET_ASYNC_RESULT iar;
1355 iar.dwResult = (DWORD)bSuccess;
1356 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1357 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1358 &iar, sizeof(INTERNET_ASYNC_RESULT));
1364 /***********************************************************************
1365 * FtpGetFileSize (WININET.@)
1367 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1369 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1371 if (lpdwFileSizeHigh)
1372 *lpdwFileSizeHigh = 0;
1377 /***********************************************************************
1378 * FtpDeleteFileA (WININET.@)
1380 * Delete a file on the ftp server
1387 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1389 LPWSTR lpwzFileName;
1392 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1393 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1394 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1398 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1400 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1401 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1403 TRACE("%p\n", lpwfs);
1405 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1406 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1409 /***********************************************************************
1410 * FtpDeleteFileW (WININET.@)
1412 * Delete a file on the ftp server
1419 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1421 LPWININETFTPSESSIONW lpwfs;
1422 LPWININETAPPINFOW hIC = NULL;
1425 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1428 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1432 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1434 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1440 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1444 hIC = lpwfs->lpAppInfo;
1445 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1447 WORKREQUEST workRequest;
1448 struct WORKREQ_FTPDELETEFILEW *req;
1450 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1451 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1452 req = &workRequest.u.FtpDeleteFileW;
1453 req->lpszFilename = WININET_strdupW(lpszFileName);
1455 r = INTERNET_AsyncCall(&workRequest);
1459 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1463 WININET_Release( &lpwfs->hdr );
1468 /***********************************************************************
1469 * FTP_FtpDeleteFileW (Internal)
1471 * Delete a file on the ftp server
1478 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1481 BOOL bSuccess = FALSE;
1482 LPWININETAPPINFOW hIC = NULL;
1484 TRACE("%p\n", lpwfs);
1486 /* Clear any error information */
1487 INTERNET_SetLastError(0);
1489 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1492 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1495 if (nResCode == 250)
1498 FTP_SetResponseError(nResCode);
1501 hIC = lpwfs->lpAppInfo;
1502 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1504 INTERNET_ASYNC_RESULT iar;
1506 iar.dwResult = (DWORD)bSuccess;
1507 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1508 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1509 &iar, sizeof(INTERNET_ASYNC_RESULT));
1516 /***********************************************************************
1517 * FtpRemoveDirectoryA (WININET.@)
1519 * Remove a directory on the ftp server
1526 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1528 LPWSTR lpwzDirectory;
1531 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1532 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1533 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1537 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1539 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1540 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1542 TRACE("%p\n", lpwfs);
1544 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1545 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1548 /***********************************************************************
1549 * FtpRemoveDirectoryW (WININET.@)
1551 * Remove a directory on the ftp server
1558 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1560 LPWININETFTPSESSIONW lpwfs;
1561 LPWININETAPPINFOW hIC = NULL;
1564 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1567 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1571 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1573 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1579 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1583 hIC = lpwfs->lpAppInfo;
1584 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1586 WORKREQUEST workRequest;
1587 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1589 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1590 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1591 req = &workRequest.u.FtpRemoveDirectoryW;
1592 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1594 r = INTERNET_AsyncCall(&workRequest);
1598 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1602 WININET_Release( &lpwfs->hdr );
1607 /***********************************************************************
1608 * FTP_FtpRemoveDirectoryW (Internal)
1610 * Remove a directory on the ftp server
1617 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1620 BOOL bSuccess = FALSE;
1621 LPWININETAPPINFOW hIC = NULL;
1625 /* Clear any error information */
1626 INTERNET_SetLastError(0);
1628 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1631 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1634 if (nResCode == 250)
1637 FTP_SetResponseError(nResCode);
1641 hIC = lpwfs->lpAppInfo;
1642 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1644 INTERNET_ASYNC_RESULT iar;
1646 iar.dwResult = (DWORD)bSuccess;
1647 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1648 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1649 &iar, sizeof(INTERNET_ASYNC_RESULT));
1656 /***********************************************************************
1657 * FtpRenameFileA (WININET.@)
1659 * Rename a file on the ftp server
1666 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1672 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1673 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1674 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1675 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1676 HeapFree(GetProcessHeap(), 0, lpwzDest);
1680 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1682 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1683 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1685 TRACE("%p\n", lpwfs);
1687 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1688 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1689 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1692 /***********************************************************************
1693 * FtpRenameFileW (WININET.@)
1695 * Rename a file on the ftp server
1702 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1704 LPWININETFTPSESSIONW lpwfs;
1705 LPWININETAPPINFOW hIC = NULL;
1708 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1711 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1715 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1717 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1721 if (!lpszSrc || !lpszDest)
1723 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1727 hIC = lpwfs->lpAppInfo;
1728 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1730 WORKREQUEST workRequest;
1731 struct WORKREQ_FTPRENAMEFILEW *req;
1733 workRequest.asyncproc = AsyncFtpRenameFileProc;
1734 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1735 req = &workRequest.u.FtpRenameFileW;
1736 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1737 req->lpszDestFile = WININET_strdupW(lpszDest);
1739 r = INTERNET_AsyncCall(&workRequest);
1743 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1747 WININET_Release( &lpwfs->hdr );
1752 /***********************************************************************
1753 * FTP_FtpRenameFileW (Internal)
1755 * Rename a file on the ftp server
1762 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1763 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1766 BOOL bSuccess = FALSE;
1767 LPWININETAPPINFOW hIC = NULL;
1771 /* Clear any error information */
1772 INTERNET_SetLastError(0);
1774 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1777 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1778 if (nResCode == 350)
1780 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1783 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1786 if (nResCode == 250)
1789 FTP_SetResponseError(nResCode);
1792 hIC = lpwfs->lpAppInfo;
1793 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1795 INTERNET_ASYNC_RESULT iar;
1797 iar.dwResult = (DWORD)bSuccess;
1798 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1799 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1800 &iar, sizeof(INTERNET_ASYNC_RESULT));
1806 /***********************************************************************
1807 * FtpCommandA (WININET.@)
1809 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1810 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1812 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1813 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1818 /***********************************************************************
1819 * FtpCommandW (WININET.@)
1821 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1822 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1824 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1825 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1830 /***********************************************************************
1831 * FTP_Connect (internal)
1833 * Connect to a ftp server
1836 * HINTERNET a session handle on success
1841 * Windows uses 'anonymous' as the username, when given a NULL username
1842 * and a NULL password. The password is first looked up in:
1844 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1846 * If this entry is not present it uses the current username as the password.
1850 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1851 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1852 LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
1853 DWORD dwInternalFlags)
1855 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1856 'M','i','c','r','o','s','o','f','t','\\',
1857 'W','i','n','d','o','w','s','\\',
1858 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1859 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1860 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1861 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1862 static const WCHAR szEmpty[] = {'\0'};
1863 struct sockaddr_in socketAddr;
1866 BOOL bSuccess = FALSE;
1867 LPWININETFTPSESSIONW lpwfs = NULL;
1868 HINTERNET handle = NULL;
1870 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1871 hIC, debugstr_w(lpszServerName),
1872 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1874 assert( hIC->hdr.htype == WH_HINIT );
1876 if (NULL == lpszUserName && NULL != lpszPassword)
1878 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1882 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1885 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1889 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1890 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1892 lpwfs->hdr.htype = WH_HFTPSESSION;
1893 lpwfs->hdr.dwFlags = dwFlags;
1894 lpwfs->hdr.dwContext = dwContext;
1895 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1896 lpwfs->hdr.dwRefCount = 1;
1897 /* FIXME: Native sends INTERNET_STATUS_CLOSING_CONNECTION and
1898 * INTERNET_STATUS_CONNECTION_CLOSED, need an equivalent FTP_CloseConnection
1900 lpwfs->hdr.close_connection = NULL;
1901 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1902 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1903 lpwfs->download_in_progress = NULL;
1905 WININET_AddRef( &hIC->hdr );
1906 lpwfs->lpAppInfo = hIC;
1908 handle = WININET_AllocHandle( &lpwfs->hdr );
1911 ERR("Failed to alloc handle\n");
1912 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1916 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1917 if(strchrW(hIC->lpszProxy, ' '))
1918 FIXME("Several proxies not implemented.\n");
1919 if(hIC->lpszProxyBypass)
1920 FIXME("Proxy bypass is ignored.\n");
1922 if ( !lpszUserName) {
1924 WCHAR szPassword[MAX_PATH];
1925 DWORD len = sizeof(szPassword);
1927 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1929 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1930 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1931 /* Nothing in the registry, get the username and use that as the password */
1932 if (!GetUserNameW(szPassword, &len)) {
1933 /* Should never get here, but use an empty password as failsafe */
1934 strcpyW(szPassword, szEmpty);
1939 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1940 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1943 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1946 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1948 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1951 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1952 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1954 INTERNET_ASYNC_RESULT iar;
1956 iar.dwResult = (DWORD)handle;
1957 iar.dwError = ERROR_SUCCESS;
1959 SendAsyncCallback(&hIC->hdr, dwContext,
1960 INTERNET_STATUS_HANDLE_CREATED, &iar,
1961 sizeof(INTERNET_ASYNC_RESULT));
1964 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1965 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1967 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1969 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1973 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1974 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1976 nsocket = socket(AF_INET,SOCK_STREAM,0);
1979 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1983 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1984 &socketAddr, sizeof(struct sockaddr_in));
1986 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1988 ERR("Unable to connect (%s)\n", strerror(errno));
1989 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1993 TRACE("Connected to server\n");
1994 lpwfs->sndSocket = nsocket;
1995 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1996 &socketAddr, sizeof(struct sockaddr_in));
1998 sock_namelen = sizeof(lpwfs->socketAddress);
1999 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2001 if (FTP_ConnectToHost(lpwfs))
2003 TRACE("Successfully logged into server\n");
2009 if (!bSuccess && nsocket != -1)
2010 closesocket(nsocket);
2012 if (!bSuccess && lpwfs)
2014 HeapFree(GetProcessHeap(), 0, lpwfs);
2015 WININET_FreeHandle( handle );
2020 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2022 INTERNET_ASYNC_RESULT iar;
2024 iar.dwResult = (DWORD)lpwfs;
2025 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2026 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2027 &iar, sizeof(INTERNET_ASYNC_RESULT));
2034 /***********************************************************************
2035 * FTP_ConnectToHost (internal)
2037 * Connect to a ftp server
2044 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2047 BOOL bSuccess = FALSE;
2050 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2052 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2055 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2058 /* Login successful... */
2059 if (nResCode == 230)
2061 /* User name okay, need password... */
2062 else if (nResCode == 331)
2063 bSuccess = FTP_SendPassword(lpwfs);
2064 /* Need account for login... */
2065 else if (nResCode == 332)
2066 bSuccess = FTP_SendAccount(lpwfs);
2068 FTP_SetResponseError(nResCode);
2071 TRACE("Returning %d\n", bSuccess);
2077 /***********************************************************************
2078 * FTP_SendCommandA (internal)
2080 * Send command to server
2087 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2088 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2092 DWORD nBytesSent = 0;
2096 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2100 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2103 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2104 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2105 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2107 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2110 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2111 dwParamLen ? lpszParam : "", szCRLF);
2113 TRACE("Sending (%s) len(%d)\n", buf, len);
2114 while((nBytesSent < len) && (nRC != -1))
2116 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2120 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2124 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2125 &nBytesSent, sizeof(DWORD));
2128 TRACE("Sent %d bytes\n", nBytesSent);
2132 /***********************************************************************
2133 * FTP_SendCommand (internal)
2135 * Send command to server
2142 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2143 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext)
2146 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2147 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2148 HeapFree(GetProcessHeap(), 0, lpszParamA);
2152 /***********************************************************************
2153 * FTP_ReceiveResponse (internal)
2155 * Receive response from server
2158 * Reply code on success
2162 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD_PTR dwContext)
2164 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2167 char firstprefix[5];
2168 BOOL multiline = FALSE;
2169 LPWININETAPPINFOW hIC = NULL;
2171 TRACE("socket(%d)\n", lpwfs->sndSocket);
2173 hIC = lpwfs->lpAppInfo;
2174 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2178 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2185 if(lpszResponse[3] != '-')
2188 { /* Start of multiline repsonse. Loop until we get "nnn " */
2190 memcpy(firstprefix, lpszResponse, 3);
2191 firstprefix[3] = ' ';
2192 firstprefix[4] = '\0';
2197 if(!memcmp(firstprefix, lpszResponse, 4))
2205 rc = atoi(lpszResponse);
2207 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2208 &nRecv, sizeof(DWORD));
2212 TRACE("return %d\n", rc);
2217 /***********************************************************************
2218 * FTP_SendPassword (internal)
2220 * Send password to ftp server
2227 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2230 BOOL bSuccess = FALSE;
2233 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2236 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2239 TRACE("Received reply code %d\n", nResCode);
2240 /* Login successful... */
2241 if (nResCode == 230)
2243 /* Command not implemented, superfluous at the server site... */
2244 /* Need account for login... */
2245 else if (nResCode == 332)
2246 bSuccess = FTP_SendAccount(lpwfs);
2248 FTP_SetResponseError(nResCode);
2252 TRACE("Returning %d\n", bSuccess);
2257 /***********************************************************************
2258 * FTP_SendAccount (internal)
2267 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2270 BOOL bSuccess = FALSE;
2273 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2276 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2280 FTP_SetResponseError(nResCode);
2287 /***********************************************************************
2288 * FTP_SendStore (internal)
2290 * Send request to upload file to ftp server
2297 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2300 BOOL bSuccess = FALSE;
2303 if (!FTP_InitListenSocket(lpwfs))
2306 if (!FTP_SendType(lpwfs, dwType))
2309 if (!FTP_SendPortOrPasv(lpwfs))
2312 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2314 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2317 if (nResCode == 150 || nResCode == 125)
2320 FTP_SetResponseError(nResCode);
2324 if (!bSuccess && lpwfs->lstnSocket != -1)
2326 closesocket(lpwfs->lstnSocket);
2327 lpwfs->lstnSocket = -1;
2334 /***********************************************************************
2335 * FTP_InitListenSocket (internal)
2337 * Create a socket to listen for server response
2344 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2346 BOOL bSuccess = FALSE;
2347 socklen_t namelen = sizeof(struct sockaddr_in);
2351 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2352 if (lpwfs->lstnSocket == -1)
2354 TRACE("Unable to create listening socket\n");
2358 /* We obtain our ip addr from the name of the command channel socket */
2359 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2361 /* and get the system to assign us a port */
2362 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2364 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2366 TRACE("Unable to bind socket\n");
2370 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2372 TRACE("listen failed\n");
2376 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2380 if (!bSuccess && lpwfs->lstnSocket != -1)
2382 closesocket(lpwfs->lstnSocket);
2383 lpwfs->lstnSocket = -1;
2390 /***********************************************************************
2391 * FTP_SendType (internal)
2393 * Tell server type of data being transferred
2399 * W98SE doesn't cache the type that's currently set
2400 * (i.e. it sends it always),
2401 * so we probably don't want to do that either.
2403 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2406 WCHAR type[] = { 'I','\0' };
2407 BOOL bSuccess = FALSE;
2410 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2413 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2416 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2422 FTP_SetResponseError(nResCode);
2430 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2431 /***********************************************************************
2432 * FTP_GetFileSize (internal)
2434 * Retrieves from the server the size of the given file
2441 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2444 BOOL bSuccess = FALSE;
2448 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2451 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2454 if (nResCode == 213) {
2455 /* Now parses the output to get the actual file size */
2457 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2459 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2460 if (lpszResponseBuffer[i] == '\0') return FALSE;
2461 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2465 FTP_SetResponseError(nResCode);
2475 /***********************************************************************
2476 * FTP_SendPort (internal)
2478 * Tell server which port to use
2485 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2487 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2489 WCHAR szIPAddress[64];
2490 BOOL bSuccess = FALSE;
2493 sprintfW(szIPAddress, szIPFormat,
2494 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2495 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2496 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2497 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2498 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2499 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2501 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2504 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2507 if (nResCode == 200)
2510 FTP_SetResponseError(nResCode);
2518 /***********************************************************************
2519 * FTP_DoPassive (internal)
2521 * Tell server that we want to do passive transfers
2522 * and connect data socket
2529 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2532 BOOL bSuccess = FALSE;
2535 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2538 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2541 if (nResCode == 227)
2543 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2547 char *pAddr, *pPort;
2549 struct sockaddr_in dataSocketAddress;
2551 p = lpszResponseBuffer+4; /* skip status code */
2552 while (*p != '\0' && (*p < '0' || *p > '9')) p++;
2556 ERR("no address found in response, aborting\n");
2560 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2563 ERR("unknown response address format '%s', aborting\n", p);
2566 for (i=0; i < 6; i++)
2569 dataSocketAddress = lpwfs->socketAddress;
2570 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2571 pPort = (char *)&(dataSocketAddress.sin_port);
2579 nsocket = socket(AF_INET,SOCK_STREAM,0);
2583 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2585 ERR("can't connect passive FTP data port.\n");
2586 closesocket(nsocket);
2589 lpwfs->pasvSocket = nsocket;
2593 FTP_SetResponseError(nResCode);
2601 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2603 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2605 if (!FTP_DoPassive(lpwfs))
2610 if (!FTP_SendPort(lpwfs))
2617 /***********************************************************************
2618 * FTP_GetDataSocket (internal)
2620 * Either accepts an incoming data socket connection from the server
2621 * or just returns the already opened socket after a PASV command
2622 * in case of passive FTP.
2630 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2632 struct sockaddr_in saddr;
2633 socklen_t addrlen = sizeof(struct sockaddr);
2636 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2638 *nDataSocket = lpwfs->pasvSocket;
2642 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2643 closesocket(lpwfs->lstnSocket);
2644 lpwfs->lstnSocket = -1;
2646 return *nDataSocket != -1;
2650 /***********************************************************************
2651 * FTP_SendData (internal)
2653 * Send data to the server
2660 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2662 BY_HANDLE_FILE_INFORMATION fi;
2663 DWORD nBytesRead = 0;
2664 DWORD nBytesSent = 0;
2665 DWORD nTotalSent = 0;
2666 DWORD nBytesToSend, nLen;
2668 time_t s_long_time, e_long_time;
2673 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2675 /* Get the size of the file. */
2676 GetFileInformationByHandle(hFile, &fi);
2681 nBytesToSend = nBytesRead - nBytesSent;
2683 if (nBytesToSend <= 0)
2685 /* Read data from file. */
2687 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2688 ERR("Failed reading from file\n");
2691 nBytesToSend = nBytesRead;
2696 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2697 DATA_PACKET_SIZE : nBytesToSend;
2698 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2706 /* Do some computation to display the status. */
2708 nSeconds = e_long_time - s_long_time;
2709 if( nSeconds / 60 > 0 )
2711 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2712 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2713 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2717 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2718 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2719 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2721 } while (nRC != -1);
2723 TRACE("file transfer complete!\n");
2725 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2731 /***********************************************************************
2732 * FTP_SendRetrieve (internal)
2734 * Send request to retrieve a file
2737 * Number of bytes to be received on success
2741 static BOOL FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2747 if (!(ret = FTP_InitListenSocket(lpwfs)))
2750 if (!(ret = FTP_SendType(lpwfs, dwType)))
2753 if (!(ret = FTP_SendPortOrPasv(lpwfs)))
2756 if (!(ret = FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0)))
2759 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2760 if ((nResCode != 125) && (nResCode != 150)) {
2761 /* That means that we got an error getting the file. */
2762 FTP_SetResponseError(nResCode);
2767 if (!ret && lpwfs->lstnSocket != -1)
2769 closesocket(lpwfs->lstnSocket);
2770 lpwfs->lstnSocket = -1;
2777 /***********************************************************************
2778 * FTP_RetrieveData (internal)
2780 * Retrieve data from server
2787 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2789 DWORD nBytesWritten;
2790 DWORD nBytesReceived = 0;
2796 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2797 if (NULL == lpszBuffer)
2799 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2805 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2808 /* other side closed socket. */
2811 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2812 nBytesReceived += nRC;
2816 TRACE("Data transfer complete\n");
2819 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2825 /***********************************************************************
2826 * FTP_CloseSessionHandle (internal)
2828 * Deallocate session handle
2835 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2837 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2841 WININET_Release(&lpwfs->lpAppInfo->hdr);
2843 if (lpwfs->download_in_progress != NULL)
2844 lpwfs->download_in_progress->session_deleted = TRUE;
2846 if (lpwfs->sndSocket != -1)
2847 closesocket(lpwfs->sndSocket);
2849 if (lpwfs->lstnSocket != -1)
2850 closesocket(lpwfs->lstnSocket);
2852 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2853 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2854 HeapFree(GetProcessHeap(), 0, lpwfs);
2858 /***********************************************************************
2859 * FTP_FindNextFileW (Internal)
2861 * Continues a file search from a previous call to FindFirstFile
2868 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2870 BOOL bSuccess = TRUE;
2871 LPWIN32_FIND_DATAW lpFindFileData;
2873 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2875 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2877 /* Clear any error information */
2878 INTERNET_SetLastError(0);
2880 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2881 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2883 if (lpwh->index >= lpwh->size)
2885 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2890 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2893 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2897 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2899 INTERNET_ASYNC_RESULT iar;
2901 iar.dwResult = (DWORD)bSuccess;
2902 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2903 INTERNET_GetLastError();
2905 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2906 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2907 sizeof(INTERNET_ASYNC_RESULT));
2914 /***********************************************************************
2915 * FTP_CloseFindNextHandle (internal)
2917 * Deallocate session handle
2924 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2926 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2931 WININET_Release(&lpwfn->lpFtpSession->hdr);
2933 for (i = 0; i < lpwfn->size; i++)
2935 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2938 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2939 HeapFree(GetProcessHeap(), 0, lpwfn);
2942 /***********************************************************************
2943 * FTP_CloseFileTransferHandle (internal)
2945 * Closes the file transfer handle. This also 'cleans' the data queue of
2946 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2949 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2951 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2952 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2957 WININET_Release(&lpwh->lpFtpSession->hdr);
2959 if (!lpwh->session_deleted)
2960 lpwfs->download_in_progress = NULL;
2962 /* This just serves to flush the control socket of any spurrious lines written
2963 to it (like '226 Transfer complete.').
2965 Wonder what to do if the server sends us an error code though...
2967 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2969 if (lpwh->nDataSocket != -1)
2970 closesocket(lpwh->nDataSocket);
2972 HeapFree(GetProcessHeap(), 0, lpwh);
2975 /***********************************************************************
2976 * FTP_ReceiveFileList (internal)
2978 * Read file list from server
2981 * Handle to file list on success
2985 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2986 LPWIN32_FIND_DATAW lpFindFileData, DWORD_PTR dwContext)
2989 LPFILEPROPERTIESW lpafp = NULL;
2990 LPWININETFTPFINDNEXTW lpwfn = NULL;
2991 HINTERNET handle = 0;
2993 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2995 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2998 FTP_ConvertFileProp(lpafp, lpFindFileData);
3000 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3003 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3004 lpwfn->hdr.dwContext = dwContext;
3005 lpwfn->hdr.dwRefCount = 1;
3006 lpwfn->hdr.close_connection = NULL;
3007 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3008 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3009 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3010 lpwfn->size = dwSize;
3011 lpwfn->lpafp = lpafp;
3013 WININET_AddRef( &lpwfs->hdr );
3014 lpwfn->lpFtpSession = lpwfs;
3016 handle = WININET_AllocHandle( &lpwfn->hdr );
3021 WININET_Release( &lpwfn->hdr );
3023 TRACE("Matched %d files\n", dwSize);
3028 /***********************************************************************
3029 * FTP_ConvertFileProp (internal)
3031 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3038 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3040 BOOL bSuccess = FALSE;
3042 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3046 /* Convert 'Unix' time to Windows time */
3047 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3048 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3049 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3050 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3052 /* Not all fields are filled in */
3053 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3054 lpFindFileData->nFileSizeLow = lpafp->nSize;
3056 if (lpafp->bIsDirectory)
3057 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3059 if (lpafp->lpszName)
3060 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3068 /***********************************************************************
3069 * FTP_ParseNextFile (internal)
3071 * Parse the next line in file listing
3077 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3079 static const char szSpace[] = " \t";
3087 lpfp->lpszName = NULL;
3089 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3092 pszToken = strtok(pszLine, szSpace);
3094 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3097 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3099 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3100 if(!FTP_ParsePermission(pszToken, lpfp))
3101 lpfp->bIsDirectory = FALSE;
3102 for(i=0; i<=3; i++) {
3103 if(!(pszToken = strtok(NULL, szSpace)))
3106 if(!pszToken) continue;
3107 if(lpfp->bIsDirectory) {
3108 TRACE("Is directory\n");
3112 TRACE("Size: %s\n", pszToken);
3113 lpfp->nSize = atol(pszToken);
3116 lpfp->tmLastModified.tm_sec = 0;
3117 lpfp->tmLastModified.tm_min = 0;
3118 lpfp->tmLastModified.tm_hour = 0;
3119 lpfp->tmLastModified.tm_mday = 0;
3120 lpfp->tmLastModified.tm_mon = 0;
3121 lpfp->tmLastModified.tm_year = 0;
3123 /* Determine month */
3124 pszToken = strtok(NULL, szSpace);
3125 if(!pszToken) continue;
3126 if(strlen(pszToken) >= 3) {
3128 if((pszTmp = StrStrIA(szMonths, pszToken)))
3129 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3132 pszToken = strtok(NULL, szSpace);
3133 if(!pszToken) continue;
3134 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3135 /* Determine time or year */
3136 pszToken = strtok(NULL, szSpace);
3137 if(!pszToken) continue;
3138 if((pszTmp = strchr(pszToken, ':'))) {
3143 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3144 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3146 apTM = localtime(&aTime);
3147 lpfp->tmLastModified.tm_year = apTM->tm_year;
3150 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3151 lpfp->tmLastModified.tm_hour = 12;
3153 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3154 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3155 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3156 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3158 pszToken = strtok(NULL, szSpace);
3159 if(!pszToken) continue;
3160 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3161 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3163 /* NT way of parsing ... :
3165 07-13-03 08:55PM <DIR> sakpatch
3166 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3168 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3169 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3171 sscanf(pszToken, "%d-%d-%d",
3172 &lpfp->tmLastModified.tm_mon,
3173 &lpfp->tmLastModified.tm_mday,
3174 &lpfp->tmLastModified.tm_year);
3176 /* Hacky and bad Y2K protection :-) */
3177 if (lpfp->tmLastModified.tm_year < 70)
3178 lpfp->tmLastModified.tm_year += 100;
3180 pszToken = strtok(NULL, szSpace);
3181 if(!pszToken) continue;
3182 sscanf(pszToken, "%d:%d",
3183 &lpfp->tmLastModified.tm_hour,
3184 &lpfp->tmLastModified.tm_min);
3185 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3186 lpfp->tmLastModified.tm_hour += 12;
3188 lpfp->tmLastModified.tm_sec = 0;
3190 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3191 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3192 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3193 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3195 pszToken = strtok(NULL, szSpace);
3196 if(!pszToken) continue;
3197 if(!strcasecmp(pszToken, "<DIR>")) {
3198 lpfp->bIsDirectory = TRUE;
3200 TRACE("Is directory\n");
3203 lpfp->bIsDirectory = FALSE;
3204 lpfp->nSize = atol(pszToken);
3205 TRACE("Size: %d\n", lpfp->nSize);
3208 pszToken = strtok(NULL, szSpace);
3209 if(!pszToken) continue;
3210 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3211 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3213 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3214 else if(pszToken[0] == '+') {
3215 FIXME("EPLF Format not implemented\n");
3218 if(lpfp->lpszName) {
3219 if((lpszSearchFile == NULL) ||
3220 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3222 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3225 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3226 lpfp->lpszName = NULL;
3233 /***********************************************************************
3234 * FTP_ParseDirectory (internal)
3236 * Parse string of directory information
3242 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3243 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3245 BOOL bSuccess = TRUE;
3246 INT sizeFilePropArray = 500;/*20; */
3247 INT indexFilePropArray = -1;
3251 /* Allocate intial file properties array */
3252 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3257 if (indexFilePropArray+1 >= sizeFilePropArray)
3259 LPFILEPROPERTIESW tmpafp;
3261 sizeFilePropArray *= 2;
3262 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3263 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3272 indexFilePropArray++;
3273 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3275 if (bSuccess && indexFilePropArray)
3277 if (indexFilePropArray < sizeFilePropArray - 1)
3279 LPFILEPROPERTIESW tmpafp;
3281 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3282 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3286 *dwfp = indexFilePropArray;
3290 HeapFree(GetProcessHeap(), 0, *lpafp);
3291 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3299 /***********************************************************************
3300 * FTP_ParsePermission (internal)
3302 * Parse permission string of directory information
3309 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3311 BOOL bSuccess = TRUE;
3312 unsigned short nPermission = 0;
3317 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3323 lpfp->bIsDirectory = (*lpszPermission == 'd');
3329 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3332 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3335 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3338 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3341 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3344 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3347 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3350 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3353 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3357 }while (nPos <= nLast);
3359 lpfp->permissions = nPermission;
3364 /***********************************************************************
3365 * FTP_SetResponseError (internal)
3367 * Set the appropriate error code for a given response from the server
3372 static DWORD FTP_SetResponseError(DWORD dwResponse)
3378 case 421: /* Service not available - Server may be shutting down. */
3379 dwCode = ERROR_INTERNET_TIMEOUT;
3382 case 425: /* Cannot open data connection. */
3383 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3386 case 426: /* Connection closed, transer aborted. */
3387 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3390 case 500: /* Syntax error. Command unrecognized. */
3391 case 501: /* Syntax error. Error in parameters or arguments. */
3392 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3395 case 530: /* Not logged in. Login incorrect. */
3396 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3399 case 550: /* File action not taken. File not found or no access. */
3400 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3403 case 450: /* File action not taken. File may be busy. */
3404 case 451: /* Action aborted. Server error. */
3405 case 452: /* Action not taken. Insufficient storage space on server. */
3406 case 502: /* Command not implemented. */
3407 case 503: /* Bad sequence of commands. */
3408 case 504: /* Command not implemented for that parameter. */
3409 case 532: /* Need account for storing files */
3410 case 551: /* Requested action aborted. Page type unknown */
3411 case 552: /* Action aborted. Exceeded storage allocation */
3412 case 553: /* Action not taken. File name not allowed. */
3415 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3419 INTERNET_SetLastError(dwCode);