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
68 /* FTP commands with arguments. */
84 /* FTP commands without arguments. */
93 static const CHAR *szFtpCommands[] = {
116 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
117 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
119 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
120 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
121 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
122 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext);
124 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
126 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
127 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
128 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
129 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
130 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
131 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
132 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
133 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
134 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
135 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
136 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
137 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
140 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
141 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
142 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
143 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
144 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
145 static DWORD FTP_SetResponseError(DWORD dwResponse);
147 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
157 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
158 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
160 LPWSTR lpwzLocalFile;
161 LPWSTR lpwzNewRemoteFile;
164 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
165 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
166 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
168 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
169 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
173 /***********************************************************************
174 * FtpPutFileW (WININET.@)
176 * Uploads a file to the FTP server
183 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
185 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
186 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
188 TRACE("%p\n", lpwfs);
190 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
191 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
193 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
194 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
197 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
198 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
200 LPWININETFTPSESSIONW lpwfs;
201 LPWININETAPPINFOW hIC = NULL;
204 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
205 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
207 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
211 hIC = lpwfs->lpAppInfo;
212 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
214 WORKREQUEST workRequest;
215 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
217 workRequest.asyncproc = AsyncFtpPutFileProc;
218 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
219 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
220 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
221 req->dwFlags = dwFlags;
222 req->dwContext = dwContext;
224 r = INTERNET_AsyncCall(&workRequest);
228 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
229 lpszNewRemoteFile, dwFlags, dwContext);
234 WININET_Release( &lpwfs->hdr );
239 /***********************************************************************
240 * FTP_FtpPutFileW (Internal)
242 * Uploads a file to the FTP server
249 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
250 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
253 BOOL bSuccess = FALSE;
254 LPWININETAPPINFOW hIC = NULL;
257 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
259 if (!lpszLocalFile || !lpszNewRemoteFile)
261 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
265 assert( WH_HFTPSESSION == lpwfs->hdr.htype);
267 /* Clear any error information */
268 INTERNET_SetLastError(0);
269 hIC = lpwfs->lpAppInfo;
271 /* Open file to be uploaded */
272 if (INVALID_HANDLE_VALUE ==
273 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
275 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
279 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
281 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
285 /* Get data socket to server */
286 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
288 FTP_SendData(lpwfs, nDataSocket, hFile);
289 closesocket(nDataSocket);
290 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
296 FTP_SetResponseError(nResCode);
302 if (lpwfs->lstnSocket != -1)
303 closesocket(lpwfs->lstnSocket);
305 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
307 INTERNET_ASYNC_RESULT iar;
309 iar.dwResult = (DWORD)bSuccess;
310 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
311 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
312 &iar, sizeof(INTERNET_ASYNC_RESULT));
322 /***********************************************************************
323 * FtpSetCurrentDirectoryA (WININET.@)
325 * Change the working directory on the FTP server
332 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
334 LPWSTR lpwzDirectory;
337 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
338 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
339 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
344 /***********************************************************************
345 * FtpSetCurrentDirectoryW (WININET.@)
347 * Change the working directory on the FTP server
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 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
367 LPWININETFTPSESSIONW lpwfs = NULL;
368 LPWININETAPPINFOW hIC = NULL;
373 SetLastError(ERROR_INVALID_PARAMETER);
377 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
378 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
380 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
384 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
386 hIC = lpwfs->lpAppInfo;
387 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
389 WORKREQUEST workRequest;
390 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
392 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
393 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
394 req = &workRequest.u.FtpSetCurrentDirectoryW;
395 req->lpszDirectory = WININET_strdupW(lpszDirectory);
397 r = INTERNET_AsyncCall(&workRequest);
401 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
406 WININET_Release( &lpwfs->hdr );
412 /***********************************************************************
413 * FTP_FtpSetCurrentDirectoryW (Internal)
415 * Change the working directory on the FTP server
422 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
425 LPWININETAPPINFOW hIC = NULL;
426 DWORD bSuccess = FALSE;
428 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
430 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
432 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
436 /* Clear any error information */
437 INTERNET_SetLastError(0);
439 hIC = lpwfs->lpAppInfo;
440 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
441 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
444 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
451 FTP_SetResponseError(nResCode);
455 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
457 INTERNET_ASYNC_RESULT iar;
459 iar.dwResult = (DWORD)bSuccess;
460 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
461 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
462 &iar, sizeof(INTERNET_ASYNC_RESULT));
468 /***********************************************************************
469 * FtpCreateDirectoryA (WININET.@)
471 * Create new directory on the FTP server
478 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
480 LPWSTR lpwzDirectory;
483 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
484 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
485 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
490 /***********************************************************************
491 * FtpCreateDirectoryW (WININET.@)
493 * Create new directory on the FTP server
500 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
502 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
503 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
505 TRACE(" %p\n", lpwfs);
507 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
508 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
511 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
513 LPWININETFTPSESSIONW lpwfs;
514 LPWININETAPPINFOW hIC = NULL;
517 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
518 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
520 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
524 hIC = lpwfs->lpAppInfo;
525 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
527 WORKREQUEST workRequest;
528 struct WORKREQ_FTPCREATEDIRECTORYW *req;
530 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
531 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
532 req = &workRequest.u.FtpCreateDirectoryW;
533 req->lpszDirectory = WININET_strdupW(lpszDirectory);
535 r = INTERNET_AsyncCall(&workRequest);
539 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
543 WININET_Release( &lpwfs->hdr );
549 /***********************************************************************
550 * FTP_FtpCreateDirectoryW (Internal)
552 * Create new directory on the FTP server
559 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
562 BOOL bSuccess = FALSE;
563 LPWININETAPPINFOW hIC = NULL;
565 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
567 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
569 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
573 /* Clear any error information */
574 INTERNET_SetLastError(0);
576 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
579 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
585 FTP_SetResponseError(nResCode);
589 hIC = lpwfs->lpAppInfo;
590 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
592 INTERNET_ASYNC_RESULT iar;
594 iar.dwResult = (DWORD)bSuccess;
595 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
596 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
597 &iar, sizeof(INTERNET_ASYNC_RESULT));
603 /***********************************************************************
604 * FtpFindFirstFileA (WININET.@)
606 * Search the specified directory
609 * HINTERNET on success
613 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
614 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
616 LPWSTR lpwzSearchFile;
617 WIN32_FIND_DATAW wfd;
618 LPWIN32_FIND_DATAW lpFindFileDataW;
621 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
622 lpFindFileDataW = lpFindFileData?&wfd:NULL;
623 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
624 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
627 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
633 /***********************************************************************
634 * FtpFindFirstFileW (WININET.@)
636 * Search the specified directory
639 * HINTERNET on success
643 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
645 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
646 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
648 TRACE("%p\n", lpwfs);
650 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
651 req->lpFindFileData, req->dwFlags, req->dwContext);
652 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
655 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
656 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
658 LPWININETFTPSESSIONW lpwfs;
659 LPWININETAPPINFOW hIC = NULL;
662 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
663 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
665 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
669 hIC = lpwfs->lpAppInfo;
670 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
672 WORKREQUEST workRequest;
673 struct WORKREQ_FTPFINDFIRSTFILEW *req;
675 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
676 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
677 req = &workRequest.u.FtpFindFirstFileW;
678 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
679 req->lpFindFileData = lpFindFileData;
680 req->dwFlags = dwFlags;
681 req->dwContext= dwContext;
683 INTERNET_AsyncCall(&workRequest);
688 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
693 WININET_Release( &lpwfs->hdr );
699 /***********************************************************************
700 * FTP_FtpFindFirstFileW (Internal)
702 * Search the specified directory
705 * HINTERNET on success
709 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
710 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
713 LPWININETAPPINFOW hIC = NULL;
714 HINTERNET hFindNext = NULL;
718 assert(WH_HFTPSESSION == lpwfs->hdr.htype);
720 /* Clear any error information */
721 INTERNET_SetLastError(0);
723 if (!FTP_InitListenSocket(lpwfs))
726 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
729 if (!FTP_SendPortOrPasv(lpwfs))
732 hIC = lpwfs->lpAppInfo;
733 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
734 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
737 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
740 if (nResCode == 125 || nResCode == 150)
744 /* Get data socket to server */
745 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
747 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
748 closesocket(nDataSocket);
749 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
750 if (nResCode != 226 && nResCode != 250)
751 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
755 FTP_SetResponseError(nResCode);
759 if (lpwfs->lstnSocket != -1)
760 closesocket(lpwfs->lstnSocket);
762 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
764 INTERNET_ASYNC_RESULT iar;
768 iar.dwResult = (DWORD)hFindNext;
769 iar.dwError = ERROR_SUCCESS;
770 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
771 &iar, sizeof(INTERNET_ASYNC_RESULT));
774 iar.dwResult = (DWORD)hFindNext;
775 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
776 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
777 &iar, sizeof(INTERNET_ASYNC_RESULT));
784 /***********************************************************************
785 * FtpGetCurrentDirectoryA (WININET.@)
787 * Retrieves the current directory
794 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
795 LPDWORD lpdwCurrentDirectory)
801 if(lpdwCurrentDirectory) {
802 len = *lpdwCurrentDirectory;
803 if(lpszCurrentDirectory)
805 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
808 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
813 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
814 if(lpdwCurrentDirectory) {
815 *lpdwCurrentDirectory = len;
816 if(lpszCurrentDirectory) {
817 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
818 HeapFree(GetProcessHeap(), 0, dir);
825 /***********************************************************************
826 * FtpGetCurrentDirectoryW (WININET.@)
828 * Retrieves the current directory
835 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
837 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
838 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
840 TRACE("%p\n", lpwfs);
842 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
845 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
846 LPDWORD lpdwCurrentDirectory)
848 LPWININETFTPSESSIONW lpwfs;
849 LPWININETAPPINFOW hIC = NULL;
852 TRACE("len(%d)\n", *lpdwCurrentDirectory);
854 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
855 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
857 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
861 hIC = lpwfs->lpAppInfo;
862 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
864 WORKREQUEST workRequest;
865 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
867 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
868 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
869 req = &workRequest.u.FtpGetCurrentDirectoryW;
870 req->lpszDirectory = lpszCurrentDirectory;
871 req->lpdwDirectory = lpdwCurrentDirectory;
873 r = INTERNET_AsyncCall(&workRequest);
877 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
878 lpdwCurrentDirectory);
883 WININET_Release( &lpwfs->hdr );
889 /***********************************************************************
890 * FTP_FtpGetCurrentDirectoryA (Internal)
892 * Retrieves the current directory
899 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
900 LPDWORD lpdwCurrentDirectory)
903 LPWININETAPPINFOW hIC = NULL;
904 DWORD bSuccess = FALSE;
906 TRACE("len(%d)\n", *lpdwCurrentDirectory);
908 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
910 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
914 /* Clear any error information */
915 INTERNET_SetLastError(0);
917 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
919 hIC = lpwfs->lpAppInfo;
920 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
921 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
924 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
927 if (nResCode == 257) /* Extract directory name */
929 DWORD firstpos, lastpos, len;
930 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
932 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
934 if ('"' == lpszResponseBuffer[lastpos])
943 len = lastpos - firstpos - 1;
944 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
945 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
946 *lpdwCurrentDirectory = len;
950 FTP_SetResponseError(nResCode);
954 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
956 INTERNET_ASYNC_RESULT iar;
958 iar.dwResult = (DWORD)bSuccess;
959 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
960 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
961 &iar, sizeof(INTERNET_ASYNC_RESULT));
964 return (DWORD) bSuccess;
967 /***********************************************************************
968 * FtpOpenFileA (WININET.@)
970 * Open a remote file for writing or reading
973 * HINTERNET handle on success
977 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
978 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
984 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
985 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
986 HeapFree(GetProcessHeap(), 0, lpwzFileName);
991 /***********************************************************************
992 * FtpOpenFileW (WININET.@)
994 * Open a remote file for writing or reading
997 * HINTERNET handle on success
1001 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
1003 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
1004 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1006 TRACE("%p\n", lpwfs);
1008 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1009 req->dwAccess, req->dwFlags, req->dwContext);
1010 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1013 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1014 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1017 LPWININETFTPSESSIONW lpwfs;
1018 LPWININETAPPINFOW hIC = NULL;
1021 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession,
1022 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1024 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1025 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1027 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1031 if (lpwfs->download_in_progress != NULL) {
1032 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1035 hIC = lpwfs->lpAppInfo;
1036 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1038 WORKREQUEST workRequest;
1039 struct WORKREQ_FTPOPENFILEW *req;
1041 workRequest.asyncproc = AsyncFtpOpenFileProc;
1042 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1043 req = &workRequest.u.FtpOpenFileW;
1044 req->lpszFilename = WININET_strdupW(lpszFileName);
1045 req->dwAccess = fdwAccess;
1046 req->dwFlags = dwFlags;
1047 req->dwContext = dwContext;
1049 INTERNET_AsyncCall(&workRequest);
1054 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1059 WININET_Release( &lpwfs->hdr );
1065 /***********************************************************************
1066 * FTP_FtpOpenFileW (Internal)
1068 * Open a remote file for writing or reading
1071 * HINTERNET handle on success
1075 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1076 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1080 BOOL bSuccess = FALSE;
1081 LPWININETFTPFILE lpwh = NULL;
1082 LPWININETAPPINFOW hIC = NULL;
1083 HINTERNET handle = NULL;
1087 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1089 /* Clear any error information */
1090 INTERNET_SetLastError(0);
1092 if (GENERIC_READ == fdwAccess)
1094 /* Set up socket to retrieve data */
1095 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1097 else if (GENERIC_WRITE == fdwAccess)
1099 /* Set up socket to send data */
1100 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1103 /* Get data socket to server */
1104 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1106 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1107 lpwh->hdr.htype = WH_HFILE;
1108 lpwh->hdr.dwFlags = dwFlags;
1109 lpwh->hdr.dwContext = dwContext;
1110 lpwh->hdr.dwRefCount = 1;
1111 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1112 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1113 lpwh->nDataSocket = nDataSocket;
1114 lpwh->session_deleted = FALSE;
1116 WININET_AddRef( &lpwfs->hdr );
1117 lpwh->lpFtpSession = lpwfs;
1119 handle = WININET_AllocHandle( &lpwh->hdr );
1123 /* Indicate that a download is currently in progress */
1124 lpwfs->download_in_progress = lpwh;
1127 if (lpwfs->lstnSocket != -1)
1128 closesocket(lpwfs->lstnSocket);
1130 hIC = lpwfs->lpAppInfo;
1131 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1133 INTERNET_ASYNC_RESULT iar;
1137 iar.dwResult = (DWORD)handle;
1138 iar.dwError = ERROR_SUCCESS;
1139 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1140 &iar, sizeof(INTERNET_ASYNC_RESULT));
1143 iar.dwResult = (DWORD)bSuccess;
1144 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1145 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1146 &iar, sizeof(INTERNET_ASYNC_RESULT));
1151 WININET_Release( &lpwh->hdr );
1157 /***********************************************************************
1158 * FtpGetFileA (WININET.@)
1160 * Retrieve file from the FTP server
1167 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1168 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1171 LPWSTR lpwzRemoteFile;
1175 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1176 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1177 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1178 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1179 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1180 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1185 /***********************************************************************
1186 * FtpGetFileW (WININET.@)
1188 * Retrieve file from the FTP server
1195 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1197 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1198 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1200 TRACE("%p\n", lpwfs);
1202 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1203 req->lpszNewFile, req->fFailIfExists,
1204 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1205 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1206 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1209 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1210 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1213 LPWININETFTPSESSIONW lpwfs;
1214 LPWININETAPPINFOW hIC = NULL;
1217 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1218 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1220 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1224 if (lpwfs->download_in_progress != NULL) {
1225 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1229 hIC = lpwfs->lpAppInfo;
1230 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1232 WORKREQUEST workRequest;
1233 struct WORKREQ_FTPGETFILEW *req;
1235 workRequest.asyncproc = AsyncFtpGetFileProc;
1236 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1237 req = &workRequest.u.FtpGetFileW;
1238 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1239 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1240 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1241 req->fFailIfExists = fFailIfExists;
1242 req->dwFlags = dwInternetFlags;
1243 req->dwContext = dwContext;
1245 r = INTERNET_AsyncCall(&workRequest);
1249 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1250 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1255 WININET_Release( &lpwfs->hdr );
1261 /***********************************************************************
1262 * FTP_FtpGetFileW (Internal)
1264 * Retrieve file from the FTP server
1271 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1272 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1276 BOOL bSuccess = FALSE;
1278 LPWININETAPPINFOW hIC = NULL;
1280 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1282 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1284 /* Clear any error information */
1285 INTERNET_SetLastError(0);
1287 /* Ensure we can write to lpszNewfile by opening it */
1288 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1289 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1290 if (INVALID_HANDLE_VALUE == hFile)
1293 /* Set up socket to retrieve data */
1294 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1300 /* Get data socket to server */
1301 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1306 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1307 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1310 if (nResCode == 226)
1313 FTP_SetResponseError(nResCode);
1315 closesocket(nDataSocket);
1320 if (lpwfs->lstnSocket != -1)
1321 closesocket(lpwfs->lstnSocket);
1326 hIC = lpwfs->lpAppInfo;
1327 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1329 INTERNET_ASYNC_RESULT iar;
1331 iar.dwResult = (DWORD)bSuccess;
1332 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1333 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1334 &iar, sizeof(INTERNET_ASYNC_RESULT));
1340 /***********************************************************************
1341 * FtpGetFileSize (WININET.@)
1343 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1345 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1347 if (lpdwFileSizeHigh)
1348 *lpdwFileSizeHigh = 0;
1353 /***********************************************************************
1354 * FtpDeleteFileA (WININET.@)
1356 * Delete a file on the ftp server
1363 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1365 LPWSTR lpwzFileName;
1368 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1369 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1370 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1374 /***********************************************************************
1375 * FtpDeleteFileW (WININET.@)
1377 * Delete a file on the ftp server
1384 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1386 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1387 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1389 TRACE("%p\n", lpwfs);
1391 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1392 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1395 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1397 LPWININETFTPSESSIONW lpwfs;
1398 LPWININETAPPINFOW hIC = NULL;
1401 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1402 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1404 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1408 hIC = lpwfs->lpAppInfo;
1409 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1411 WORKREQUEST workRequest;
1412 struct WORKREQ_FTPDELETEFILEW *req;
1414 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1415 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1416 req = &workRequest.u.FtpDeleteFileW;
1417 req->lpszFilename = WININET_strdupW(lpszFileName);
1419 r = INTERNET_AsyncCall(&workRequest);
1423 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1428 WININET_Release( &lpwfs->hdr );
1433 /***********************************************************************
1434 * FTP_FtpDeleteFileW (Internal)
1436 * Delete a file on the ftp server
1443 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1446 BOOL bSuccess = FALSE;
1447 LPWININETAPPINFOW hIC = NULL;
1449 TRACE("%p\n", lpwfs);
1451 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1453 /* Clear any error information */
1454 INTERNET_SetLastError(0);
1456 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1459 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1462 if (nResCode == 250)
1465 FTP_SetResponseError(nResCode);
1468 hIC = lpwfs->lpAppInfo;
1469 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1471 INTERNET_ASYNC_RESULT iar;
1473 iar.dwResult = (DWORD)bSuccess;
1474 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1475 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1476 &iar, sizeof(INTERNET_ASYNC_RESULT));
1483 /***********************************************************************
1484 * FtpRemoveDirectoryA (WININET.@)
1486 * Remove a directory on the ftp server
1493 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1495 LPWSTR lpwzDirectory;
1498 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1499 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1500 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1504 /***********************************************************************
1505 * FtpRemoveDirectoryW (WININET.@)
1507 * Remove a directory on the ftp server
1514 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1516 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1517 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1519 TRACE("%p\n", lpwfs);
1521 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1522 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1525 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1527 LPWININETFTPSESSIONW lpwfs;
1528 LPWININETAPPINFOW hIC = NULL;
1531 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1532 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1534 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1538 hIC = lpwfs->lpAppInfo;
1539 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1541 WORKREQUEST workRequest;
1542 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1544 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1545 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1546 req = &workRequest.u.FtpRemoveDirectoryW;
1547 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1549 r = INTERNET_AsyncCall(&workRequest);
1553 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1558 WININET_Release( &lpwfs->hdr );
1563 /***********************************************************************
1564 * FTP_FtpRemoveDirectoryW (Internal)
1566 * Remove a directory on the ftp server
1573 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1576 BOOL bSuccess = FALSE;
1577 LPWININETAPPINFOW hIC = NULL;
1581 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1583 /* Clear any error information */
1584 INTERNET_SetLastError(0);
1586 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1589 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1592 if (nResCode == 250)
1595 FTP_SetResponseError(nResCode);
1599 hIC = lpwfs->lpAppInfo;
1600 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1602 INTERNET_ASYNC_RESULT iar;
1604 iar.dwResult = (DWORD)bSuccess;
1605 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1606 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1607 &iar, sizeof(INTERNET_ASYNC_RESULT));
1614 /***********************************************************************
1615 * FtpRenameFileA (WININET.@)
1617 * Rename a file on the ftp server
1624 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1630 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1631 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1632 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1633 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1634 HeapFree(GetProcessHeap(), 0, lpwzDest);
1638 /***********************************************************************
1639 * FtpRenameFileW (WININET.@)
1641 * Rename a file on the ftp server
1648 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1650 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1651 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1653 TRACE("%p\n", lpwfs);
1655 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1656 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1657 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1660 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1662 LPWININETFTPSESSIONW lpwfs;
1663 LPWININETAPPINFOW hIC = NULL;
1666 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1667 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1669 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1673 hIC = lpwfs->lpAppInfo;
1674 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1676 WORKREQUEST workRequest;
1677 struct WORKREQ_FTPRENAMEFILEW *req;
1679 workRequest.asyncproc = AsyncFtpRenameFileProc;
1680 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1681 req = &workRequest.u.FtpRenameFileW;
1682 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1683 req->lpszDestFile = WININET_strdupW(lpszDest);
1685 r = INTERNET_AsyncCall(&workRequest);
1689 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1694 WININET_Release( &lpwfs->hdr );
1699 /***********************************************************************
1700 * FTP_FtpRenameFileW (Internal)
1702 * Rename a file on the ftp server
1709 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1710 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1713 BOOL bSuccess = FALSE;
1714 LPWININETAPPINFOW hIC = NULL;
1718 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1720 /* Clear any error information */
1721 INTERNET_SetLastError(0);
1723 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1726 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1727 if (nResCode == 350)
1729 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1732 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1735 if (nResCode == 250)
1738 FTP_SetResponseError(nResCode);
1741 hIC = lpwfs->lpAppInfo;
1742 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1744 INTERNET_ASYNC_RESULT iar;
1746 iar.dwResult = (DWORD)bSuccess;
1747 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1748 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1749 &iar, sizeof(INTERNET_ASYNC_RESULT));
1755 /***********************************************************************
1756 * FtpCommandA (WININET.@)
1758 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1759 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1761 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1762 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1767 /***********************************************************************
1768 * FtpCommandW (WININET.@)
1770 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1771 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1773 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1774 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1779 /***********************************************************************
1780 * FTP_Connect (internal)
1782 * Connect to a ftp server
1785 * HINTERNET a session handle on success
1790 * Windows uses 'anonymous' as the username, when given a NULL username
1791 * and a NULL password. The password is first looked up in:
1793 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1795 * If this entry is not present it uses the current username as the password.
1799 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1800 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1801 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1802 DWORD dwInternalFlags)
1804 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1805 'M','i','c','r','o','s','o','f','t','\\',
1806 'W','i','n','d','o','w','s','\\',
1807 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1808 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1809 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1810 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1811 static const WCHAR szEmpty[] = {'\0'};
1812 struct sockaddr_in socketAddr;
1815 BOOL bSuccess = FALSE;
1816 LPWININETFTPSESSIONW lpwfs = NULL;
1817 HINTERNET handle = NULL;
1819 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1820 hIC, debugstr_w(lpszServerName),
1821 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1823 assert( hIC->hdr.htype == WH_HINIT );
1825 if (NULL == lpszUserName && NULL != lpszPassword)
1827 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1831 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1834 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1838 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1839 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1841 lpwfs->hdr.htype = WH_HFTPSESSION;
1842 lpwfs->hdr.dwFlags = dwFlags;
1843 lpwfs->hdr.dwContext = dwContext;
1844 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1845 lpwfs->hdr.dwRefCount = 1;
1846 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1847 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1848 lpwfs->download_in_progress = NULL;
1850 WININET_AddRef( &hIC->hdr );
1851 lpwfs->lpAppInfo = hIC;
1853 handle = WININET_AllocHandle( &lpwfs->hdr );
1856 ERR("Failed to alloc handle\n");
1857 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1861 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1862 if(strchrW(hIC->lpszProxy, ' '))
1863 FIXME("Several proxies not implemented.\n");
1864 if(hIC->lpszProxyBypass)
1865 FIXME("Proxy bypass is ignored.\n");
1867 if ( !lpszUserName) {
1869 WCHAR szPassword[MAX_PATH];
1870 DWORD len = sizeof(szPassword);
1872 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1874 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1875 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1876 /* Nothing in the registry, get the username and use that as the password */
1877 if (!GetUserNameW(szPassword, &len)) {
1878 /* Should never get here, but use an empty password as failsafe */
1879 strcpyW(szPassword, szEmpty);
1884 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1885 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1888 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1891 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1893 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1896 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1897 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1899 INTERNET_ASYNC_RESULT iar;
1901 iar.dwResult = (DWORD)handle;
1902 iar.dwError = ERROR_SUCCESS;
1904 SendAsyncCallback(&hIC->hdr, dwContext,
1905 INTERNET_STATUS_HANDLE_CREATED, &iar,
1906 sizeof(INTERNET_ASYNC_RESULT));
1909 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1910 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1912 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1914 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1918 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1919 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1921 nsocket = socket(AF_INET,SOCK_STREAM,0);
1924 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1928 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1929 &socketAddr, sizeof(struct sockaddr_in));
1931 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1933 ERR("Unable to connect (%s)\n", strerror(errno));
1934 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1938 TRACE("Connected to server\n");
1939 lpwfs->sndSocket = nsocket;
1940 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1941 &socketAddr, sizeof(struct sockaddr_in));
1943 sock_namelen = sizeof(lpwfs->socketAddress);
1944 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1946 if (FTP_ConnectToHost(lpwfs))
1948 TRACE("Successfully logged into server\n");
1954 if (!bSuccess && nsocket == -1)
1955 closesocket(nsocket);
1957 if (!bSuccess && lpwfs)
1959 HeapFree(GetProcessHeap(), 0, lpwfs);
1960 WININET_FreeHandle( handle );
1965 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1967 INTERNET_ASYNC_RESULT iar;
1969 iar.dwResult = (DWORD)lpwfs;
1970 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1971 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1972 &iar, sizeof(INTERNET_ASYNC_RESULT));
1979 /***********************************************************************
1980 * FTP_ConnectToHost (internal)
1982 * Connect to a ftp server
1989 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1992 BOOL bSuccess = FALSE;
1995 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1997 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2000 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2003 /* Login successful... */
2004 if (nResCode == 230)
2006 /* User name okay, need password... */
2007 else if (nResCode == 331)
2008 bSuccess = FTP_SendPassword(lpwfs);
2009 /* Need account for login... */
2010 else if (nResCode == 332)
2011 bSuccess = FTP_SendAccount(lpwfs);
2013 FTP_SetResponseError(nResCode);
2016 TRACE("Returning %d\n", bSuccess);
2022 /***********************************************************************
2023 * FTP_SendCommandA (internal)
2025 * Send command to server
2032 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2033 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2037 DWORD nBytesSent = 0;
2041 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2045 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2048 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2049 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2050 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2052 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2055 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2056 dwParamLen ? lpszParam : "", szCRLF);
2058 TRACE("Sending (%s) len(%d)\n", buf, len);
2059 while((nBytesSent < len) && (nRC != -1))
2061 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2065 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2069 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2070 &nBytesSent, sizeof(DWORD));
2073 TRACE("Sent %d bytes\n", nBytesSent);
2077 /***********************************************************************
2078 * FTP_SendCommand (internal)
2080 * Send command to server
2087 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2088 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2091 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2092 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2093 HeapFree(GetProcessHeap(), 0, lpszParamA);
2097 /***********************************************************************
2098 * FTP_ReceiveResponse (internal)
2100 * Receive response from server
2103 * Reply code on success
2107 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2109 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2112 char firstprefix[5];
2113 BOOL multiline = FALSE;
2114 LPWININETAPPINFOW hIC = NULL;
2116 TRACE("socket(%d)\n", lpwfs->sndSocket);
2118 hIC = lpwfs->lpAppInfo;
2119 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2123 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2130 if(lpszResponse[3] != '-')
2133 { /* Start of multiline repsonse. Loop until we get "nnn " */
2135 memcpy(firstprefix, lpszResponse, 3);
2136 firstprefix[3] = ' ';
2137 firstprefix[4] = '\0';
2142 if(!memcmp(firstprefix, lpszResponse, 4))
2150 rc = atoi(lpszResponse);
2152 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2153 &nRecv, sizeof(DWORD));
2157 TRACE("return %d\n", rc);
2162 /***********************************************************************
2163 * FTP_SendPassword (internal)
2165 * Send password to ftp server
2172 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2175 BOOL bSuccess = FALSE;
2178 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2181 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2184 TRACE("Received reply code %d\n", nResCode);
2185 /* Login successful... */
2186 if (nResCode == 230)
2188 /* Command not implemented, superfluous at the server site... */
2189 /* Need account for login... */
2190 else if (nResCode == 332)
2191 bSuccess = FTP_SendAccount(lpwfs);
2193 FTP_SetResponseError(nResCode);
2197 TRACE("Returning %d\n", bSuccess);
2202 /***********************************************************************
2203 * FTP_SendAccount (internal)
2212 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2215 BOOL bSuccess = FALSE;
2218 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2221 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2225 FTP_SetResponseError(nResCode);
2232 /***********************************************************************
2233 * FTP_SendStore (internal)
2235 * Send request to upload file to ftp server
2242 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2245 BOOL bSuccess = FALSE;
2248 if (!FTP_InitListenSocket(lpwfs))
2251 if (!FTP_SendType(lpwfs, dwType))
2254 if (!FTP_SendPortOrPasv(lpwfs))
2257 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2259 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2262 if (nResCode == 150 || nResCode == 125)
2265 FTP_SetResponseError(nResCode);
2269 if (!bSuccess && lpwfs->lstnSocket != -1)
2271 closesocket(lpwfs->lstnSocket);
2272 lpwfs->lstnSocket = -1;
2279 /***********************************************************************
2280 * FTP_InitListenSocket (internal)
2282 * Create a socket to listen for server response
2289 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2291 BOOL bSuccess = FALSE;
2292 size_t namelen = sizeof(struct sockaddr_in);
2296 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2297 if (lpwfs->lstnSocket == -1)
2299 TRACE("Unable to create listening socket\n");
2303 /* We obtain our ip addr from the name of the command channel socket */
2304 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2306 /* and get the system to assign us a port */
2307 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2309 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2311 TRACE("Unable to bind socket\n");
2315 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2317 TRACE("listen failed\n");
2321 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2325 if (!bSuccess && lpwfs->lstnSocket == -1)
2327 closesocket(lpwfs->lstnSocket);
2328 lpwfs->lstnSocket = -1;
2335 /***********************************************************************
2336 * FTP_SendType (internal)
2338 * Tell server type of data being transferred
2344 * W98SE doesn't cache the type that's currently set
2345 * (i.e. it sends it always),
2346 * so we probably don't want to do that either.
2348 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2351 WCHAR type[] = { 'I','\0' };
2352 BOOL bSuccess = FALSE;
2355 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2358 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2361 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2367 FTP_SetResponseError(nResCode);
2374 /***********************************************************************
2375 * FTP_GetFileSize (internal)
2377 * Retrieves from the server the size of the given file
2384 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2387 BOOL bSuccess = FALSE;
2391 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2394 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2397 if (nResCode == 213) {
2398 /* Now parses the output to get the actual file size */
2400 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2402 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2403 if (lpszResponseBuffer[i] == '\0') return FALSE;
2404 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2408 FTP_SetResponseError(nResCode);
2417 /***********************************************************************
2418 * FTP_SendPort (internal)
2420 * Tell server which port to use
2427 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2429 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2431 WCHAR szIPAddress[64];
2432 BOOL bSuccess = FALSE;
2435 sprintfW(szIPAddress, szIPFormat,
2436 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2437 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2438 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2439 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2440 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2441 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2443 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2446 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2449 if (nResCode == 200)
2452 FTP_SetResponseError(nResCode);
2460 /***********************************************************************
2461 * FTP_DoPassive (internal)
2463 * Tell server that we want to do passive transfers
2464 * and connect data socket
2471 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2474 BOOL bSuccess = FALSE;
2477 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2480 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2483 if (nResCode == 227)
2485 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2489 char *pAddr, *pPort;
2491 struct sockaddr_in dataSocketAddress;
2493 p = lpszResponseBuffer+4; /* skip status code */
2495 /* do a very strict check; we can improve that later. */
2497 if (strncmp(p, "Entering Passive Mode", 21))
2499 ERR("unknown response '%.*s', aborting\n", 21, p);
2502 p += 21; /* skip string */
2503 if ((*p++ != ' ') || (*p++ != '('))
2505 ERR("unknown response format, aborting\n");
2509 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2512 ERR("unknown response address format '%s', aborting\n", p);
2515 for (i=0; i < 6; i++)
2518 dataSocketAddress = lpwfs->socketAddress;
2519 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2520 pPort = (char *)&(dataSocketAddress.sin_port);
2528 nsocket = socket(AF_INET,SOCK_STREAM,0);
2532 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2534 ERR("can't connect passive FTP data port.\n");
2535 closesocket(nsocket);
2538 lpwfs->pasvSocket = nsocket;
2542 FTP_SetResponseError(nResCode);
2550 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2552 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2554 if (!FTP_DoPassive(lpwfs))
2559 if (!FTP_SendPort(lpwfs))
2566 /***********************************************************************
2567 * FTP_GetDataSocket (internal)
2569 * Either accepts an incoming data socket connection from the server
2570 * or just returns the already opened socket after a PASV command
2571 * in case of passive FTP.
2579 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2581 struct sockaddr_in saddr;
2582 size_t addrlen = sizeof(struct sockaddr);
2585 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2587 *nDataSocket = lpwfs->pasvSocket;
2591 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2592 closesocket(lpwfs->lstnSocket);
2593 lpwfs->lstnSocket = -1;
2595 return *nDataSocket != -1;
2599 /***********************************************************************
2600 * FTP_SendData (internal)
2602 * Send data to the server
2609 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2611 BY_HANDLE_FILE_INFORMATION fi;
2612 DWORD nBytesRead = 0;
2613 DWORD nBytesSent = 0;
2614 DWORD nTotalSent = 0;
2615 DWORD nBytesToSend, nLen;
2617 time_t s_long_time, e_long_time;
2622 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2623 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2625 /* Get the size of the file. */
2626 GetFileInformationByHandle(hFile, &fi);
2631 nBytesToSend = nBytesRead - nBytesSent;
2633 if (nBytesToSend <= 0)
2635 /* Read data from file. */
2637 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2638 ERR("Failed reading from file\n");
2641 nBytesToSend = nBytesRead;
2646 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2647 DATA_PACKET_SIZE : nBytesToSend;
2648 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2656 /* Do some computation to display the status. */
2658 nSeconds = e_long_time - s_long_time;
2659 if( nSeconds / 60 > 0 )
2661 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2662 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2663 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2667 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2668 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2669 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2671 } while (nRC != -1);
2673 TRACE("file transfer complete!\n");
2675 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2681 /***********************************************************************
2682 * FTP_SendRetrieve (internal)
2684 * Send request to retrieve a file
2687 * Number of bytes to be received on success
2691 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2697 if (!FTP_InitListenSocket(lpwfs))
2700 if (!FTP_SendType(lpwfs, dwType))
2703 if (!FTP_SendPortOrPasv(lpwfs))
2706 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2709 TRACE("Waiting to receive %d bytes\n", nResult);
2711 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2714 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2715 if ((nResCode != 125) && (nResCode != 150)) {
2716 /* That means that we got an error getting the file. */
2721 if (0 == nResult && lpwfs->lstnSocket != -1)
2723 closesocket(lpwfs->lstnSocket);
2724 lpwfs->lstnSocket = -1;
2731 /***********************************************************************
2732 * FTP_RetrieveData (internal)
2734 * Retrieve data from server
2741 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2743 DWORD nBytesWritten;
2744 DWORD nBytesReceived = 0;
2750 if (INVALID_HANDLE_VALUE == hFile)
2753 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2754 if (NULL == lpszBuffer)
2756 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2760 while (nBytesReceived < nBytes && nRC != -1)
2762 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2765 /* other side closed socket. */
2768 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2769 nBytesReceived += nRC;
2772 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2773 nBytesReceived * 100 / nBytes);
2776 TRACE("Data transfer complete\n");
2777 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2784 /***********************************************************************
2785 * FTP_CloseSessionHandle (internal)
2787 * Deallocate session handle
2794 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2796 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2800 WININET_Release(&lpwfs->lpAppInfo->hdr);
2802 if (lpwfs->download_in_progress != NULL)
2803 lpwfs->download_in_progress->session_deleted = TRUE;
2805 if (lpwfs->sndSocket != -1)
2806 closesocket(lpwfs->sndSocket);
2808 if (lpwfs->lstnSocket != -1)
2809 closesocket(lpwfs->lstnSocket);
2811 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2812 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2813 HeapFree(GetProcessHeap(), 0, lpwfs);
2817 /***********************************************************************
2818 * FTP_FindNextFileW (Internal)
2820 * Continues a file search from a previous call to FindFirstFile
2827 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2829 BOOL bSuccess = TRUE;
2830 LPWIN32_FIND_DATAW lpFindFileData;
2832 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2834 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2836 /* Clear any error information */
2837 INTERNET_SetLastError(0);
2839 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2840 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2842 if (lpwh->index >= lpwh->size)
2844 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2849 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2852 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2856 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2858 INTERNET_ASYNC_RESULT iar;
2860 iar.dwResult = (DWORD)bSuccess;
2861 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2862 INTERNET_GetLastError();
2864 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2865 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2866 sizeof(INTERNET_ASYNC_RESULT));
2873 /***********************************************************************
2874 * FTP_CloseFindNextHandle (internal)
2876 * Deallocate session handle
2883 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2885 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2890 WININET_Release(&lpwfn->lpFtpSession->hdr);
2892 for (i = 0; i < lpwfn->size; i++)
2894 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2897 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2898 HeapFree(GetProcessHeap(), 0, lpwfn);
2901 /***********************************************************************
2902 * FTP_CloseFileTransferHandle (internal)
2904 * Closes the file transfer handle. This also 'cleans' the data queue of
2905 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2908 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2910 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2911 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2916 WININET_Release(&lpwh->lpFtpSession->hdr);
2918 if (!lpwh->session_deleted)
2919 lpwfs->download_in_progress = NULL;
2921 /* This just serves to flush the control socket of any spurrious lines written
2922 to it (like '226 Transfer complete.').
2924 Wonder what to do if the server sends us an error code though...
2926 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2928 if (lpwh->nDataSocket != -1)
2929 closesocket(lpwh->nDataSocket);
2931 HeapFree(GetProcessHeap(), 0, lpwh);
2934 /***********************************************************************
2935 * FTP_ReceiveFileList (internal)
2937 * Read file list from server
2940 * Handle to file list on success
2944 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2945 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2948 LPFILEPROPERTIESW lpafp = NULL;
2949 LPWININETFTPFINDNEXTW lpwfn = NULL;
2950 HINTERNET handle = 0;
2952 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2954 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2957 FTP_ConvertFileProp(lpafp, lpFindFileData);
2959 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
2962 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
2963 lpwfn->hdr.dwContext = dwContext;
2964 lpwfn->hdr.dwRefCount = 1;
2965 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2966 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2967 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2968 lpwfn->size = dwSize;
2969 lpwfn->lpafp = lpafp;
2971 WININET_AddRef( &lpwfs->hdr );
2972 lpwfn->lpFtpSession = lpwfs;
2974 handle = WININET_AllocHandle( &lpwfn->hdr );
2979 WININET_Release( &lpwfn->hdr );
2981 TRACE("Matched %d files\n", dwSize);
2986 /***********************************************************************
2987 * FTP_ConvertFileProp (internal)
2989 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2996 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2998 BOOL bSuccess = FALSE;
3000 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3004 /* Convert 'Unix' time to Windows time */
3005 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3006 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3007 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3008 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3010 /* Not all fields are filled in */
3011 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3012 lpFindFileData->nFileSizeLow = lpafp->nSize;
3014 if (lpafp->bIsDirectory)
3015 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3017 if (lpafp->lpszName)
3018 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3026 /***********************************************************************
3027 * FTP_ParseNextFile (internal)
3029 * Parse the next line in file listing
3035 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3037 static const char szSpace[] = " \t";
3045 lpfp->lpszName = NULL;
3047 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3050 pszToken = strtok(pszLine, szSpace);
3052 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3055 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3057 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3058 if(!FTP_ParsePermission(pszToken, lpfp))
3059 lpfp->bIsDirectory = FALSE;
3060 for(i=0; i<=3; i++) {
3061 if(!(pszToken = strtok(NULL, szSpace)))
3064 if(!pszToken) continue;
3065 if(lpfp->bIsDirectory) {
3066 TRACE("Is directory\n");
3070 TRACE("Size: %s\n", pszToken);
3071 lpfp->nSize = atol(pszToken);
3074 lpfp->tmLastModified.tm_sec = 0;
3075 lpfp->tmLastModified.tm_min = 0;
3076 lpfp->tmLastModified.tm_hour = 0;
3077 lpfp->tmLastModified.tm_mday = 0;
3078 lpfp->tmLastModified.tm_mon = 0;
3079 lpfp->tmLastModified.tm_year = 0;
3081 /* Determine month */
3082 pszToken = strtok(NULL, szSpace);
3083 if(!pszToken) continue;
3084 if(strlen(pszToken) >= 3) {
3086 if((pszTmp = StrStrIA(szMonths, pszToken)))
3087 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3090 pszToken = strtok(NULL, szSpace);
3091 if(!pszToken) continue;
3092 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3093 /* Determine time or year */
3094 pszToken = strtok(NULL, szSpace);
3095 if(!pszToken) continue;
3096 if((pszTmp = strchr(pszToken, ':'))) {
3101 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3102 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3104 apTM = localtime(&aTime);
3105 lpfp->tmLastModified.tm_year = apTM->tm_year;
3108 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3109 lpfp->tmLastModified.tm_hour = 12;
3111 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3112 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3113 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3114 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3116 pszToken = strtok(NULL, szSpace);
3117 if(!pszToken) continue;
3118 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3119 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3121 /* NT way of parsing ... :
3123 07-13-03 08:55PM <DIR> sakpatch
3124 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3126 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3127 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3129 sscanf(pszToken, "%d-%d-%d",
3130 &lpfp->tmLastModified.tm_mon,
3131 &lpfp->tmLastModified.tm_mday,
3132 &lpfp->tmLastModified.tm_year);
3134 /* Hacky and bad Y2K protection :-) */
3135 if (lpfp->tmLastModified.tm_year < 70)
3136 lpfp->tmLastModified.tm_year += 100;
3138 pszToken = strtok(NULL, szSpace);
3139 if(!pszToken) continue;
3140 sscanf(pszToken, "%d:%d",
3141 &lpfp->tmLastModified.tm_hour,
3142 &lpfp->tmLastModified.tm_min);
3143 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3144 lpfp->tmLastModified.tm_hour += 12;
3146 lpfp->tmLastModified.tm_sec = 0;
3148 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3149 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3150 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3151 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3153 pszToken = strtok(NULL, szSpace);
3154 if(!pszToken) continue;
3155 if(!strcasecmp(pszToken, "<DIR>")) {
3156 lpfp->bIsDirectory = TRUE;
3158 TRACE("Is directory\n");
3161 lpfp->bIsDirectory = FALSE;
3162 lpfp->nSize = atol(pszToken);
3163 TRACE("Size: %d\n", lpfp->nSize);
3166 pszToken = strtok(NULL, szSpace);
3167 if(!pszToken) continue;
3168 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3169 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3171 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3172 else if(pszToken[0] == '+') {
3173 FIXME("EPLF Format not implemented\n");
3176 if(lpfp->lpszName) {
3177 if((lpszSearchFile == NULL) ||
3178 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3180 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3183 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3184 lpfp->lpszName = NULL;
3191 /***********************************************************************
3192 * FTP_ParseDirectory (internal)
3194 * Parse string of directory information
3200 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3201 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3203 BOOL bSuccess = TRUE;
3204 INT sizeFilePropArray = 500;/*20; */
3205 INT indexFilePropArray = -1;
3209 /* Allocate intial file properties array */
3210 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3215 if (indexFilePropArray+1 >= sizeFilePropArray)
3217 LPFILEPROPERTIESW tmpafp;
3219 sizeFilePropArray *= 2;
3220 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3221 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3230 indexFilePropArray++;
3231 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3233 if (bSuccess && indexFilePropArray)
3235 if (indexFilePropArray < sizeFilePropArray - 1)
3237 LPFILEPROPERTIESW tmpafp;
3239 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3240 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3244 *dwfp = indexFilePropArray;
3248 HeapFree(GetProcessHeap(), 0, *lpafp);
3249 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3257 /***********************************************************************
3258 * FTP_ParsePermission (internal)
3260 * Parse permission string of directory information
3267 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3269 BOOL bSuccess = TRUE;
3270 unsigned short nPermission = 0;
3275 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3281 lpfp->bIsDirectory = (*lpszPermission == 'd');
3287 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3290 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3293 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3296 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3299 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3302 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3305 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3308 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3311 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3315 }while (nPos <= nLast);
3317 lpfp->permissions = nPermission;
3322 /***********************************************************************
3323 * FTP_SetResponseError (internal)
3325 * Set the appropriate error code for a given response from the server
3330 static DWORD FTP_SetResponseError(DWORD dwResponse)
3336 case 421: /* Service not available - Server may be shutting down. */
3337 dwCode = ERROR_INTERNET_TIMEOUT;
3340 case 425: /* Cannot open data connection. */
3341 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3344 case 426: /* Connection closed, transer aborted. */
3345 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3348 case 500: /* Syntax error. Command unrecognized. */
3349 case 501: /* Syntax error. Error in parameters or arguments. */
3350 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3353 case 530: /* Not logged in. Login incorrect. */
3354 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3357 case 550: /* File action not taken. File not found or no access. */
3358 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3361 case 450: /* File action not taken. File may be busy. */
3362 case 451: /* Action aborted. Server error. */
3363 case 452: /* Action not taken. Insufficient storage space on server. */
3364 case 502: /* Command not implemented. */
3365 case 503: /* Bad sequence of command. */
3366 case 504: /* Command not implemented for that parameter. */
3367 case 532: /* Need account for storing files */
3368 case 551: /* Requested action aborted. Page type unknown */
3369 case 552: /* Action aborted. Exceeded storage allocation */
3370 case 553: /* Action not taken. File name not allowed. */
3373 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3377 INTERNET_SetLastError(dwCode);