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 /* Clear any error information */
266 INTERNET_SetLastError(0);
267 hIC = lpwfs->lpAppInfo;
269 /* Open file to be uploaded */
270 if (INVALID_HANDLE_VALUE ==
271 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
273 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
277 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
279 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
283 /* Get data socket to server */
284 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
286 FTP_SendData(lpwfs, nDataSocket, hFile);
287 closesocket(nDataSocket);
288 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
294 FTP_SetResponseError(nResCode);
300 if (lpwfs->lstnSocket != -1)
301 closesocket(lpwfs->lstnSocket);
303 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
305 INTERNET_ASYNC_RESULT iar;
307 iar.dwResult = (DWORD)bSuccess;
308 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
309 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
310 &iar, sizeof(INTERNET_ASYNC_RESULT));
320 /***********************************************************************
321 * FtpSetCurrentDirectoryA (WININET.@)
323 * Change the working directory on the FTP server
330 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
332 LPWSTR lpwzDirectory;
335 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
336 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
337 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
342 /***********************************************************************
343 * FtpSetCurrentDirectoryW (WININET.@)
345 * Change the working directory on the FTP server
352 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
354 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
355 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
357 TRACE("%p\n", lpwfs);
359 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
360 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
363 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
365 LPWININETFTPSESSIONW lpwfs = NULL;
366 LPWININETAPPINFOW hIC = NULL;
371 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
375 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
376 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
378 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
382 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
384 hIC = lpwfs->lpAppInfo;
385 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
387 WORKREQUEST workRequest;
388 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
390 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
391 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
392 req = &workRequest.u.FtpSetCurrentDirectoryW;
393 req->lpszDirectory = WININET_strdupW(lpszDirectory);
395 r = INTERNET_AsyncCall(&workRequest);
399 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
404 WININET_Release( &lpwfs->hdr );
410 /***********************************************************************
411 * FTP_FtpSetCurrentDirectoryW (Internal)
413 * Change the working directory on the FTP server
420 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
423 LPWININETAPPINFOW hIC = NULL;
424 DWORD bSuccess = FALSE;
426 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
428 /* Clear any error information */
429 INTERNET_SetLastError(0);
431 hIC = lpwfs->lpAppInfo;
432 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
433 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
436 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
443 FTP_SetResponseError(nResCode);
447 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
449 INTERNET_ASYNC_RESULT iar;
451 iar.dwResult = (DWORD)bSuccess;
452 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
453 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
454 &iar, sizeof(INTERNET_ASYNC_RESULT));
460 /***********************************************************************
461 * FtpCreateDirectoryA (WININET.@)
463 * Create new directory on the FTP server
470 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
472 LPWSTR lpwzDirectory;
475 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
476 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
477 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
482 /***********************************************************************
483 * FtpCreateDirectoryW (WININET.@)
485 * Create new directory on the FTP server
492 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
494 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
495 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
497 TRACE(" %p\n", lpwfs);
499 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
500 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
503 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
505 LPWININETFTPSESSIONW lpwfs;
506 LPWININETAPPINFOW hIC = NULL;
509 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
512 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
516 if (WH_HFTPSESSION != lpwfs->hdr.htype)
518 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
524 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
528 hIC = lpwfs->lpAppInfo;
529 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
531 WORKREQUEST workRequest;
532 struct WORKREQ_FTPCREATEDIRECTORYW *req;
534 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
535 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
536 req = &workRequest.u.FtpCreateDirectoryW;
537 req->lpszDirectory = WININET_strdupW(lpszDirectory);
539 r = INTERNET_AsyncCall(&workRequest);
543 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
546 WININET_Release( &lpwfs->hdr );
552 /***********************************************************************
553 * FTP_FtpCreateDirectoryW (Internal)
555 * Create new directory on the FTP server
562 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
565 BOOL bSuccess = FALSE;
566 LPWININETAPPINFOW hIC = NULL;
568 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
570 /* Clear any error information */
571 INTERNET_SetLastError(0);
573 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
576 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
582 FTP_SetResponseError(nResCode);
586 hIC = lpwfs->lpAppInfo;
587 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
589 INTERNET_ASYNC_RESULT iar;
591 iar.dwResult = (DWORD)bSuccess;
592 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
593 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
594 &iar, sizeof(INTERNET_ASYNC_RESULT));
600 /***********************************************************************
601 * FtpFindFirstFileA (WININET.@)
603 * Search the specified directory
606 * HINTERNET on success
610 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
611 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
613 LPWSTR lpwzSearchFile;
614 WIN32_FIND_DATAW wfd;
615 LPWIN32_FIND_DATAW lpFindFileDataW;
618 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
619 lpFindFileDataW = lpFindFileData?&wfd:NULL;
620 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
621 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
624 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
630 /***********************************************************************
631 * FtpFindFirstFileW (WININET.@)
633 * Search the specified directory
636 * HINTERNET on success
640 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
642 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
643 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
645 TRACE("%p\n", lpwfs);
647 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
648 req->lpFindFileData, req->dwFlags, req->dwContext);
649 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
652 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
653 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
655 LPWININETFTPSESSIONW lpwfs;
656 LPWININETAPPINFOW hIC = NULL;
659 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
660 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
662 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
666 hIC = lpwfs->lpAppInfo;
667 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
669 WORKREQUEST workRequest;
670 struct WORKREQ_FTPFINDFIRSTFILEW *req;
672 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
673 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
674 req = &workRequest.u.FtpFindFirstFileW;
675 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
676 req->lpFindFileData = lpFindFileData;
677 req->dwFlags = dwFlags;
678 req->dwContext= dwContext;
680 INTERNET_AsyncCall(&workRequest);
685 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
690 WININET_Release( &lpwfs->hdr );
696 /***********************************************************************
697 * FTP_FtpFindFirstFileW (Internal)
699 * Search the specified directory
702 * HINTERNET on success
706 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
707 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
710 LPWININETAPPINFOW hIC = NULL;
711 HINTERNET hFindNext = NULL;
715 /* Clear any error information */
716 INTERNET_SetLastError(0);
718 if (!FTP_InitListenSocket(lpwfs))
721 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
724 if (!FTP_SendPortOrPasv(lpwfs))
727 hIC = lpwfs->lpAppInfo;
728 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
729 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
732 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
735 if (nResCode == 125 || nResCode == 150)
739 /* Get data socket to server */
740 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
742 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
743 closesocket(nDataSocket);
744 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
745 if (nResCode != 226 && nResCode != 250)
746 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
750 FTP_SetResponseError(nResCode);
754 if (lpwfs->lstnSocket != -1)
755 closesocket(lpwfs->lstnSocket);
757 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
759 INTERNET_ASYNC_RESULT iar;
763 iar.dwResult = (DWORD)hFindNext;
764 iar.dwError = ERROR_SUCCESS;
765 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
766 &iar, sizeof(INTERNET_ASYNC_RESULT));
769 iar.dwResult = (DWORD)hFindNext;
770 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
771 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
772 &iar, sizeof(INTERNET_ASYNC_RESULT));
779 /***********************************************************************
780 * FtpGetCurrentDirectoryA (WININET.@)
782 * Retrieves the current directory
789 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
790 LPDWORD lpdwCurrentDirectory)
796 if(lpdwCurrentDirectory) {
797 len = *lpdwCurrentDirectory;
798 if(lpszCurrentDirectory)
800 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
803 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
808 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
809 if(lpdwCurrentDirectory) {
810 *lpdwCurrentDirectory = len;
811 if(lpszCurrentDirectory) {
812 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
813 HeapFree(GetProcessHeap(), 0, dir);
820 /***********************************************************************
821 * FtpGetCurrentDirectoryW (WININET.@)
823 * Retrieves the current directory
830 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
832 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
833 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
835 TRACE("%p\n", lpwfs);
837 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
840 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
841 LPDWORD lpdwCurrentDirectory)
843 LPWININETFTPSESSIONW lpwfs;
844 LPWININETAPPINFOW hIC = NULL;
847 TRACE("len(%d)\n", *lpdwCurrentDirectory);
849 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
850 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
852 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
856 hIC = lpwfs->lpAppInfo;
857 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
859 WORKREQUEST workRequest;
860 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
862 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
863 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
864 req = &workRequest.u.FtpGetCurrentDirectoryW;
865 req->lpszDirectory = lpszCurrentDirectory;
866 req->lpdwDirectory = lpdwCurrentDirectory;
868 r = INTERNET_AsyncCall(&workRequest);
872 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
873 lpdwCurrentDirectory);
878 WININET_Release( &lpwfs->hdr );
884 /***********************************************************************
885 * FTP_FtpGetCurrentDirectoryW (Internal)
887 * Retrieves the current directory
894 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
895 LPDWORD lpdwCurrentDirectory)
898 LPWININETAPPINFOW hIC = NULL;
899 DWORD bSuccess = FALSE;
901 TRACE("len(%d)\n", *lpdwCurrentDirectory);
903 /* Clear any error information */
904 INTERNET_SetLastError(0);
906 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
908 hIC = lpwfs->lpAppInfo;
909 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
910 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
913 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
916 if (nResCode == 257) /* Extract directory name */
918 DWORD firstpos, lastpos, len;
919 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
921 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
923 if ('"' == lpszResponseBuffer[lastpos])
932 len = lastpos - firstpos - 1;
933 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
934 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
935 *lpdwCurrentDirectory = len;
939 FTP_SetResponseError(nResCode);
943 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
945 INTERNET_ASYNC_RESULT iar;
947 iar.dwResult = (DWORD)bSuccess;
948 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
949 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
950 &iar, sizeof(INTERNET_ASYNC_RESULT));
953 return (DWORD) bSuccess;
956 /***********************************************************************
957 * FtpOpenFileA (WININET.@)
959 * Open a remote file for writing or reading
962 * HINTERNET handle on success
966 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
967 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
973 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
974 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
975 HeapFree(GetProcessHeap(), 0, lpwzFileName);
980 /***********************************************************************
981 * FtpOpenFileW (WININET.@)
983 * Open a remote file for writing or reading
986 * HINTERNET handle on success
990 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
992 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
993 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
995 TRACE("%p\n", lpwfs);
997 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
998 req->dwAccess, req->dwFlags, req->dwContext);
999 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1002 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1003 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1006 LPWININETFTPSESSIONW lpwfs;
1007 LPWININETAPPINFOW hIC = NULL;
1010 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession,
1011 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1013 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1014 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1016 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1020 if (lpwfs->download_in_progress != NULL) {
1021 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1024 hIC = lpwfs->lpAppInfo;
1025 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1027 WORKREQUEST workRequest;
1028 struct WORKREQ_FTPOPENFILEW *req;
1030 workRequest.asyncproc = AsyncFtpOpenFileProc;
1031 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1032 req = &workRequest.u.FtpOpenFileW;
1033 req->lpszFilename = WININET_strdupW(lpszFileName);
1034 req->dwAccess = fdwAccess;
1035 req->dwFlags = dwFlags;
1036 req->dwContext = dwContext;
1038 INTERNET_AsyncCall(&workRequest);
1043 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1048 WININET_Release( &lpwfs->hdr );
1054 /***********************************************************************
1055 * FTP_FtpOpenFileW (Internal)
1057 * Open a remote file for writing or reading
1060 * HINTERNET handle on success
1064 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1065 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1069 BOOL bSuccess = FALSE;
1070 LPWININETFTPFILE lpwh = NULL;
1071 LPWININETAPPINFOW hIC = NULL;
1072 HINTERNET handle = NULL;
1076 /* Clear any error information */
1077 INTERNET_SetLastError(0);
1079 if (GENERIC_READ == fdwAccess)
1081 /* Set up socket to retrieve data */
1082 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1084 else if (GENERIC_WRITE == fdwAccess)
1086 /* Set up socket to send data */
1087 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1090 /* Get data socket to server */
1091 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1093 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1094 lpwh->hdr.htype = WH_HFILE;
1095 lpwh->hdr.dwFlags = dwFlags;
1096 lpwh->hdr.dwContext = dwContext;
1097 lpwh->hdr.dwRefCount = 1;
1098 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1099 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1100 lpwh->nDataSocket = nDataSocket;
1101 lpwh->session_deleted = FALSE;
1103 WININET_AddRef( &lpwfs->hdr );
1104 lpwh->lpFtpSession = lpwfs;
1106 handle = WININET_AllocHandle( &lpwh->hdr );
1110 /* Indicate that a download is currently in progress */
1111 lpwfs->download_in_progress = lpwh;
1114 if (lpwfs->lstnSocket != -1)
1115 closesocket(lpwfs->lstnSocket);
1117 hIC = lpwfs->lpAppInfo;
1118 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1120 INTERNET_ASYNC_RESULT iar;
1124 iar.dwResult = (DWORD)handle;
1125 iar.dwError = ERROR_SUCCESS;
1126 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1127 &iar, sizeof(INTERNET_ASYNC_RESULT));
1130 iar.dwResult = (DWORD)bSuccess;
1131 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1132 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1133 &iar, sizeof(INTERNET_ASYNC_RESULT));
1138 WININET_Release( &lpwh->hdr );
1144 /***********************************************************************
1145 * FtpGetFileA (WININET.@)
1147 * Retrieve file from the FTP server
1154 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1155 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1158 LPWSTR lpwzRemoteFile;
1162 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1163 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1164 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1165 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1166 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1167 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1172 /***********************************************************************
1173 * FtpGetFileW (WININET.@)
1175 * Retrieve file from the FTP server
1182 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1184 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1185 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1187 TRACE("%p\n", lpwfs);
1189 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1190 req->lpszNewFile, req->fFailIfExists,
1191 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1192 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1193 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1196 #define FTP_CONDITION_MASK 0x0007
1198 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1199 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1202 LPWININETFTPSESSIONW lpwfs;
1203 LPWININETAPPINFOW hIC = NULL;
1206 if (!lpszRemoteFile || !lpszNewFile)
1208 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1212 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1215 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1219 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1221 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1225 /* Testing shows that Windows only accepts dwInternetFlags where the last
1226 * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY.
1229 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1231 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1235 if (lpwfs->download_in_progress != NULL) {
1236 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1240 hIC = lpwfs->lpAppInfo;
1241 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1243 WORKREQUEST workRequest;
1244 struct WORKREQ_FTPGETFILEW *req;
1246 workRequest.asyncproc = AsyncFtpGetFileProc;
1247 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1248 req = &workRequest.u.FtpGetFileW;
1249 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1250 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1251 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1252 req->fFailIfExists = fFailIfExists;
1253 req->dwFlags = dwInternetFlags;
1254 req->dwContext = dwContext;
1256 r = INTERNET_AsyncCall(&workRequest);
1260 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1261 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1265 WININET_Release( &lpwfs->hdr );
1271 /***********************************************************************
1272 * FTP_FtpGetFileW (Internal)
1274 * Retrieve file from the FTP server
1281 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1282 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1286 BOOL bSuccess = FALSE;
1288 LPWININETAPPINFOW hIC = NULL;
1290 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1292 /* Clear any error information */
1293 INTERNET_SetLastError(0);
1295 /* Ensure we can write to lpszNewfile by opening it */
1296 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1297 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1298 if (INVALID_HANDLE_VALUE == hFile)
1301 /* Set up socket to retrieve data */
1302 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1308 /* Get data socket to server */
1309 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1314 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1315 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1318 if (nResCode == 226)
1321 FTP_SetResponseError(nResCode);
1323 closesocket(nDataSocket);
1328 if (lpwfs->lstnSocket != -1)
1329 closesocket(lpwfs->lstnSocket);
1334 hIC = lpwfs->lpAppInfo;
1335 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1337 INTERNET_ASYNC_RESULT iar;
1339 iar.dwResult = (DWORD)bSuccess;
1340 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1341 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1342 &iar, sizeof(INTERNET_ASYNC_RESULT));
1348 /***********************************************************************
1349 * FtpGetFileSize (WININET.@)
1351 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1353 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1355 if (lpdwFileSizeHigh)
1356 *lpdwFileSizeHigh = 0;
1361 /***********************************************************************
1362 * FtpDeleteFileA (WININET.@)
1364 * Delete a file on the ftp server
1371 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1373 LPWSTR lpwzFileName;
1376 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1377 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1378 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1382 /***********************************************************************
1383 * FtpDeleteFileW (WININET.@)
1385 * Delete a file on the ftp server
1392 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1394 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1395 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1397 TRACE("%p\n", lpwfs);
1399 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1400 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1403 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1405 LPWININETFTPSESSIONW lpwfs;
1406 LPWININETAPPINFOW hIC = NULL;
1409 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1412 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1416 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1418 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1424 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1428 hIC = lpwfs->lpAppInfo;
1429 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1431 WORKREQUEST workRequest;
1432 struct WORKREQ_FTPDELETEFILEW *req;
1434 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1435 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1436 req = &workRequest.u.FtpDeleteFileW;
1437 req->lpszFilename = WININET_strdupW(lpszFileName);
1439 r = INTERNET_AsyncCall(&workRequest);
1443 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1447 WININET_Release( &lpwfs->hdr );
1452 /***********************************************************************
1453 * FTP_FtpDeleteFileW (Internal)
1455 * Delete a file on the ftp server
1462 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1465 BOOL bSuccess = FALSE;
1466 LPWININETAPPINFOW hIC = NULL;
1468 TRACE("%p\n", lpwfs);
1470 /* Clear any error information */
1471 INTERNET_SetLastError(0);
1473 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1476 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1479 if (nResCode == 250)
1482 FTP_SetResponseError(nResCode);
1485 hIC = lpwfs->lpAppInfo;
1486 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1488 INTERNET_ASYNC_RESULT iar;
1490 iar.dwResult = (DWORD)bSuccess;
1491 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1492 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1493 &iar, sizeof(INTERNET_ASYNC_RESULT));
1500 /***********************************************************************
1501 * FtpRemoveDirectoryA (WININET.@)
1503 * Remove a directory on the ftp server
1510 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1512 LPWSTR lpwzDirectory;
1515 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1516 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1517 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1521 /***********************************************************************
1522 * FtpRemoveDirectoryW (WININET.@)
1524 * Remove a directory on the ftp server
1531 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1533 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1534 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1536 TRACE("%p\n", lpwfs);
1538 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1539 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1542 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1544 LPWININETFTPSESSIONW lpwfs;
1545 LPWININETAPPINFOW hIC = NULL;
1548 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1551 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1555 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1557 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1563 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1567 hIC = lpwfs->lpAppInfo;
1568 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1570 WORKREQUEST workRequest;
1571 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1573 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1574 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1575 req = &workRequest.u.FtpRemoveDirectoryW;
1576 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1578 r = INTERNET_AsyncCall(&workRequest);
1582 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1586 WININET_Release( &lpwfs->hdr );
1591 /***********************************************************************
1592 * FTP_FtpRemoveDirectoryW (Internal)
1594 * Remove a directory on the ftp server
1601 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1604 BOOL bSuccess = FALSE;
1605 LPWININETAPPINFOW hIC = NULL;
1609 /* Clear any error information */
1610 INTERNET_SetLastError(0);
1612 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1615 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1618 if (nResCode == 250)
1621 FTP_SetResponseError(nResCode);
1625 hIC = lpwfs->lpAppInfo;
1626 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1628 INTERNET_ASYNC_RESULT iar;
1630 iar.dwResult = (DWORD)bSuccess;
1631 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1632 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1633 &iar, sizeof(INTERNET_ASYNC_RESULT));
1640 /***********************************************************************
1641 * FtpRenameFileA (WININET.@)
1643 * Rename a file on the ftp server
1650 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1656 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1657 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1658 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1659 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1660 HeapFree(GetProcessHeap(), 0, lpwzDest);
1664 /***********************************************************************
1665 * FtpRenameFileW (WININET.@)
1667 * Rename a file on the ftp server
1674 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1676 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1677 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1679 TRACE("%p\n", lpwfs);
1681 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1682 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1683 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1686 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1688 LPWININETFTPSESSIONW lpwfs;
1689 LPWININETAPPINFOW hIC = NULL;
1692 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1695 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1699 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1701 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1705 if (!lpszSrc || !lpszDest)
1707 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1711 hIC = lpwfs->lpAppInfo;
1712 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1714 WORKREQUEST workRequest;
1715 struct WORKREQ_FTPRENAMEFILEW *req;
1717 workRequest.asyncproc = AsyncFtpRenameFileProc;
1718 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1719 req = &workRequest.u.FtpRenameFileW;
1720 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1721 req->lpszDestFile = WININET_strdupW(lpszDest);
1723 r = INTERNET_AsyncCall(&workRequest);
1727 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1731 WININET_Release( &lpwfs->hdr );
1736 /***********************************************************************
1737 * FTP_FtpRenameFileW (Internal)
1739 * Rename a file on the ftp server
1746 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1747 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1750 BOOL bSuccess = FALSE;
1751 LPWININETAPPINFOW hIC = NULL;
1755 /* Clear any error information */
1756 INTERNET_SetLastError(0);
1758 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1761 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1762 if (nResCode == 350)
1764 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1767 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1770 if (nResCode == 250)
1773 FTP_SetResponseError(nResCode);
1776 hIC = lpwfs->lpAppInfo;
1777 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1779 INTERNET_ASYNC_RESULT iar;
1781 iar.dwResult = (DWORD)bSuccess;
1782 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1783 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1784 &iar, sizeof(INTERNET_ASYNC_RESULT));
1790 /***********************************************************************
1791 * FtpCommandA (WININET.@)
1793 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1794 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1796 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1797 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1802 /***********************************************************************
1803 * FtpCommandW (WININET.@)
1805 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1806 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1808 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1809 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1814 /***********************************************************************
1815 * FTP_Connect (internal)
1817 * Connect to a ftp server
1820 * HINTERNET a session handle on success
1825 * Windows uses 'anonymous' as the username, when given a NULL username
1826 * and a NULL password. The password is first looked up in:
1828 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1830 * If this entry is not present it uses the current username as the password.
1834 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1835 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1836 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1837 DWORD dwInternalFlags)
1839 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1840 'M','i','c','r','o','s','o','f','t','\\',
1841 'W','i','n','d','o','w','s','\\',
1842 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1843 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1844 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1845 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1846 static const WCHAR szEmpty[] = {'\0'};
1847 struct sockaddr_in socketAddr;
1850 BOOL bSuccess = FALSE;
1851 LPWININETFTPSESSIONW lpwfs = NULL;
1852 HINTERNET handle = NULL;
1854 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1855 hIC, debugstr_w(lpszServerName),
1856 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1858 assert( hIC->hdr.htype == WH_HINIT );
1860 if (NULL == lpszUserName && NULL != lpszPassword)
1862 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1866 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1869 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1873 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1874 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1876 lpwfs->hdr.htype = WH_HFTPSESSION;
1877 lpwfs->hdr.dwFlags = dwFlags;
1878 lpwfs->hdr.dwContext = dwContext;
1879 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1880 lpwfs->hdr.dwRefCount = 1;
1881 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1882 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1883 lpwfs->download_in_progress = NULL;
1885 WININET_AddRef( &hIC->hdr );
1886 lpwfs->lpAppInfo = hIC;
1888 handle = WININET_AllocHandle( &lpwfs->hdr );
1891 ERR("Failed to alloc handle\n");
1892 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1896 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1897 if(strchrW(hIC->lpszProxy, ' '))
1898 FIXME("Several proxies not implemented.\n");
1899 if(hIC->lpszProxyBypass)
1900 FIXME("Proxy bypass is ignored.\n");
1902 if ( !lpszUserName) {
1904 WCHAR szPassword[MAX_PATH];
1905 DWORD len = sizeof(szPassword);
1907 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1909 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1910 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1911 /* Nothing in the registry, get the username and use that as the password */
1912 if (!GetUserNameW(szPassword, &len)) {
1913 /* Should never get here, but use an empty password as failsafe */
1914 strcpyW(szPassword, szEmpty);
1919 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1920 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1923 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1926 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1928 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1931 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1932 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1934 INTERNET_ASYNC_RESULT iar;
1936 iar.dwResult = (DWORD)handle;
1937 iar.dwError = ERROR_SUCCESS;
1939 SendAsyncCallback(&hIC->hdr, dwContext,
1940 INTERNET_STATUS_HANDLE_CREATED, &iar,
1941 sizeof(INTERNET_ASYNC_RESULT));
1944 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1945 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1947 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1949 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1953 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1954 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1956 nsocket = socket(AF_INET,SOCK_STREAM,0);
1959 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1963 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1964 &socketAddr, sizeof(struct sockaddr_in));
1966 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1968 ERR("Unable to connect (%s)\n", strerror(errno));
1969 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1973 TRACE("Connected to server\n");
1974 lpwfs->sndSocket = nsocket;
1975 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1976 &socketAddr, sizeof(struct sockaddr_in));
1978 sock_namelen = sizeof(lpwfs->socketAddress);
1979 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1981 if (FTP_ConnectToHost(lpwfs))
1983 TRACE("Successfully logged into server\n");
1989 if (!bSuccess && nsocket == -1)
1990 closesocket(nsocket);
1992 if (!bSuccess && lpwfs)
1994 HeapFree(GetProcessHeap(), 0, lpwfs);
1995 WININET_FreeHandle( handle );
2000 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2002 INTERNET_ASYNC_RESULT iar;
2004 iar.dwResult = (DWORD)lpwfs;
2005 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2006 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2007 &iar, sizeof(INTERNET_ASYNC_RESULT));
2014 /***********************************************************************
2015 * FTP_ConnectToHost (internal)
2017 * Connect to a ftp server
2024 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2027 BOOL bSuccess = FALSE;
2030 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2032 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2035 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2038 /* Login successful... */
2039 if (nResCode == 230)
2041 /* User name okay, need password... */
2042 else if (nResCode == 331)
2043 bSuccess = FTP_SendPassword(lpwfs);
2044 /* Need account for login... */
2045 else if (nResCode == 332)
2046 bSuccess = FTP_SendAccount(lpwfs);
2048 FTP_SetResponseError(nResCode);
2051 TRACE("Returning %d\n", bSuccess);
2057 /***********************************************************************
2058 * FTP_SendCommandA (internal)
2060 * Send command to server
2067 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2068 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2072 DWORD nBytesSent = 0;
2076 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2080 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2083 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2084 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2085 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2087 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2090 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2091 dwParamLen ? lpszParam : "", szCRLF);
2093 TRACE("Sending (%s) len(%d)\n", buf, len);
2094 while((nBytesSent < len) && (nRC != -1))
2096 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2100 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2104 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2105 &nBytesSent, sizeof(DWORD));
2108 TRACE("Sent %d bytes\n", nBytesSent);
2112 /***********************************************************************
2113 * FTP_SendCommand (internal)
2115 * Send command to server
2122 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2123 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2126 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2127 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2128 HeapFree(GetProcessHeap(), 0, lpszParamA);
2132 /***********************************************************************
2133 * FTP_ReceiveResponse (internal)
2135 * Receive response from server
2138 * Reply code on success
2142 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2144 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2147 char firstprefix[5];
2148 BOOL multiline = FALSE;
2149 LPWININETAPPINFOW hIC = NULL;
2151 TRACE("socket(%d)\n", lpwfs->sndSocket);
2153 hIC = lpwfs->lpAppInfo;
2154 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2158 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2165 if(lpszResponse[3] != '-')
2168 { /* Start of multiline repsonse. Loop until we get "nnn " */
2170 memcpy(firstprefix, lpszResponse, 3);
2171 firstprefix[3] = ' ';
2172 firstprefix[4] = '\0';
2177 if(!memcmp(firstprefix, lpszResponse, 4))
2185 rc = atoi(lpszResponse);
2187 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2188 &nRecv, sizeof(DWORD));
2192 TRACE("return %d\n", rc);
2197 /***********************************************************************
2198 * FTP_SendPassword (internal)
2200 * Send password to ftp server
2207 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2210 BOOL bSuccess = FALSE;
2213 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2216 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2219 TRACE("Received reply code %d\n", nResCode);
2220 /* Login successful... */
2221 if (nResCode == 230)
2223 /* Command not implemented, superfluous at the server site... */
2224 /* Need account for login... */
2225 else if (nResCode == 332)
2226 bSuccess = FTP_SendAccount(lpwfs);
2228 FTP_SetResponseError(nResCode);
2232 TRACE("Returning %d\n", bSuccess);
2237 /***********************************************************************
2238 * FTP_SendAccount (internal)
2247 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2250 BOOL bSuccess = FALSE;
2253 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2256 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2260 FTP_SetResponseError(nResCode);
2267 /***********************************************************************
2268 * FTP_SendStore (internal)
2270 * Send request to upload file to ftp server
2277 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2280 BOOL bSuccess = FALSE;
2283 if (!FTP_InitListenSocket(lpwfs))
2286 if (!FTP_SendType(lpwfs, dwType))
2289 if (!FTP_SendPortOrPasv(lpwfs))
2292 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2294 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2297 if (nResCode == 150 || nResCode == 125)
2300 FTP_SetResponseError(nResCode);
2304 if (!bSuccess && lpwfs->lstnSocket != -1)
2306 closesocket(lpwfs->lstnSocket);
2307 lpwfs->lstnSocket = -1;
2314 /***********************************************************************
2315 * FTP_InitListenSocket (internal)
2317 * Create a socket to listen for server response
2324 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2326 BOOL bSuccess = FALSE;
2327 socklen_t namelen = sizeof(struct sockaddr_in);
2331 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2332 if (lpwfs->lstnSocket == -1)
2334 TRACE("Unable to create listening socket\n");
2338 /* We obtain our ip addr from the name of the command channel socket */
2339 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2341 /* and get the system to assign us a port */
2342 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2344 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2346 TRACE("Unable to bind socket\n");
2350 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2352 TRACE("listen failed\n");
2356 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2360 if (!bSuccess && lpwfs->lstnSocket == -1)
2362 closesocket(lpwfs->lstnSocket);
2363 lpwfs->lstnSocket = -1;
2370 /***********************************************************************
2371 * FTP_SendType (internal)
2373 * Tell server type of data being transferred
2379 * W98SE doesn't cache the type that's currently set
2380 * (i.e. it sends it always),
2381 * so we probably don't want to do that either.
2383 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2386 WCHAR type[] = { 'I','\0' };
2387 BOOL bSuccess = FALSE;
2390 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2393 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2396 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2402 FTP_SetResponseError(nResCode);
2409 /***********************************************************************
2410 * FTP_GetFileSize (internal)
2412 * Retrieves from the server the size of the given file
2419 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2422 BOOL bSuccess = FALSE;
2426 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2429 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2432 if (nResCode == 213) {
2433 /* Now parses the output to get the actual file size */
2435 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2437 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2438 if (lpszResponseBuffer[i] == '\0') return FALSE;
2439 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2443 FTP_SetResponseError(nResCode);
2452 /***********************************************************************
2453 * FTP_SendPort (internal)
2455 * Tell server which port to use
2462 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2464 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2466 WCHAR szIPAddress[64];
2467 BOOL bSuccess = FALSE;
2470 sprintfW(szIPAddress, szIPFormat,
2471 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2472 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2473 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2474 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2475 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2476 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2478 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2481 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2484 if (nResCode == 200)
2487 FTP_SetResponseError(nResCode);
2495 /***********************************************************************
2496 * FTP_DoPassive (internal)
2498 * Tell server that we want to do passive transfers
2499 * and connect data socket
2506 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2509 BOOL bSuccess = FALSE;
2512 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2515 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2518 if (nResCode == 227)
2520 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2524 char *pAddr, *pPort;
2526 struct sockaddr_in dataSocketAddress;
2528 p = lpszResponseBuffer+4; /* skip status code */
2530 /* do a very strict check; we can improve that later. */
2532 if (strncmp(p, "Entering Passive Mode", 21))
2534 ERR("unknown response '%.*s', aborting\n", 21, p);
2537 p += 21; /* skip string */
2538 if ((*p++ != ' ') || (*p++ != '('))
2540 ERR("unknown response format, aborting\n");
2544 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2547 ERR("unknown response address format '%s', aborting\n", p);
2550 for (i=0; i < 6; i++)
2553 dataSocketAddress = lpwfs->socketAddress;
2554 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2555 pPort = (char *)&(dataSocketAddress.sin_port);
2563 nsocket = socket(AF_INET,SOCK_STREAM,0);
2567 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2569 ERR("can't connect passive FTP data port.\n");
2570 closesocket(nsocket);
2573 lpwfs->pasvSocket = nsocket;
2577 FTP_SetResponseError(nResCode);
2585 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2587 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2589 if (!FTP_DoPassive(lpwfs))
2594 if (!FTP_SendPort(lpwfs))
2601 /***********************************************************************
2602 * FTP_GetDataSocket (internal)
2604 * Either accepts an incoming data socket connection from the server
2605 * or just returns the already opened socket after a PASV command
2606 * in case of passive FTP.
2614 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2616 struct sockaddr_in saddr;
2617 socklen_t addrlen = sizeof(struct sockaddr);
2620 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2622 *nDataSocket = lpwfs->pasvSocket;
2626 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2627 closesocket(lpwfs->lstnSocket);
2628 lpwfs->lstnSocket = -1;
2630 return *nDataSocket != -1;
2634 /***********************************************************************
2635 * FTP_SendData (internal)
2637 * Send data to the server
2644 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2646 BY_HANDLE_FILE_INFORMATION fi;
2647 DWORD nBytesRead = 0;
2648 DWORD nBytesSent = 0;
2649 DWORD nTotalSent = 0;
2650 DWORD nBytesToSend, nLen;
2652 time_t s_long_time, e_long_time;
2657 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2658 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2660 /* Get the size of the file. */
2661 GetFileInformationByHandle(hFile, &fi);
2666 nBytesToSend = nBytesRead - nBytesSent;
2668 if (nBytesToSend <= 0)
2670 /* Read data from file. */
2672 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2673 ERR("Failed reading from file\n");
2676 nBytesToSend = nBytesRead;
2681 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2682 DATA_PACKET_SIZE : nBytesToSend;
2683 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2691 /* Do some computation to display the status. */
2693 nSeconds = e_long_time - s_long_time;
2694 if( nSeconds / 60 > 0 )
2696 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2697 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2698 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2702 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2703 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2704 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2706 } while (nRC != -1);
2708 TRACE("file transfer complete!\n");
2710 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2716 /***********************************************************************
2717 * FTP_SendRetrieve (internal)
2719 * Send request to retrieve a file
2722 * Number of bytes to be received on success
2726 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2732 if (!FTP_InitListenSocket(lpwfs))
2735 if (!FTP_SendType(lpwfs, dwType))
2738 if (!FTP_SendPortOrPasv(lpwfs))
2741 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2744 TRACE("Waiting to receive %d bytes\n", nResult);
2746 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2749 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2750 if ((nResCode != 125) && (nResCode != 150)) {
2751 /* That means that we got an error getting the file. */
2756 if (0 == nResult && lpwfs->lstnSocket != -1)
2758 closesocket(lpwfs->lstnSocket);
2759 lpwfs->lstnSocket = -1;
2766 /***********************************************************************
2767 * FTP_RetrieveData (internal)
2769 * Retrieve data from server
2776 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2778 DWORD nBytesWritten;
2779 DWORD nBytesReceived = 0;
2785 if (INVALID_HANDLE_VALUE == hFile)
2788 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2789 if (NULL == lpszBuffer)
2791 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2795 while (nBytesReceived < nBytes && nRC != -1)
2797 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2800 /* other side closed socket. */
2803 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2804 nBytesReceived += nRC;
2807 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2808 nBytesReceived * 100 / nBytes);
2811 TRACE("Data transfer complete\n");
2812 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2819 /***********************************************************************
2820 * FTP_CloseSessionHandle (internal)
2822 * Deallocate session handle
2829 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2831 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2835 WININET_Release(&lpwfs->lpAppInfo->hdr);
2837 if (lpwfs->download_in_progress != NULL)
2838 lpwfs->download_in_progress->session_deleted = TRUE;
2840 if (lpwfs->sndSocket != -1)
2841 closesocket(lpwfs->sndSocket);
2843 if (lpwfs->lstnSocket != -1)
2844 closesocket(lpwfs->lstnSocket);
2846 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2847 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2848 HeapFree(GetProcessHeap(), 0, lpwfs);
2852 /***********************************************************************
2853 * FTP_FindNextFileW (Internal)
2855 * Continues a file search from a previous call to FindFirstFile
2862 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2864 BOOL bSuccess = TRUE;
2865 LPWIN32_FIND_DATAW lpFindFileData;
2867 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2869 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2871 /* Clear any error information */
2872 INTERNET_SetLastError(0);
2874 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2875 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2877 if (lpwh->index >= lpwh->size)
2879 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2884 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2887 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2891 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2893 INTERNET_ASYNC_RESULT iar;
2895 iar.dwResult = (DWORD)bSuccess;
2896 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2897 INTERNET_GetLastError();
2899 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2900 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2901 sizeof(INTERNET_ASYNC_RESULT));
2908 /***********************************************************************
2909 * FTP_CloseFindNextHandle (internal)
2911 * Deallocate session handle
2918 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2920 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2925 WININET_Release(&lpwfn->lpFtpSession->hdr);
2927 for (i = 0; i < lpwfn->size; i++)
2929 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2932 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2933 HeapFree(GetProcessHeap(), 0, lpwfn);
2936 /***********************************************************************
2937 * FTP_CloseFileTransferHandle (internal)
2939 * Closes the file transfer handle. This also 'cleans' the data queue of
2940 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2943 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2945 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2946 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2951 WININET_Release(&lpwh->lpFtpSession->hdr);
2953 if (!lpwh->session_deleted)
2954 lpwfs->download_in_progress = NULL;
2956 /* This just serves to flush the control socket of any spurrious lines written
2957 to it (like '226 Transfer complete.').
2959 Wonder what to do if the server sends us an error code though...
2961 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2963 if (lpwh->nDataSocket != -1)
2964 closesocket(lpwh->nDataSocket);
2966 HeapFree(GetProcessHeap(), 0, lpwh);
2969 /***********************************************************************
2970 * FTP_ReceiveFileList (internal)
2972 * Read file list from server
2975 * Handle to file list on success
2979 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2980 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2983 LPFILEPROPERTIESW lpafp = NULL;
2984 LPWININETFTPFINDNEXTW lpwfn = NULL;
2985 HINTERNET handle = 0;
2987 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2989 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2992 FTP_ConvertFileProp(lpafp, lpFindFileData);
2994 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
2997 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
2998 lpwfn->hdr.dwContext = dwContext;
2999 lpwfn->hdr.dwRefCount = 1;
3000 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3001 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3002 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3003 lpwfn->size = dwSize;
3004 lpwfn->lpafp = lpafp;
3006 WININET_AddRef( &lpwfs->hdr );
3007 lpwfn->lpFtpSession = lpwfs;
3009 handle = WININET_AllocHandle( &lpwfn->hdr );
3014 WININET_Release( &lpwfn->hdr );
3016 TRACE("Matched %d files\n", dwSize);
3021 /***********************************************************************
3022 * FTP_ConvertFileProp (internal)
3024 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3031 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3033 BOOL bSuccess = FALSE;
3035 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3039 /* Convert 'Unix' time to Windows time */
3040 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3041 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3042 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3043 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3045 /* Not all fields are filled in */
3046 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3047 lpFindFileData->nFileSizeLow = lpafp->nSize;
3049 if (lpafp->bIsDirectory)
3050 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3052 if (lpafp->lpszName)
3053 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3061 /***********************************************************************
3062 * FTP_ParseNextFile (internal)
3064 * Parse the next line in file listing
3070 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3072 static const char szSpace[] = " \t";
3080 lpfp->lpszName = NULL;
3082 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3085 pszToken = strtok(pszLine, szSpace);
3087 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3090 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3092 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3093 if(!FTP_ParsePermission(pszToken, lpfp))
3094 lpfp->bIsDirectory = FALSE;
3095 for(i=0; i<=3; i++) {
3096 if(!(pszToken = strtok(NULL, szSpace)))
3099 if(!pszToken) continue;
3100 if(lpfp->bIsDirectory) {
3101 TRACE("Is directory\n");
3105 TRACE("Size: %s\n", pszToken);
3106 lpfp->nSize = atol(pszToken);
3109 lpfp->tmLastModified.tm_sec = 0;
3110 lpfp->tmLastModified.tm_min = 0;
3111 lpfp->tmLastModified.tm_hour = 0;
3112 lpfp->tmLastModified.tm_mday = 0;
3113 lpfp->tmLastModified.tm_mon = 0;
3114 lpfp->tmLastModified.tm_year = 0;
3116 /* Determine month */
3117 pszToken = strtok(NULL, szSpace);
3118 if(!pszToken) continue;
3119 if(strlen(pszToken) >= 3) {
3121 if((pszTmp = StrStrIA(szMonths, pszToken)))
3122 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3125 pszToken = strtok(NULL, szSpace);
3126 if(!pszToken) continue;
3127 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3128 /* Determine time or year */
3129 pszToken = strtok(NULL, szSpace);
3130 if(!pszToken) continue;
3131 if((pszTmp = strchr(pszToken, ':'))) {
3136 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3137 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3139 apTM = localtime(&aTime);
3140 lpfp->tmLastModified.tm_year = apTM->tm_year;
3143 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3144 lpfp->tmLastModified.tm_hour = 12;
3146 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3147 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3148 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3149 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3151 pszToken = strtok(NULL, szSpace);
3152 if(!pszToken) continue;
3153 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3154 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3156 /* NT way of parsing ... :
3158 07-13-03 08:55PM <DIR> sakpatch
3159 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3161 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3162 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3164 sscanf(pszToken, "%d-%d-%d",
3165 &lpfp->tmLastModified.tm_mon,
3166 &lpfp->tmLastModified.tm_mday,
3167 &lpfp->tmLastModified.tm_year);
3169 /* Hacky and bad Y2K protection :-) */
3170 if (lpfp->tmLastModified.tm_year < 70)
3171 lpfp->tmLastModified.tm_year += 100;
3173 pszToken = strtok(NULL, szSpace);
3174 if(!pszToken) continue;
3175 sscanf(pszToken, "%d:%d",
3176 &lpfp->tmLastModified.tm_hour,
3177 &lpfp->tmLastModified.tm_min);
3178 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3179 lpfp->tmLastModified.tm_hour += 12;
3181 lpfp->tmLastModified.tm_sec = 0;
3183 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3184 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3185 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3186 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3188 pszToken = strtok(NULL, szSpace);
3189 if(!pszToken) continue;
3190 if(!strcasecmp(pszToken, "<DIR>")) {
3191 lpfp->bIsDirectory = TRUE;
3193 TRACE("Is directory\n");
3196 lpfp->bIsDirectory = FALSE;
3197 lpfp->nSize = atol(pszToken);
3198 TRACE("Size: %d\n", lpfp->nSize);
3201 pszToken = strtok(NULL, szSpace);
3202 if(!pszToken) continue;
3203 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3204 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3206 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3207 else if(pszToken[0] == '+') {
3208 FIXME("EPLF Format not implemented\n");
3211 if(lpfp->lpszName) {
3212 if((lpszSearchFile == NULL) ||
3213 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3215 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3218 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3219 lpfp->lpszName = NULL;
3226 /***********************************************************************
3227 * FTP_ParseDirectory (internal)
3229 * Parse string of directory information
3235 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3236 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3238 BOOL bSuccess = TRUE;
3239 INT sizeFilePropArray = 500;/*20; */
3240 INT indexFilePropArray = -1;
3244 /* Allocate intial file properties array */
3245 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3250 if (indexFilePropArray+1 >= sizeFilePropArray)
3252 LPFILEPROPERTIESW tmpafp;
3254 sizeFilePropArray *= 2;
3255 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3256 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3265 indexFilePropArray++;
3266 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3268 if (bSuccess && indexFilePropArray)
3270 if (indexFilePropArray < sizeFilePropArray - 1)
3272 LPFILEPROPERTIESW tmpafp;
3274 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3275 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3279 *dwfp = indexFilePropArray;
3283 HeapFree(GetProcessHeap(), 0, *lpafp);
3284 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3292 /***********************************************************************
3293 * FTP_ParsePermission (internal)
3295 * Parse permission string of directory information
3302 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3304 BOOL bSuccess = TRUE;
3305 unsigned short nPermission = 0;
3310 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3316 lpfp->bIsDirectory = (*lpszPermission == 'd');
3322 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3325 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3328 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3331 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3334 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3337 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3340 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3343 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3346 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3350 }while (nPos <= nLast);
3352 lpfp->permissions = nPermission;
3357 /***********************************************************************
3358 * FTP_SetResponseError (internal)
3360 * Set the appropriate error code for a given response from the server
3365 static DWORD FTP_SetResponseError(DWORD dwResponse)
3371 case 421: /* Service not available - Server may be shutting down. */
3372 dwCode = ERROR_INTERNET_TIMEOUT;
3375 case 425: /* Cannot open data connection. */
3376 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3379 case 426: /* Connection closed, transer aborted. */
3380 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3383 case 500: /* Syntax error. Command unrecognized. */
3384 case 501: /* Syntax error. Error in parameters or arguments. */
3385 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3388 case 530: /* Not logged in. Login incorrect. */
3389 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3392 case 550: /* File action not taken. File not found or no access. */
3393 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3396 case 450: /* File action not taken. File may be busy. */
3397 case 451: /* Action aborted. Server error. */
3398 case 452: /* Action not taken. Insufficient storage space on server. */
3399 case 502: /* Command not implemented. */
3400 case 503: /* Bad sequence of command. */
3401 case 504: /* Command not implemented for that parameter. */
3402 case 532: /* Need account for storing files */
3403 case 551: /* Requested action aborted. Page type unknown */
3404 case 552: /* Action aborted. Exceeded storage allocation */
3405 case 553: /* Action not taken. File name not allowed. */
3408 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3412 INTERNET_SetLastError(dwCode);