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 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 dwContext);
133 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
134 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, 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_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
141 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
142 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
143 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
144 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
145 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
146 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
147 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
148 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
149 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
150 static DWORD FTP_SetResponseError(DWORD dwResponse);
152 /***********************************************************************
153 * FtpPutFileA (WININET.@)
155 * Uploads a file to the FTP server
162 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
163 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
165 LPWSTR lpwzLocalFile;
166 LPWSTR lpwzNewRemoteFile;
169 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
170 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
171 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
173 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
174 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
178 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
180 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
181 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
183 TRACE("%p\n", lpwfs);
185 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
186 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
188 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
189 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
192 /***********************************************************************
193 * FtpPutFileW (WININET.@)
195 * Uploads a file to the FTP server
202 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
203 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
205 LPWININETFTPSESSIONW lpwfs;
206 LPWININETAPPINFOW hIC = NULL;
209 if (!lpszLocalFile || !lpszNewRemoteFile)
211 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
215 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
218 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
222 if (WH_HFTPSESSION != lpwfs->hdr.htype)
224 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
228 if ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
230 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
234 hIC = lpwfs->lpAppInfo;
235 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
237 WORKREQUEST workRequest;
238 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
240 workRequest.asyncproc = AsyncFtpPutFileProc;
241 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
242 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
243 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
244 req->dwFlags = dwFlags;
245 req->dwContext = dwContext;
247 r = INTERNET_AsyncCall(&workRequest);
251 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
252 lpszNewRemoteFile, dwFlags, dwContext);
256 WININET_Release( &lpwfs->hdr );
261 /***********************************************************************
262 * FTP_FtpPutFileW (Internal)
264 * Uploads a file to the FTP server
271 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
272 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
275 BOOL bSuccess = FALSE;
276 LPWININETAPPINFOW hIC = NULL;
279 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
281 /* Clear any error information */
282 INTERNET_SetLastError(0);
284 /* Open file to be uploaded */
285 if (INVALID_HANDLE_VALUE ==
286 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
287 /* Let CreateFile set the appropriate error */
290 hIC = lpwfs->lpAppInfo;
292 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
294 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
298 /* Get data socket to server */
299 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
301 FTP_SendData(lpwfs, nDataSocket, hFile);
302 closesocket(nDataSocket);
303 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
309 FTP_SetResponseError(nResCode);
314 if (lpwfs->lstnSocket != -1)
315 closesocket(lpwfs->lstnSocket);
317 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
319 INTERNET_ASYNC_RESULT iar;
321 iar.dwResult = (DWORD)bSuccess;
322 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
323 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
324 &iar, sizeof(INTERNET_ASYNC_RESULT));
334 /***********************************************************************
335 * FtpSetCurrentDirectoryA (WININET.@)
337 * Change the working directory on the FTP server
344 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
346 LPWSTR lpwzDirectory;
349 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
350 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
351 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
356 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
358 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
359 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
361 TRACE("%p\n", lpwfs);
363 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
364 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
367 /***********************************************************************
368 * FtpSetCurrentDirectoryW (WININET.@)
370 * Change the working directory on the FTP server
377 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
379 LPWININETFTPSESSIONW lpwfs = NULL;
380 LPWININETAPPINFOW hIC = NULL;
385 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
389 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
390 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
392 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
396 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
398 hIC = lpwfs->lpAppInfo;
399 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
401 WORKREQUEST workRequest;
402 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
404 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
405 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
406 req = &workRequest.u.FtpSetCurrentDirectoryW;
407 req->lpszDirectory = WININET_strdupW(lpszDirectory);
409 r = INTERNET_AsyncCall(&workRequest);
413 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
418 WININET_Release( &lpwfs->hdr );
424 /***********************************************************************
425 * FTP_FtpSetCurrentDirectoryW (Internal)
427 * Change the working directory on the FTP server
434 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
437 LPWININETAPPINFOW hIC = NULL;
438 DWORD bSuccess = FALSE;
440 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
442 /* Clear any error information */
443 INTERNET_SetLastError(0);
445 hIC = lpwfs->lpAppInfo;
446 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
447 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
450 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
457 FTP_SetResponseError(nResCode);
461 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
463 INTERNET_ASYNC_RESULT iar;
465 iar.dwResult = (DWORD)bSuccess;
466 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
467 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
468 &iar, sizeof(INTERNET_ASYNC_RESULT));
474 /***********************************************************************
475 * FtpCreateDirectoryA (WININET.@)
477 * Create new directory on the FTP server
484 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
486 LPWSTR lpwzDirectory;
489 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
490 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
491 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
496 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
498 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
499 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
501 TRACE(" %p\n", lpwfs);
503 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
504 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
507 /***********************************************************************
508 * FtpCreateDirectoryW (WININET.@)
510 * Create new directory on the FTP server
517 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
519 LPWININETFTPSESSIONW lpwfs;
520 LPWININETAPPINFOW hIC = NULL;
523 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
526 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
530 if (WH_HFTPSESSION != lpwfs->hdr.htype)
532 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
538 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
542 hIC = lpwfs->lpAppInfo;
543 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
545 WORKREQUEST workRequest;
546 struct WORKREQ_FTPCREATEDIRECTORYW *req;
548 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
549 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
550 req = &workRequest.u.FtpCreateDirectoryW;
551 req->lpszDirectory = WININET_strdupW(lpszDirectory);
553 r = INTERNET_AsyncCall(&workRequest);
557 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
560 WININET_Release( &lpwfs->hdr );
566 /***********************************************************************
567 * FTP_FtpCreateDirectoryW (Internal)
569 * Create new directory on the FTP server
576 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
579 BOOL bSuccess = FALSE;
580 LPWININETAPPINFOW hIC = NULL;
582 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
584 /* Clear any error information */
585 INTERNET_SetLastError(0);
587 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
590 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
596 FTP_SetResponseError(nResCode);
600 hIC = lpwfs->lpAppInfo;
601 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
603 INTERNET_ASYNC_RESULT iar;
605 iar.dwResult = (DWORD)bSuccess;
606 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
607 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
608 &iar, sizeof(INTERNET_ASYNC_RESULT));
614 /***********************************************************************
615 * FtpFindFirstFileA (WININET.@)
617 * Search the specified directory
620 * HINTERNET on success
624 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
625 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
627 LPWSTR lpwzSearchFile;
628 WIN32_FIND_DATAW wfd;
629 LPWIN32_FIND_DATAW lpFindFileDataW;
632 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
633 lpFindFileDataW = lpFindFileData?&wfd:NULL;
634 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
635 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
638 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
644 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
646 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
647 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
649 TRACE("%p\n", lpwfs);
651 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
652 req->lpFindFileData, req->dwFlags, req->dwContext);
653 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
656 /***********************************************************************
657 * FtpFindFirstFileW (WININET.@)
659 * Search the specified directory
662 * HINTERNET on success
666 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
667 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
669 LPWININETFTPSESSIONW lpwfs;
670 LPWININETAPPINFOW hIC = NULL;
673 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
674 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
676 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
680 hIC = lpwfs->lpAppInfo;
681 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
683 WORKREQUEST workRequest;
684 struct WORKREQ_FTPFINDFIRSTFILEW *req;
686 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
687 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
688 req = &workRequest.u.FtpFindFirstFileW;
689 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
690 req->lpFindFileData = lpFindFileData;
691 req->dwFlags = dwFlags;
692 req->dwContext= dwContext;
694 INTERNET_AsyncCall(&workRequest);
699 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
704 WININET_Release( &lpwfs->hdr );
710 /***********************************************************************
711 * FTP_FtpFindFirstFileW (Internal)
713 * Search the specified directory
716 * HINTERNET on success
720 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
721 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
724 LPWININETAPPINFOW hIC = NULL;
725 HINTERNET hFindNext = NULL;
729 /* Clear any error information */
730 INTERNET_SetLastError(0);
732 if (!FTP_InitListenSocket(lpwfs))
735 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
738 if (!FTP_SendPortOrPasv(lpwfs))
741 hIC = lpwfs->lpAppInfo;
742 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
743 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
746 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
749 if (nResCode == 125 || nResCode == 150)
753 /* Get data socket to server */
754 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
756 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
757 closesocket(nDataSocket);
758 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
759 if (nResCode != 226 && nResCode != 250)
760 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
764 FTP_SetResponseError(nResCode);
768 if (lpwfs->lstnSocket != -1)
769 closesocket(lpwfs->lstnSocket);
771 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
773 INTERNET_ASYNC_RESULT iar;
777 iar.dwResult = (DWORD)hFindNext;
778 iar.dwError = ERROR_SUCCESS;
779 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
780 &iar, sizeof(INTERNET_ASYNC_RESULT));
783 iar.dwResult = (DWORD)hFindNext;
784 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
785 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
786 &iar, sizeof(INTERNET_ASYNC_RESULT));
793 /***********************************************************************
794 * FtpGetCurrentDirectoryA (WININET.@)
796 * Retrieves the current directory
803 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
804 LPDWORD lpdwCurrentDirectory)
810 if(lpdwCurrentDirectory) {
811 len = *lpdwCurrentDirectory;
812 if(lpszCurrentDirectory)
814 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
817 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
822 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
823 if(lpdwCurrentDirectory) {
824 *lpdwCurrentDirectory = len;
825 if(lpszCurrentDirectory) {
826 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
827 HeapFree(GetProcessHeap(), 0, dir);
834 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
836 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
837 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
839 TRACE("%p\n", lpwfs);
841 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
844 /***********************************************************************
845 * FtpGetCurrentDirectoryW (WININET.@)
847 * Retrieves the current directory
854 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
855 LPDWORD lpdwCurrentDirectory)
857 LPWININETFTPSESSIONW lpwfs;
858 LPWININETAPPINFOW hIC = NULL;
861 TRACE("len(%d)\n", *lpdwCurrentDirectory);
863 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
864 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
866 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
870 hIC = lpwfs->lpAppInfo;
871 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
873 WORKREQUEST workRequest;
874 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
876 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
877 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
878 req = &workRequest.u.FtpGetCurrentDirectoryW;
879 req->lpszDirectory = lpszCurrentDirectory;
880 req->lpdwDirectory = lpdwCurrentDirectory;
882 r = INTERNET_AsyncCall(&workRequest);
886 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
887 lpdwCurrentDirectory);
892 WININET_Release( &lpwfs->hdr );
898 /***********************************************************************
899 * FTP_FtpGetCurrentDirectoryW (Internal)
901 * Retrieves the current directory
908 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
909 LPDWORD lpdwCurrentDirectory)
912 LPWININETAPPINFOW hIC = NULL;
913 DWORD bSuccess = FALSE;
915 TRACE("len(%d)\n", *lpdwCurrentDirectory);
917 /* Clear any error information */
918 INTERNET_SetLastError(0);
920 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
922 hIC = lpwfs->lpAppInfo;
923 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
924 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
927 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
930 if (nResCode == 257) /* Extract directory name */
932 DWORD firstpos, lastpos, len;
933 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
935 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
937 if ('"' == lpszResponseBuffer[lastpos])
946 len = lastpos - firstpos - 1;
947 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
948 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
949 *lpdwCurrentDirectory = len;
953 FTP_SetResponseError(nResCode);
957 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
959 INTERNET_ASYNC_RESULT iar;
961 iar.dwResult = (DWORD)bSuccess;
962 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
963 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
964 &iar, sizeof(INTERNET_ASYNC_RESULT));
967 return (DWORD) bSuccess;
970 /***********************************************************************
971 * FtpOpenFileA (WININET.@)
973 * Open a remote file for writing or reading
976 * HINTERNET handle on success
980 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
981 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
987 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
988 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
989 HeapFree(GetProcessHeap(), 0, lpwzFileName);
994 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
996 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
997 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
999 TRACE("%p\n", lpwfs);
1001 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1002 req->dwAccess, req->dwFlags, req->dwContext);
1003 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1006 /***********************************************************************
1007 * FtpOpenFileW (WININET.@)
1009 * Open a remote file for writing or reading
1012 * HINTERNET handle on success
1016 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1017 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1020 LPWININETFTPSESSIONW lpwfs;
1021 LPWININETAPPINFOW hIC = NULL;
1024 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession,
1025 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1027 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1030 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1034 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1036 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1040 if ((!lpszFileName) ||
1041 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1042 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1044 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1048 if (lpwfs->download_in_progress != NULL) {
1049 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1052 hIC = lpwfs->lpAppInfo;
1053 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1055 WORKREQUEST workRequest;
1056 struct WORKREQ_FTPOPENFILEW *req;
1058 workRequest.asyncproc = AsyncFtpOpenFileProc;
1059 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1060 req = &workRequest.u.FtpOpenFileW;
1061 req->lpszFilename = WININET_strdupW(lpszFileName);
1062 req->dwAccess = fdwAccess;
1063 req->dwFlags = dwFlags;
1064 req->dwContext = dwContext;
1066 INTERNET_AsyncCall(&workRequest);
1071 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1075 WININET_Release( &lpwfs->hdr );
1081 /***********************************************************************
1082 * FTP_FtpOpenFileW (Internal)
1084 * Open a remote file for writing or reading
1087 * HINTERNET handle on success
1091 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1092 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1096 BOOL bSuccess = FALSE;
1097 LPWININETFTPFILE lpwh = NULL;
1098 LPWININETAPPINFOW hIC = NULL;
1099 HINTERNET handle = NULL;
1103 /* Clear any error information */
1104 INTERNET_SetLastError(0);
1106 if (GENERIC_READ == fdwAccess)
1108 /* Set up socket to retrieve data */
1109 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1111 else if (GENERIC_WRITE == fdwAccess)
1113 /* Set up socket to send data */
1114 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1117 /* Get data socket to server */
1118 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1120 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1121 lpwh->hdr.htype = WH_HFILE;
1122 lpwh->hdr.dwFlags = dwFlags;
1123 lpwh->hdr.dwContext = dwContext;
1124 lpwh->hdr.dwRefCount = 1;
1125 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1126 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1127 lpwh->nDataSocket = nDataSocket;
1128 lpwh->session_deleted = FALSE;
1130 WININET_AddRef( &lpwfs->hdr );
1131 lpwh->lpFtpSession = lpwfs;
1133 handle = WININET_AllocHandle( &lpwh->hdr );
1137 /* Indicate that a download is currently in progress */
1138 lpwfs->download_in_progress = lpwh;
1141 if (lpwfs->lstnSocket != -1)
1142 closesocket(lpwfs->lstnSocket);
1144 hIC = lpwfs->lpAppInfo;
1145 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1147 INTERNET_ASYNC_RESULT iar;
1151 iar.dwResult = (DWORD)handle;
1152 iar.dwError = ERROR_SUCCESS;
1153 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1154 &iar, sizeof(INTERNET_ASYNC_RESULT));
1157 iar.dwResult = (DWORD)bSuccess;
1158 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1159 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1160 &iar, sizeof(INTERNET_ASYNC_RESULT));
1165 WININET_Release( &lpwh->hdr );
1171 /***********************************************************************
1172 * FtpGetFileA (WININET.@)
1174 * Retrieve file from the FTP server
1181 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1182 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1185 LPWSTR lpwzRemoteFile;
1189 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1190 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1191 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1192 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1193 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1194 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1199 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1201 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1202 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1204 TRACE("%p\n", lpwfs);
1206 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1207 req->lpszNewFile, req->fFailIfExists,
1208 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1209 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1210 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1214 /***********************************************************************
1215 * FtpGetFileW (WININET.@)
1217 * Retrieve file from the FTP server
1224 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1225 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1228 LPWININETFTPSESSIONW lpwfs;
1229 LPWININETAPPINFOW hIC = NULL;
1232 if (!lpszRemoteFile || !lpszNewFile)
1234 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1238 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1241 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1245 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1247 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1251 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1253 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1257 if (lpwfs->download_in_progress != NULL) {
1258 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1262 hIC = lpwfs->lpAppInfo;
1263 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1265 WORKREQUEST workRequest;
1266 struct WORKREQ_FTPGETFILEW *req;
1268 workRequest.asyncproc = AsyncFtpGetFileProc;
1269 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1270 req = &workRequest.u.FtpGetFileW;
1271 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1272 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1273 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1274 req->fFailIfExists = fFailIfExists;
1275 req->dwFlags = dwInternetFlags;
1276 req->dwContext = dwContext;
1278 r = INTERNET_AsyncCall(&workRequest);
1282 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1283 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1287 WININET_Release( &lpwfs->hdr );
1293 /***********************************************************************
1294 * FTP_FtpGetFileW (Internal)
1296 * Retrieve file from the FTP server
1303 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1304 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1308 BOOL bSuccess = FALSE;
1310 LPWININETAPPINFOW hIC = NULL;
1312 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1314 /* Clear any error information */
1315 INTERNET_SetLastError(0);
1317 /* Ensure we can write to lpszNewfile by opening it */
1318 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1319 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1320 if (INVALID_HANDLE_VALUE == hFile)
1323 /* Set up socket to retrieve data */
1324 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1330 /* Get data socket to server */
1331 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1336 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1337 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1340 if (nResCode == 226)
1343 FTP_SetResponseError(nResCode);
1345 closesocket(nDataSocket);
1350 if (lpwfs->lstnSocket != -1)
1351 closesocket(lpwfs->lstnSocket);
1356 hIC = lpwfs->lpAppInfo;
1357 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1359 INTERNET_ASYNC_RESULT iar;
1361 iar.dwResult = (DWORD)bSuccess;
1362 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1363 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1364 &iar, sizeof(INTERNET_ASYNC_RESULT));
1370 /***********************************************************************
1371 * FtpGetFileSize (WININET.@)
1373 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1375 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1377 if (lpdwFileSizeHigh)
1378 *lpdwFileSizeHigh = 0;
1383 /***********************************************************************
1384 * FtpDeleteFileA (WININET.@)
1386 * Delete a file on the ftp server
1393 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1395 LPWSTR lpwzFileName;
1398 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1399 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1400 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1404 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1406 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1407 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1409 TRACE("%p\n", lpwfs);
1411 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1412 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1415 /***********************************************************************
1416 * FtpDeleteFileW (WININET.@)
1418 * Delete a file on the ftp server
1425 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1427 LPWININETFTPSESSIONW lpwfs;
1428 LPWININETAPPINFOW hIC = NULL;
1431 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1434 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1438 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1440 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1446 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1450 hIC = lpwfs->lpAppInfo;
1451 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1453 WORKREQUEST workRequest;
1454 struct WORKREQ_FTPDELETEFILEW *req;
1456 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1457 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1458 req = &workRequest.u.FtpDeleteFileW;
1459 req->lpszFilename = WININET_strdupW(lpszFileName);
1461 r = INTERNET_AsyncCall(&workRequest);
1465 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1469 WININET_Release( &lpwfs->hdr );
1474 /***********************************************************************
1475 * FTP_FtpDeleteFileW (Internal)
1477 * Delete a file on the ftp server
1484 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1487 BOOL bSuccess = FALSE;
1488 LPWININETAPPINFOW hIC = NULL;
1490 TRACE("%p\n", lpwfs);
1492 /* Clear any error information */
1493 INTERNET_SetLastError(0);
1495 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1498 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1501 if (nResCode == 250)
1504 FTP_SetResponseError(nResCode);
1507 hIC = lpwfs->lpAppInfo;
1508 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1510 INTERNET_ASYNC_RESULT iar;
1512 iar.dwResult = (DWORD)bSuccess;
1513 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1514 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1515 &iar, sizeof(INTERNET_ASYNC_RESULT));
1522 /***********************************************************************
1523 * FtpRemoveDirectoryA (WININET.@)
1525 * Remove a directory on the ftp server
1532 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1534 LPWSTR lpwzDirectory;
1537 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1538 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1539 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1543 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1545 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1546 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1548 TRACE("%p\n", lpwfs);
1550 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1551 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1554 /***********************************************************************
1555 * FtpRemoveDirectoryW (WININET.@)
1557 * Remove a directory on the ftp server
1564 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1566 LPWININETFTPSESSIONW lpwfs;
1567 LPWININETAPPINFOW hIC = NULL;
1570 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1573 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1577 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1579 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1585 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1589 hIC = lpwfs->lpAppInfo;
1590 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1592 WORKREQUEST workRequest;
1593 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1595 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1596 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1597 req = &workRequest.u.FtpRemoveDirectoryW;
1598 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1600 r = INTERNET_AsyncCall(&workRequest);
1604 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1608 WININET_Release( &lpwfs->hdr );
1613 /***********************************************************************
1614 * FTP_FtpRemoveDirectoryW (Internal)
1616 * Remove a directory on the ftp server
1623 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1626 BOOL bSuccess = FALSE;
1627 LPWININETAPPINFOW hIC = NULL;
1631 /* Clear any error information */
1632 INTERNET_SetLastError(0);
1634 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1637 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1640 if (nResCode == 250)
1643 FTP_SetResponseError(nResCode);
1647 hIC = lpwfs->lpAppInfo;
1648 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1650 INTERNET_ASYNC_RESULT iar;
1652 iar.dwResult = (DWORD)bSuccess;
1653 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1654 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1655 &iar, sizeof(INTERNET_ASYNC_RESULT));
1662 /***********************************************************************
1663 * FtpRenameFileA (WININET.@)
1665 * Rename a file on the ftp server
1672 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1678 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1679 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1680 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1681 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1682 HeapFree(GetProcessHeap(), 0, lpwzDest);
1686 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1688 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1689 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1691 TRACE("%p\n", lpwfs);
1693 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1694 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1695 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1698 /***********************************************************************
1699 * FtpRenameFileW (WININET.@)
1701 * Rename a file on the ftp server
1708 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1710 LPWININETFTPSESSIONW lpwfs;
1711 LPWININETAPPINFOW hIC = NULL;
1714 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1717 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1721 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1723 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1727 if (!lpszSrc || !lpszDest)
1729 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1733 hIC = lpwfs->lpAppInfo;
1734 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1736 WORKREQUEST workRequest;
1737 struct WORKREQ_FTPRENAMEFILEW *req;
1739 workRequest.asyncproc = AsyncFtpRenameFileProc;
1740 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1741 req = &workRequest.u.FtpRenameFileW;
1742 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1743 req->lpszDestFile = WININET_strdupW(lpszDest);
1745 r = INTERNET_AsyncCall(&workRequest);
1749 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1753 WININET_Release( &lpwfs->hdr );
1758 /***********************************************************************
1759 * FTP_FtpRenameFileW (Internal)
1761 * Rename a file on the ftp server
1768 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1769 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1772 BOOL bSuccess = FALSE;
1773 LPWININETAPPINFOW hIC = NULL;
1777 /* Clear any error information */
1778 INTERNET_SetLastError(0);
1780 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1783 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1784 if (nResCode == 350)
1786 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1789 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1792 if (nResCode == 250)
1795 FTP_SetResponseError(nResCode);
1798 hIC = lpwfs->lpAppInfo;
1799 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1801 INTERNET_ASYNC_RESULT iar;
1803 iar.dwResult = (DWORD)bSuccess;
1804 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1805 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1806 &iar, sizeof(INTERNET_ASYNC_RESULT));
1812 /***********************************************************************
1813 * FtpCommandA (WININET.@)
1815 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1816 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1818 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1819 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1824 /***********************************************************************
1825 * FtpCommandW (WININET.@)
1827 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1828 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1830 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1831 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1836 /***********************************************************************
1837 * FTP_Connect (internal)
1839 * Connect to a ftp server
1842 * HINTERNET a session handle on success
1847 * Windows uses 'anonymous' as the username, when given a NULL username
1848 * and a NULL password. The password is first looked up in:
1850 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1852 * If this entry is not present it uses the current username as the password.
1856 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1857 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1858 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1859 DWORD dwInternalFlags)
1861 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1862 'M','i','c','r','o','s','o','f','t','\\',
1863 'W','i','n','d','o','w','s','\\',
1864 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1865 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1866 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1867 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1868 static const WCHAR szEmpty[] = {'\0'};
1869 struct sockaddr_in socketAddr;
1872 BOOL bSuccess = FALSE;
1873 LPWININETFTPSESSIONW lpwfs = NULL;
1874 HINTERNET handle = NULL;
1876 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1877 hIC, debugstr_w(lpszServerName),
1878 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1880 assert( hIC->hdr.htype == WH_HINIT );
1882 if (NULL == lpszUserName && NULL != lpszPassword)
1884 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1888 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1891 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1895 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1896 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1898 lpwfs->hdr.htype = WH_HFTPSESSION;
1899 lpwfs->hdr.dwFlags = dwFlags;
1900 lpwfs->hdr.dwContext = dwContext;
1901 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1902 lpwfs->hdr.dwRefCount = 1;
1903 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1904 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1905 lpwfs->download_in_progress = NULL;
1907 WININET_AddRef( &hIC->hdr );
1908 lpwfs->lpAppInfo = hIC;
1910 handle = WININET_AllocHandle( &lpwfs->hdr );
1913 ERR("Failed to alloc handle\n");
1914 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1918 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1919 if(strchrW(hIC->lpszProxy, ' '))
1920 FIXME("Several proxies not implemented.\n");
1921 if(hIC->lpszProxyBypass)
1922 FIXME("Proxy bypass is ignored.\n");
1924 if ( !lpszUserName) {
1926 WCHAR szPassword[MAX_PATH];
1927 DWORD len = sizeof(szPassword);
1929 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1931 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1932 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1933 /* Nothing in the registry, get the username and use that as the password */
1934 if (!GetUserNameW(szPassword, &len)) {
1935 /* Should never get here, but use an empty password as failsafe */
1936 strcpyW(szPassword, szEmpty);
1941 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1942 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1945 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1948 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1950 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1953 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1954 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1956 INTERNET_ASYNC_RESULT iar;
1958 iar.dwResult = (DWORD)handle;
1959 iar.dwError = ERROR_SUCCESS;
1961 SendAsyncCallback(&hIC->hdr, dwContext,
1962 INTERNET_STATUS_HANDLE_CREATED, &iar,
1963 sizeof(INTERNET_ASYNC_RESULT));
1966 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1967 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1969 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1971 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1975 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1976 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1978 nsocket = socket(AF_INET,SOCK_STREAM,0);
1981 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1985 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1986 &socketAddr, sizeof(struct sockaddr_in));
1988 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1990 ERR("Unable to connect (%s)\n", strerror(errno));
1991 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1995 TRACE("Connected to server\n");
1996 lpwfs->sndSocket = nsocket;
1997 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1998 &socketAddr, sizeof(struct sockaddr_in));
2000 sock_namelen = sizeof(lpwfs->socketAddress);
2001 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2003 if (FTP_ConnectToHost(lpwfs))
2005 TRACE("Successfully logged into server\n");
2011 if (!bSuccess && nsocket == -1)
2012 closesocket(nsocket);
2014 if (!bSuccess && lpwfs)
2016 HeapFree(GetProcessHeap(), 0, lpwfs);
2017 WININET_FreeHandle( handle );
2022 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2024 INTERNET_ASYNC_RESULT iar;
2026 iar.dwResult = (DWORD)lpwfs;
2027 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2028 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2029 &iar, sizeof(INTERNET_ASYNC_RESULT));
2036 /***********************************************************************
2037 * FTP_ConnectToHost (internal)
2039 * Connect to a ftp server
2046 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2049 BOOL bSuccess = FALSE;
2052 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2054 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2057 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2060 /* Login successful... */
2061 if (nResCode == 230)
2063 /* User name okay, need password... */
2064 else if (nResCode == 331)
2065 bSuccess = FTP_SendPassword(lpwfs);
2066 /* Need account for login... */
2067 else if (nResCode == 332)
2068 bSuccess = FTP_SendAccount(lpwfs);
2070 FTP_SetResponseError(nResCode);
2073 TRACE("Returning %d\n", bSuccess);
2079 /***********************************************************************
2080 * FTP_SendCommandA (internal)
2082 * Send command to server
2089 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2090 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2094 DWORD nBytesSent = 0;
2098 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2102 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2105 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2106 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2107 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2109 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2112 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2113 dwParamLen ? lpszParam : "", szCRLF);
2115 TRACE("Sending (%s) len(%d)\n", buf, len);
2116 while((nBytesSent < len) && (nRC != -1))
2118 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2122 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2126 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2127 &nBytesSent, sizeof(DWORD));
2130 TRACE("Sent %d bytes\n", nBytesSent);
2134 /***********************************************************************
2135 * FTP_SendCommand (internal)
2137 * Send command to server
2144 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2145 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2148 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2149 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2150 HeapFree(GetProcessHeap(), 0, lpszParamA);
2154 /***********************************************************************
2155 * FTP_ReceiveResponse (internal)
2157 * Receive response from server
2160 * Reply code on success
2164 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2166 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2169 char firstprefix[5];
2170 BOOL multiline = FALSE;
2171 LPWININETAPPINFOW hIC = NULL;
2173 TRACE("socket(%d)\n", lpwfs->sndSocket);
2175 hIC = lpwfs->lpAppInfo;
2176 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2180 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2187 if(lpszResponse[3] != '-')
2190 { /* Start of multiline repsonse. Loop until we get "nnn " */
2192 memcpy(firstprefix, lpszResponse, 3);
2193 firstprefix[3] = ' ';
2194 firstprefix[4] = '\0';
2199 if(!memcmp(firstprefix, lpszResponse, 4))
2207 rc = atoi(lpszResponse);
2209 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2210 &nRecv, sizeof(DWORD));
2214 TRACE("return %d\n", rc);
2219 /***********************************************************************
2220 * FTP_SendPassword (internal)
2222 * Send password to ftp server
2229 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2232 BOOL bSuccess = FALSE;
2235 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2238 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2241 TRACE("Received reply code %d\n", nResCode);
2242 /* Login successful... */
2243 if (nResCode == 230)
2245 /* Command not implemented, superfluous at the server site... */
2246 /* Need account for login... */
2247 else if (nResCode == 332)
2248 bSuccess = FTP_SendAccount(lpwfs);
2250 FTP_SetResponseError(nResCode);
2254 TRACE("Returning %d\n", bSuccess);
2259 /***********************************************************************
2260 * FTP_SendAccount (internal)
2269 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2272 BOOL bSuccess = FALSE;
2275 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2278 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2282 FTP_SetResponseError(nResCode);
2289 /***********************************************************************
2290 * FTP_SendStore (internal)
2292 * Send request to upload file to ftp server
2299 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2302 BOOL bSuccess = FALSE;
2305 if (!FTP_InitListenSocket(lpwfs))
2308 if (!FTP_SendType(lpwfs, dwType))
2311 if (!FTP_SendPortOrPasv(lpwfs))
2314 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2316 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2319 if (nResCode == 150 || nResCode == 125)
2322 FTP_SetResponseError(nResCode);
2326 if (!bSuccess && lpwfs->lstnSocket != -1)
2328 closesocket(lpwfs->lstnSocket);
2329 lpwfs->lstnSocket = -1;
2336 /***********************************************************************
2337 * FTP_InitListenSocket (internal)
2339 * Create a socket to listen for server response
2346 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2348 BOOL bSuccess = FALSE;
2349 socklen_t namelen = sizeof(struct sockaddr_in);
2353 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2354 if (lpwfs->lstnSocket == -1)
2356 TRACE("Unable to create listening socket\n");
2360 /* We obtain our ip addr from the name of the command channel socket */
2361 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2363 /* and get the system to assign us a port */
2364 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2366 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2368 TRACE("Unable to bind socket\n");
2372 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2374 TRACE("listen failed\n");
2378 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2382 if (!bSuccess && lpwfs->lstnSocket == -1)
2384 closesocket(lpwfs->lstnSocket);
2385 lpwfs->lstnSocket = -1;
2392 /***********************************************************************
2393 * FTP_SendType (internal)
2395 * Tell server type of data being transferred
2401 * W98SE doesn't cache the type that's currently set
2402 * (i.e. it sends it always),
2403 * so we probably don't want to do that either.
2405 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2408 WCHAR type[] = { 'I','\0' };
2409 BOOL bSuccess = FALSE;
2412 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2415 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2418 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2424 FTP_SetResponseError(nResCode);
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);
2474 /***********************************************************************
2475 * FTP_SendPort (internal)
2477 * Tell server which port to use
2484 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2486 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2488 WCHAR szIPAddress[64];
2489 BOOL bSuccess = FALSE;
2492 sprintfW(szIPAddress, szIPFormat,
2493 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2494 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2495 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2496 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2497 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2498 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2500 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2503 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2506 if (nResCode == 200)
2509 FTP_SetResponseError(nResCode);
2517 /***********************************************************************
2518 * FTP_DoPassive (internal)
2520 * Tell server that we want to do passive transfers
2521 * and connect data socket
2528 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2531 BOOL bSuccess = FALSE;
2534 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2537 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2540 if (nResCode == 227)
2542 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2546 char *pAddr, *pPort;
2548 struct sockaddr_in dataSocketAddress;
2550 p = lpszResponseBuffer+4; /* skip status code */
2552 /* do a very strict check; we can improve that later. */
2554 if (strncmp(p, "Entering Passive Mode", 21))
2556 ERR("unknown response '%.*s', aborting\n", 21, p);
2559 p += 21; /* skip string */
2560 if ((*p++ != ' ') || (*p++ != '('))
2562 ERR("unknown response format, aborting\n");
2566 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2569 ERR("unknown response address format '%s', aborting\n", p);
2572 for (i=0; i < 6; i++)
2575 dataSocketAddress = lpwfs->socketAddress;
2576 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2577 pPort = (char *)&(dataSocketAddress.sin_port);
2585 nsocket = socket(AF_INET,SOCK_STREAM,0);
2589 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2591 ERR("can't connect passive FTP data port.\n");
2592 closesocket(nsocket);
2595 lpwfs->pasvSocket = nsocket;
2599 FTP_SetResponseError(nResCode);
2607 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2609 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2611 if (!FTP_DoPassive(lpwfs))
2616 if (!FTP_SendPort(lpwfs))
2623 /***********************************************************************
2624 * FTP_GetDataSocket (internal)
2626 * Either accepts an incoming data socket connection from the server
2627 * or just returns the already opened socket after a PASV command
2628 * in case of passive FTP.
2636 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2638 struct sockaddr_in saddr;
2639 socklen_t addrlen = sizeof(struct sockaddr);
2642 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2644 *nDataSocket = lpwfs->pasvSocket;
2648 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2649 closesocket(lpwfs->lstnSocket);
2650 lpwfs->lstnSocket = -1;
2652 return *nDataSocket != -1;
2656 /***********************************************************************
2657 * FTP_SendData (internal)
2659 * Send data to the server
2666 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2668 BY_HANDLE_FILE_INFORMATION fi;
2669 DWORD nBytesRead = 0;
2670 DWORD nBytesSent = 0;
2671 DWORD nTotalSent = 0;
2672 DWORD nBytesToSend, nLen;
2674 time_t s_long_time, e_long_time;
2679 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2680 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2682 /* Get the size of the file. */
2683 GetFileInformationByHandle(hFile, &fi);
2688 nBytesToSend = nBytesRead - nBytesSent;
2690 if (nBytesToSend <= 0)
2692 /* Read data from file. */
2694 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2695 ERR("Failed reading from file\n");
2698 nBytesToSend = nBytesRead;
2703 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2704 DATA_PACKET_SIZE : nBytesToSend;
2705 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2713 /* Do some computation to display the status. */
2715 nSeconds = e_long_time - s_long_time;
2716 if( nSeconds / 60 > 0 )
2718 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2719 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2720 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2724 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2725 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2726 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2728 } while (nRC != -1);
2730 TRACE("file transfer complete!\n");
2732 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2738 /***********************************************************************
2739 * FTP_SendRetrieve (internal)
2741 * Send request to retrieve a file
2744 * Number of bytes to be received on success
2748 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2754 if (!FTP_InitListenSocket(lpwfs))
2757 if (!FTP_SendType(lpwfs, dwType))
2760 if (!FTP_SendPortOrPasv(lpwfs))
2763 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2766 TRACE("Waiting to receive %d bytes\n", nResult);
2768 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2771 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2772 if ((nResCode != 125) && (nResCode != 150)) {
2773 /* That means that we got an error getting the file. */
2778 if (0 == nResult && lpwfs->lstnSocket != -1)
2780 closesocket(lpwfs->lstnSocket);
2781 lpwfs->lstnSocket = -1;
2788 /***********************************************************************
2789 * FTP_RetrieveData (internal)
2791 * Retrieve data from server
2798 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2800 DWORD nBytesWritten;
2801 DWORD nBytesReceived = 0;
2807 if (INVALID_HANDLE_VALUE == hFile)
2810 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2811 if (NULL == lpszBuffer)
2813 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2817 while (nBytesReceived < nBytes && nRC != -1)
2819 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2822 /* other side closed socket. */
2825 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2826 nBytesReceived += nRC;
2829 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2830 nBytesReceived * 100 / nBytes);
2833 TRACE("Data transfer complete\n");
2834 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2841 /***********************************************************************
2842 * FTP_CloseSessionHandle (internal)
2844 * Deallocate session handle
2851 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2853 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2857 WININET_Release(&lpwfs->lpAppInfo->hdr);
2859 if (lpwfs->download_in_progress != NULL)
2860 lpwfs->download_in_progress->session_deleted = TRUE;
2862 if (lpwfs->sndSocket != -1)
2863 closesocket(lpwfs->sndSocket);
2865 if (lpwfs->lstnSocket != -1)
2866 closesocket(lpwfs->lstnSocket);
2868 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2869 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2870 HeapFree(GetProcessHeap(), 0, lpwfs);
2874 /***********************************************************************
2875 * FTP_FindNextFileW (Internal)
2877 * Continues a file search from a previous call to FindFirstFile
2884 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2886 BOOL bSuccess = TRUE;
2887 LPWIN32_FIND_DATAW lpFindFileData;
2889 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2891 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2893 /* Clear any error information */
2894 INTERNET_SetLastError(0);
2896 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2897 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2899 if (lpwh->index >= lpwh->size)
2901 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2906 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2909 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2913 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2915 INTERNET_ASYNC_RESULT iar;
2917 iar.dwResult = (DWORD)bSuccess;
2918 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2919 INTERNET_GetLastError();
2921 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2922 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2923 sizeof(INTERNET_ASYNC_RESULT));
2930 /***********************************************************************
2931 * FTP_CloseFindNextHandle (internal)
2933 * Deallocate session handle
2940 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2942 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2947 WININET_Release(&lpwfn->lpFtpSession->hdr);
2949 for (i = 0; i < lpwfn->size; i++)
2951 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2954 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2955 HeapFree(GetProcessHeap(), 0, lpwfn);
2958 /***********************************************************************
2959 * FTP_CloseFileTransferHandle (internal)
2961 * Closes the file transfer handle. This also 'cleans' the data queue of
2962 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2965 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2967 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2968 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2973 WININET_Release(&lpwh->lpFtpSession->hdr);
2975 if (!lpwh->session_deleted)
2976 lpwfs->download_in_progress = NULL;
2978 /* This just serves to flush the control socket of any spurrious lines written
2979 to it (like '226 Transfer complete.').
2981 Wonder what to do if the server sends us an error code though...
2983 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2985 if (lpwh->nDataSocket != -1)
2986 closesocket(lpwh->nDataSocket);
2988 HeapFree(GetProcessHeap(), 0, lpwh);
2991 /***********************************************************************
2992 * FTP_ReceiveFileList (internal)
2994 * Read file list from server
2997 * Handle to file list on success
3001 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3002 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
3005 LPFILEPROPERTIESW lpafp = NULL;
3006 LPWININETFTPFINDNEXTW lpwfn = NULL;
3007 HINTERNET handle = 0;
3009 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3011 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3014 FTP_ConvertFileProp(lpafp, lpFindFileData);
3016 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3019 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3020 lpwfn->hdr.dwContext = dwContext;
3021 lpwfn->hdr.dwRefCount = 1;
3022 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3023 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3024 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3025 lpwfn->size = dwSize;
3026 lpwfn->lpafp = lpafp;
3028 WININET_AddRef( &lpwfs->hdr );
3029 lpwfn->lpFtpSession = lpwfs;
3031 handle = WININET_AllocHandle( &lpwfn->hdr );
3036 WININET_Release( &lpwfn->hdr );
3038 TRACE("Matched %d files\n", dwSize);
3043 /***********************************************************************
3044 * FTP_ConvertFileProp (internal)
3046 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3053 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3055 BOOL bSuccess = FALSE;
3057 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3061 /* Convert 'Unix' time to Windows time */
3062 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3063 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3064 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3065 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3067 /* Not all fields are filled in */
3068 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3069 lpFindFileData->nFileSizeLow = lpafp->nSize;
3071 if (lpafp->bIsDirectory)
3072 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3074 if (lpafp->lpszName)
3075 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3083 /***********************************************************************
3084 * FTP_ParseNextFile (internal)
3086 * Parse the next line in file listing
3092 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3094 static const char szSpace[] = " \t";
3102 lpfp->lpszName = NULL;
3104 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3107 pszToken = strtok(pszLine, szSpace);
3109 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3112 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3114 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3115 if(!FTP_ParsePermission(pszToken, lpfp))
3116 lpfp->bIsDirectory = FALSE;
3117 for(i=0; i<=3; i++) {
3118 if(!(pszToken = strtok(NULL, szSpace)))
3121 if(!pszToken) continue;
3122 if(lpfp->bIsDirectory) {
3123 TRACE("Is directory\n");
3127 TRACE("Size: %s\n", pszToken);
3128 lpfp->nSize = atol(pszToken);
3131 lpfp->tmLastModified.tm_sec = 0;
3132 lpfp->tmLastModified.tm_min = 0;
3133 lpfp->tmLastModified.tm_hour = 0;
3134 lpfp->tmLastModified.tm_mday = 0;
3135 lpfp->tmLastModified.tm_mon = 0;
3136 lpfp->tmLastModified.tm_year = 0;
3138 /* Determine month */
3139 pszToken = strtok(NULL, szSpace);
3140 if(!pszToken) continue;
3141 if(strlen(pszToken) >= 3) {
3143 if((pszTmp = StrStrIA(szMonths, pszToken)))
3144 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3147 pszToken = strtok(NULL, szSpace);
3148 if(!pszToken) continue;
3149 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3150 /* Determine time or year */
3151 pszToken = strtok(NULL, szSpace);
3152 if(!pszToken) continue;
3153 if((pszTmp = strchr(pszToken, ':'))) {
3158 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3159 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3161 apTM = localtime(&aTime);
3162 lpfp->tmLastModified.tm_year = apTM->tm_year;
3165 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3166 lpfp->tmLastModified.tm_hour = 12;
3168 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3169 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3170 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3171 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3173 pszToken = strtok(NULL, szSpace);
3174 if(!pszToken) continue;
3175 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3176 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3178 /* NT way of parsing ... :
3180 07-13-03 08:55PM <DIR> sakpatch
3181 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3183 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3184 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3186 sscanf(pszToken, "%d-%d-%d",
3187 &lpfp->tmLastModified.tm_mon,
3188 &lpfp->tmLastModified.tm_mday,
3189 &lpfp->tmLastModified.tm_year);
3191 /* Hacky and bad Y2K protection :-) */
3192 if (lpfp->tmLastModified.tm_year < 70)
3193 lpfp->tmLastModified.tm_year += 100;
3195 pszToken = strtok(NULL, szSpace);
3196 if(!pszToken) continue;
3197 sscanf(pszToken, "%d:%d",
3198 &lpfp->tmLastModified.tm_hour,
3199 &lpfp->tmLastModified.tm_min);
3200 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3201 lpfp->tmLastModified.tm_hour += 12;
3203 lpfp->tmLastModified.tm_sec = 0;
3205 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3206 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3207 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3208 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3210 pszToken = strtok(NULL, szSpace);
3211 if(!pszToken) continue;
3212 if(!strcasecmp(pszToken, "<DIR>")) {
3213 lpfp->bIsDirectory = TRUE;
3215 TRACE("Is directory\n");
3218 lpfp->bIsDirectory = FALSE;
3219 lpfp->nSize = atol(pszToken);
3220 TRACE("Size: %d\n", lpfp->nSize);
3223 pszToken = strtok(NULL, szSpace);
3224 if(!pszToken) continue;
3225 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3226 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3228 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3229 else if(pszToken[0] == '+') {
3230 FIXME("EPLF Format not implemented\n");
3233 if(lpfp->lpszName) {
3234 if((lpszSearchFile == NULL) ||
3235 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3237 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3240 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3241 lpfp->lpszName = NULL;
3248 /***********************************************************************
3249 * FTP_ParseDirectory (internal)
3251 * Parse string of directory information
3257 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3258 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3260 BOOL bSuccess = TRUE;
3261 INT sizeFilePropArray = 500;/*20; */
3262 INT indexFilePropArray = -1;
3266 /* Allocate intial file properties array */
3267 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3272 if (indexFilePropArray+1 >= sizeFilePropArray)
3274 LPFILEPROPERTIESW tmpafp;
3276 sizeFilePropArray *= 2;
3277 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3278 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3287 indexFilePropArray++;
3288 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3290 if (bSuccess && indexFilePropArray)
3292 if (indexFilePropArray < sizeFilePropArray - 1)
3294 LPFILEPROPERTIESW tmpafp;
3296 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3297 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3301 *dwfp = indexFilePropArray;
3305 HeapFree(GetProcessHeap(), 0, *lpafp);
3306 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3314 /***********************************************************************
3315 * FTP_ParsePermission (internal)
3317 * Parse permission string of directory information
3324 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3326 BOOL bSuccess = TRUE;
3327 unsigned short nPermission = 0;
3332 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3338 lpfp->bIsDirectory = (*lpszPermission == 'd');
3344 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3347 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3350 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3353 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3356 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3359 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3362 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3365 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3368 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3372 }while (nPos <= nLast);
3374 lpfp->permissions = nPermission;
3379 /***********************************************************************
3380 * FTP_SetResponseError (internal)
3382 * Set the appropriate error code for a given response from the server
3387 static DWORD FTP_SetResponseError(DWORD dwResponse)
3393 case 421: /* Service not available - Server may be shutting down. */
3394 dwCode = ERROR_INTERNET_TIMEOUT;
3397 case 425: /* Cannot open data connection. */
3398 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3401 case 426: /* Connection closed, transer aborted. */
3402 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3405 case 500: /* Syntax error. Command unrecognized. */
3406 case 501: /* Syntax error. Error in parameters or arguments. */
3407 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3410 case 530: /* Not logged in. Login incorrect. */
3411 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3414 case 550: /* File action not taken. File not found or no access. */
3415 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3418 case 450: /* File action not taken. File may be busy. */
3419 case 451: /* Action aborted. Server error. */
3420 case 452: /* Action not taken. Insufficient storage space on server. */
3421 case 502: /* Command not implemented. */
3422 case 503: /* Bad sequence of commands. */
3423 case 504: /* Command not implemented for that parameter. */
3424 case 532: /* Need account for storing files */
3425 case 551: /* Requested action aborted. Page type unknown */
3426 case 552: /* Action aborted. Exceeded storage allocation */
3427 case 553: /* Action not taken. File name not allowed. */
3430 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3434 INTERNET_SetLastError(dwCode);