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));
333 /***********************************************************************
334 * FtpSetCurrentDirectoryA (WININET.@)
336 * Change the working directory on the FTP server
343 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
345 LPWSTR lpwzDirectory;
348 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
349 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
350 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
355 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
357 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
358 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
360 TRACE("%p\n", lpwfs);
362 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
363 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
366 /***********************************************************************
367 * FtpSetCurrentDirectoryW (WININET.@)
369 * Change the working directory on the FTP server
376 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
378 LPWININETFTPSESSIONW lpwfs = NULL;
379 LPWININETAPPINFOW hIC = NULL;
384 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
388 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
389 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
391 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
395 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
397 hIC = lpwfs->lpAppInfo;
398 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
400 WORKREQUEST workRequest;
401 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
403 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
404 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
405 req = &workRequest.u.FtpSetCurrentDirectoryW;
406 req->lpszDirectory = WININET_strdupW(lpszDirectory);
408 r = INTERNET_AsyncCall(&workRequest);
412 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
417 WININET_Release( &lpwfs->hdr );
423 /***********************************************************************
424 * FTP_FtpSetCurrentDirectoryW (Internal)
426 * Change the working directory on the FTP server
433 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
436 LPWININETAPPINFOW hIC = NULL;
437 DWORD bSuccess = FALSE;
439 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
441 /* Clear any error information */
442 INTERNET_SetLastError(0);
444 hIC = lpwfs->lpAppInfo;
445 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
446 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
449 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
456 FTP_SetResponseError(nResCode);
460 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
462 INTERNET_ASYNC_RESULT iar;
464 iar.dwResult = (DWORD)bSuccess;
465 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
466 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
467 &iar, sizeof(INTERNET_ASYNC_RESULT));
473 /***********************************************************************
474 * FtpCreateDirectoryA (WININET.@)
476 * Create new directory on the FTP server
483 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
485 LPWSTR lpwzDirectory;
488 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
489 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
490 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
495 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
497 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
498 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
500 TRACE(" %p\n", lpwfs);
502 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
503 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
506 /***********************************************************************
507 * FtpCreateDirectoryW (WININET.@)
509 * Create new directory on the FTP server
516 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
518 LPWININETFTPSESSIONW lpwfs;
519 LPWININETAPPINFOW hIC = NULL;
522 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
525 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
529 if (WH_HFTPSESSION != lpwfs->hdr.htype)
531 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
537 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
541 hIC = lpwfs->lpAppInfo;
542 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
544 WORKREQUEST workRequest;
545 struct WORKREQ_FTPCREATEDIRECTORYW *req;
547 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
548 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
549 req = &workRequest.u.FtpCreateDirectoryW;
550 req->lpszDirectory = WININET_strdupW(lpszDirectory);
552 r = INTERNET_AsyncCall(&workRequest);
556 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
559 WININET_Release( &lpwfs->hdr );
565 /***********************************************************************
566 * FTP_FtpCreateDirectoryW (Internal)
568 * Create new directory on the FTP server
575 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
578 BOOL bSuccess = FALSE;
579 LPWININETAPPINFOW hIC = NULL;
581 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
583 /* Clear any error information */
584 INTERNET_SetLastError(0);
586 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
589 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
595 FTP_SetResponseError(nResCode);
599 hIC = lpwfs->lpAppInfo;
600 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
602 INTERNET_ASYNC_RESULT iar;
604 iar.dwResult = (DWORD)bSuccess;
605 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
606 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
607 &iar, sizeof(INTERNET_ASYNC_RESULT));
613 /***********************************************************************
614 * FtpFindFirstFileA (WININET.@)
616 * Search the specified directory
619 * HINTERNET on success
623 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
624 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
626 LPWSTR lpwzSearchFile;
627 WIN32_FIND_DATAW wfd;
628 LPWIN32_FIND_DATAW lpFindFileDataW;
631 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
632 lpFindFileDataW = lpFindFileData?&wfd:NULL;
633 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
634 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
637 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
643 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
645 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
646 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
648 TRACE("%p\n", lpwfs);
650 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
651 req->lpFindFileData, req->dwFlags, req->dwContext);
652 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
655 /***********************************************************************
656 * FtpFindFirstFileW (WININET.@)
658 * Search the specified directory
661 * HINTERNET on success
665 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
666 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
668 LPWININETFTPSESSIONW lpwfs;
669 LPWININETAPPINFOW hIC = NULL;
672 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
673 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
675 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
679 hIC = lpwfs->lpAppInfo;
680 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
682 WORKREQUEST workRequest;
683 struct WORKREQ_FTPFINDFIRSTFILEW *req;
685 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
686 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
687 req = &workRequest.u.FtpFindFirstFileW;
688 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
689 req->lpFindFileData = lpFindFileData;
690 req->dwFlags = dwFlags;
691 req->dwContext= dwContext;
693 INTERNET_AsyncCall(&workRequest);
698 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
703 WININET_Release( &lpwfs->hdr );
709 /***********************************************************************
710 * FTP_FtpFindFirstFileW (Internal)
712 * Search the specified directory
715 * HINTERNET on success
719 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
720 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
723 LPWININETAPPINFOW hIC = NULL;
724 HINTERNET hFindNext = NULL;
728 /* Clear any error information */
729 INTERNET_SetLastError(0);
731 if (!FTP_InitListenSocket(lpwfs))
734 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
737 if (!FTP_SendPortOrPasv(lpwfs))
740 hIC = lpwfs->lpAppInfo;
741 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
742 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
745 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
748 if (nResCode == 125 || nResCode == 150)
752 /* Get data socket to server */
753 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
755 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
756 closesocket(nDataSocket);
757 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
758 if (nResCode != 226 && nResCode != 250)
759 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
763 FTP_SetResponseError(nResCode);
767 if (lpwfs->lstnSocket != -1)
768 closesocket(lpwfs->lstnSocket);
770 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
772 INTERNET_ASYNC_RESULT iar;
776 iar.dwResult = (DWORD)hFindNext;
777 iar.dwError = ERROR_SUCCESS;
778 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
779 &iar, sizeof(INTERNET_ASYNC_RESULT));
782 iar.dwResult = (DWORD)hFindNext;
783 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
784 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
785 &iar, sizeof(INTERNET_ASYNC_RESULT));
792 /***********************************************************************
793 * FtpGetCurrentDirectoryA (WININET.@)
795 * Retrieves the current directory
802 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
803 LPDWORD lpdwCurrentDirectory)
809 if(lpdwCurrentDirectory) {
810 len = *lpdwCurrentDirectory;
811 if(lpszCurrentDirectory)
813 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
816 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
821 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
822 if(lpdwCurrentDirectory) {
823 *lpdwCurrentDirectory = len;
824 if(lpszCurrentDirectory) {
825 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
826 HeapFree(GetProcessHeap(), 0, dir);
833 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
835 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
836 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
838 TRACE("%p\n", lpwfs);
840 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
843 /***********************************************************************
844 * FtpGetCurrentDirectoryW (WININET.@)
846 * Retrieves the current directory
853 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
854 LPDWORD lpdwCurrentDirectory)
856 LPWININETFTPSESSIONW lpwfs;
857 LPWININETAPPINFOW hIC = NULL;
860 TRACE("len(%d)\n", *lpdwCurrentDirectory);
862 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
863 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
865 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
869 hIC = lpwfs->lpAppInfo;
870 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
872 WORKREQUEST workRequest;
873 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
875 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
876 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
877 req = &workRequest.u.FtpGetCurrentDirectoryW;
878 req->lpszDirectory = lpszCurrentDirectory;
879 req->lpdwDirectory = lpdwCurrentDirectory;
881 r = INTERNET_AsyncCall(&workRequest);
885 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
886 lpdwCurrentDirectory);
891 WININET_Release( &lpwfs->hdr );
897 /***********************************************************************
898 * FTP_FtpGetCurrentDirectoryW (Internal)
900 * Retrieves the current directory
907 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
908 LPDWORD lpdwCurrentDirectory)
911 LPWININETAPPINFOW hIC = NULL;
912 DWORD bSuccess = FALSE;
914 TRACE("len(%d)\n", *lpdwCurrentDirectory);
916 /* Clear any error information */
917 INTERNET_SetLastError(0);
919 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
921 hIC = lpwfs->lpAppInfo;
922 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
923 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
926 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
929 if (nResCode == 257) /* Extract directory name */
931 DWORD firstpos, lastpos, len;
932 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
934 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
936 if ('"' == lpszResponseBuffer[lastpos])
945 len = lastpos - firstpos - 1;
946 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
947 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
948 *lpdwCurrentDirectory = len;
952 FTP_SetResponseError(nResCode);
956 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
958 INTERNET_ASYNC_RESULT iar;
960 iar.dwResult = (DWORD)bSuccess;
961 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
962 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
963 &iar, sizeof(INTERNET_ASYNC_RESULT));
966 return (DWORD) bSuccess;
969 /***********************************************************************
970 * FtpOpenFileA (WININET.@)
972 * Open a remote file for writing or reading
975 * HINTERNET handle on success
979 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
980 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
986 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
987 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
988 HeapFree(GetProcessHeap(), 0, lpwzFileName);
993 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
995 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
996 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
998 TRACE("%p\n", lpwfs);
1000 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
1001 req->dwAccess, req->dwFlags, req->dwContext);
1002 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1005 /***********************************************************************
1006 * FtpOpenFileW (WININET.@)
1008 * Open a remote file for writing or reading
1011 * HINTERNET handle on success
1015 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
1016 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1019 LPWININETFTPSESSIONW lpwfs;
1020 LPWININETAPPINFOW hIC = NULL;
1023 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession,
1024 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1026 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1029 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1033 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1035 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1039 if ((!lpszFileName) ||
1040 ((fdwAccess != GENERIC_READ) && (fdwAccess != GENERIC_WRITE)) ||
1041 ((dwFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY))
1043 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1047 if (lpwfs->download_in_progress != NULL) {
1048 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1051 hIC = lpwfs->lpAppInfo;
1052 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1054 WORKREQUEST workRequest;
1055 struct WORKREQ_FTPOPENFILEW *req;
1057 workRequest.asyncproc = AsyncFtpOpenFileProc;
1058 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1059 req = &workRequest.u.FtpOpenFileW;
1060 req->lpszFilename = WININET_strdupW(lpszFileName);
1061 req->dwAccess = fdwAccess;
1062 req->dwFlags = dwFlags;
1063 req->dwContext = dwContext;
1065 INTERNET_AsyncCall(&workRequest);
1070 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1074 WININET_Release( &lpwfs->hdr );
1080 /***********************************************************************
1081 * FTP_FtpOpenFileW (Internal)
1083 * Open a remote file for writing or reading
1086 * HINTERNET handle on success
1090 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1091 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1095 BOOL bSuccess = FALSE;
1096 LPWININETFTPFILE lpwh = NULL;
1097 LPWININETAPPINFOW hIC = NULL;
1098 HINTERNET handle = NULL;
1102 /* Clear any error information */
1103 INTERNET_SetLastError(0);
1105 if (GENERIC_READ == fdwAccess)
1107 /* Set up socket to retrieve data */
1108 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1110 else if (GENERIC_WRITE == fdwAccess)
1112 /* Set up socket to send data */
1113 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1116 /* Get data socket to server */
1117 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1119 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1120 lpwh->hdr.htype = WH_HFILE;
1121 lpwh->hdr.dwFlags = dwFlags;
1122 lpwh->hdr.dwContext = dwContext;
1123 lpwh->hdr.dwRefCount = 1;
1124 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1125 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1126 lpwh->nDataSocket = nDataSocket;
1127 lpwh->session_deleted = FALSE;
1129 WININET_AddRef( &lpwfs->hdr );
1130 lpwh->lpFtpSession = lpwfs;
1132 handle = WININET_AllocHandle( &lpwh->hdr );
1136 /* Indicate that a download is currently in progress */
1137 lpwfs->download_in_progress = lpwh;
1140 if (lpwfs->lstnSocket != -1)
1141 closesocket(lpwfs->lstnSocket);
1143 hIC = lpwfs->lpAppInfo;
1144 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1146 INTERNET_ASYNC_RESULT iar;
1150 iar.dwResult = (DWORD)handle;
1151 iar.dwError = ERROR_SUCCESS;
1152 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1153 &iar, sizeof(INTERNET_ASYNC_RESULT));
1156 iar.dwResult = (DWORD)bSuccess;
1157 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1158 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1159 &iar, sizeof(INTERNET_ASYNC_RESULT));
1164 WININET_Release( &lpwh->hdr );
1170 /***********************************************************************
1171 * FtpGetFileA (WININET.@)
1173 * Retrieve file from the FTP server
1180 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1181 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1184 LPWSTR lpwzRemoteFile;
1188 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1189 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1190 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1191 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1192 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1193 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1198 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1200 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1201 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1203 TRACE("%p\n", lpwfs);
1205 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1206 req->lpszNewFile, req->fFailIfExists,
1207 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1208 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1209 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1213 /***********************************************************************
1214 * FtpGetFileW (WININET.@)
1216 * Retrieve file from the FTP server
1223 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1224 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1227 LPWININETFTPSESSIONW lpwfs;
1228 LPWININETAPPINFOW hIC = NULL;
1231 if (!lpszRemoteFile || !lpszNewFile)
1233 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1237 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1240 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1244 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1246 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1250 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1252 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1256 if (lpwfs->download_in_progress != NULL) {
1257 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1261 hIC = lpwfs->lpAppInfo;
1262 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1264 WORKREQUEST workRequest;
1265 struct WORKREQ_FTPGETFILEW *req;
1267 workRequest.asyncproc = AsyncFtpGetFileProc;
1268 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1269 req = &workRequest.u.FtpGetFileW;
1270 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1271 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1272 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1273 req->fFailIfExists = fFailIfExists;
1274 req->dwFlags = dwInternetFlags;
1275 req->dwContext = dwContext;
1277 r = INTERNET_AsyncCall(&workRequest);
1281 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1282 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1286 WININET_Release( &lpwfs->hdr );
1292 /***********************************************************************
1293 * FTP_FtpGetFileW (Internal)
1295 * Retrieve file from the FTP server
1302 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1303 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1307 BOOL bSuccess = FALSE;
1309 LPWININETAPPINFOW hIC = NULL;
1311 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1313 /* Clear any error information */
1314 INTERNET_SetLastError(0);
1316 /* Ensure we can write to lpszNewfile by opening it */
1317 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1318 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1319 if (INVALID_HANDLE_VALUE == hFile)
1322 /* Set up socket to retrieve data */
1323 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1329 /* Get data socket to server */
1330 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1335 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1336 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1339 if (nResCode == 226)
1342 FTP_SetResponseError(nResCode);
1344 closesocket(nDataSocket);
1349 if (lpwfs->lstnSocket != -1)
1350 closesocket(lpwfs->lstnSocket);
1352 if (INVALID_HANDLE_VALUE != hFile)
1355 hIC = lpwfs->lpAppInfo;
1356 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1358 INTERNET_ASYNC_RESULT iar;
1360 iar.dwResult = (DWORD)bSuccess;
1361 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1362 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1363 &iar, sizeof(INTERNET_ASYNC_RESULT));
1369 /***********************************************************************
1370 * FtpGetFileSize (WININET.@)
1372 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1374 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1376 if (lpdwFileSizeHigh)
1377 *lpdwFileSizeHigh = 0;
1382 /***********************************************************************
1383 * FtpDeleteFileA (WININET.@)
1385 * Delete a file on the ftp server
1392 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1394 LPWSTR lpwzFileName;
1397 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1398 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1399 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1403 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1405 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1406 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1408 TRACE("%p\n", lpwfs);
1410 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1411 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1414 /***********************************************************************
1415 * FtpDeleteFileW (WININET.@)
1417 * Delete a file on the ftp server
1424 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1426 LPWININETFTPSESSIONW lpwfs;
1427 LPWININETAPPINFOW hIC = NULL;
1430 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1433 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1437 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1439 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1445 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1449 hIC = lpwfs->lpAppInfo;
1450 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1452 WORKREQUEST workRequest;
1453 struct WORKREQ_FTPDELETEFILEW *req;
1455 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1456 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1457 req = &workRequest.u.FtpDeleteFileW;
1458 req->lpszFilename = WININET_strdupW(lpszFileName);
1460 r = INTERNET_AsyncCall(&workRequest);
1464 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1468 WININET_Release( &lpwfs->hdr );
1473 /***********************************************************************
1474 * FTP_FtpDeleteFileW (Internal)
1476 * Delete a file on the ftp server
1483 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1486 BOOL bSuccess = FALSE;
1487 LPWININETAPPINFOW hIC = NULL;
1489 TRACE("%p\n", lpwfs);
1491 /* Clear any error information */
1492 INTERNET_SetLastError(0);
1494 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1497 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1500 if (nResCode == 250)
1503 FTP_SetResponseError(nResCode);
1506 hIC = lpwfs->lpAppInfo;
1507 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1509 INTERNET_ASYNC_RESULT iar;
1511 iar.dwResult = (DWORD)bSuccess;
1512 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1513 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1514 &iar, sizeof(INTERNET_ASYNC_RESULT));
1521 /***********************************************************************
1522 * FtpRemoveDirectoryA (WININET.@)
1524 * Remove a directory on the ftp server
1531 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1533 LPWSTR lpwzDirectory;
1536 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1537 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1538 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1542 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1544 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1545 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1547 TRACE("%p\n", lpwfs);
1549 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1550 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1553 /***********************************************************************
1554 * FtpRemoveDirectoryW (WININET.@)
1556 * Remove a directory on the ftp server
1563 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1565 LPWININETFTPSESSIONW lpwfs;
1566 LPWININETAPPINFOW hIC = NULL;
1569 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1572 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1576 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1578 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1584 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1588 hIC = lpwfs->lpAppInfo;
1589 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1591 WORKREQUEST workRequest;
1592 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1594 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1595 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1596 req = &workRequest.u.FtpRemoveDirectoryW;
1597 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1599 r = INTERNET_AsyncCall(&workRequest);
1603 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1607 WININET_Release( &lpwfs->hdr );
1612 /***********************************************************************
1613 * FTP_FtpRemoveDirectoryW (Internal)
1615 * Remove a directory on the ftp server
1622 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1625 BOOL bSuccess = FALSE;
1626 LPWININETAPPINFOW hIC = NULL;
1630 /* Clear any error information */
1631 INTERNET_SetLastError(0);
1633 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1636 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1639 if (nResCode == 250)
1642 FTP_SetResponseError(nResCode);
1646 hIC = lpwfs->lpAppInfo;
1647 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1649 INTERNET_ASYNC_RESULT iar;
1651 iar.dwResult = (DWORD)bSuccess;
1652 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1653 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1654 &iar, sizeof(INTERNET_ASYNC_RESULT));
1661 /***********************************************************************
1662 * FtpRenameFileA (WININET.@)
1664 * Rename a file on the ftp server
1671 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1677 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1678 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1679 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1680 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1681 HeapFree(GetProcessHeap(), 0, lpwzDest);
1685 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1687 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1688 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1690 TRACE("%p\n", lpwfs);
1692 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1693 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1694 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1697 /***********************************************************************
1698 * FtpRenameFileW (WININET.@)
1700 * Rename a file on the ftp server
1707 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1709 LPWININETFTPSESSIONW lpwfs;
1710 LPWININETAPPINFOW hIC = NULL;
1713 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1716 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1720 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1722 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1726 if (!lpszSrc || !lpszDest)
1728 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1732 hIC = lpwfs->lpAppInfo;
1733 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1735 WORKREQUEST workRequest;
1736 struct WORKREQ_FTPRENAMEFILEW *req;
1738 workRequest.asyncproc = AsyncFtpRenameFileProc;
1739 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1740 req = &workRequest.u.FtpRenameFileW;
1741 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1742 req->lpszDestFile = WININET_strdupW(lpszDest);
1744 r = INTERNET_AsyncCall(&workRequest);
1748 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1752 WININET_Release( &lpwfs->hdr );
1757 /***********************************************************************
1758 * FTP_FtpRenameFileW (Internal)
1760 * Rename a file on the ftp server
1767 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1768 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1771 BOOL bSuccess = FALSE;
1772 LPWININETAPPINFOW hIC = NULL;
1776 /* Clear any error information */
1777 INTERNET_SetLastError(0);
1779 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1782 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1783 if (nResCode == 350)
1785 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1788 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1791 if (nResCode == 250)
1794 FTP_SetResponseError(nResCode);
1797 hIC = lpwfs->lpAppInfo;
1798 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1800 INTERNET_ASYNC_RESULT iar;
1802 iar.dwResult = (DWORD)bSuccess;
1803 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1804 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1805 &iar, sizeof(INTERNET_ASYNC_RESULT));
1811 /***********************************************************************
1812 * FtpCommandA (WININET.@)
1814 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1815 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1817 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1818 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1823 /***********************************************************************
1824 * FtpCommandW (WININET.@)
1826 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1827 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1829 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1830 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1835 /***********************************************************************
1836 * FTP_Connect (internal)
1838 * Connect to a ftp server
1841 * HINTERNET a session handle on success
1846 * Windows uses 'anonymous' as the username, when given a NULL username
1847 * and a NULL password. The password is first looked up in:
1849 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1851 * If this entry is not present it uses the current username as the password.
1855 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1856 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1857 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1858 DWORD dwInternalFlags)
1860 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1861 'M','i','c','r','o','s','o','f','t','\\',
1862 'W','i','n','d','o','w','s','\\',
1863 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1864 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1865 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1866 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1867 static const WCHAR szEmpty[] = {'\0'};
1868 struct sockaddr_in socketAddr;
1871 BOOL bSuccess = FALSE;
1872 LPWININETFTPSESSIONW lpwfs = NULL;
1873 HINTERNET handle = NULL;
1875 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1876 hIC, debugstr_w(lpszServerName),
1877 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1879 assert( hIC->hdr.htype == WH_HINIT );
1881 if (NULL == lpszUserName && NULL != lpszPassword)
1883 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1887 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1890 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1894 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1895 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1897 lpwfs->hdr.htype = WH_HFTPSESSION;
1898 lpwfs->hdr.dwFlags = dwFlags;
1899 lpwfs->hdr.dwContext = dwContext;
1900 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1901 lpwfs->hdr.dwRefCount = 1;
1902 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1903 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1904 lpwfs->download_in_progress = NULL;
1906 WININET_AddRef( &hIC->hdr );
1907 lpwfs->lpAppInfo = hIC;
1909 handle = WININET_AllocHandle( &lpwfs->hdr );
1912 ERR("Failed to alloc handle\n");
1913 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1917 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1918 if(strchrW(hIC->lpszProxy, ' '))
1919 FIXME("Several proxies not implemented.\n");
1920 if(hIC->lpszProxyBypass)
1921 FIXME("Proxy bypass is ignored.\n");
1923 if ( !lpszUserName) {
1925 WCHAR szPassword[MAX_PATH];
1926 DWORD len = sizeof(szPassword);
1928 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1930 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1931 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1932 /* Nothing in the registry, get the username and use that as the password */
1933 if (!GetUserNameW(szPassword, &len)) {
1934 /* Should never get here, but use an empty password as failsafe */
1935 strcpyW(szPassword, szEmpty);
1940 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1941 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1944 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1947 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1949 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1952 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1953 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1955 INTERNET_ASYNC_RESULT iar;
1957 iar.dwResult = (DWORD)handle;
1958 iar.dwError = ERROR_SUCCESS;
1960 SendAsyncCallback(&hIC->hdr, dwContext,
1961 INTERNET_STATUS_HANDLE_CREATED, &iar,
1962 sizeof(INTERNET_ASYNC_RESULT));
1965 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1966 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1968 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1970 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1974 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1975 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1977 nsocket = socket(AF_INET,SOCK_STREAM,0);
1980 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1984 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1985 &socketAddr, sizeof(struct sockaddr_in));
1987 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1989 ERR("Unable to connect (%s)\n", strerror(errno));
1990 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1994 TRACE("Connected to server\n");
1995 lpwfs->sndSocket = nsocket;
1996 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1997 &socketAddr, sizeof(struct sockaddr_in));
1999 sock_namelen = sizeof(lpwfs->socketAddress);
2000 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2002 if (FTP_ConnectToHost(lpwfs))
2004 TRACE("Successfully logged into server\n");
2010 if (!bSuccess && nsocket != -1)
2011 closesocket(nsocket);
2013 if (!bSuccess && lpwfs)
2015 HeapFree(GetProcessHeap(), 0, lpwfs);
2016 WININET_FreeHandle( handle );
2021 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2023 INTERNET_ASYNC_RESULT iar;
2025 iar.dwResult = (DWORD)lpwfs;
2026 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2027 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2028 &iar, sizeof(INTERNET_ASYNC_RESULT));
2035 /***********************************************************************
2036 * FTP_ConnectToHost (internal)
2038 * Connect to a ftp server
2045 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2048 BOOL bSuccess = FALSE;
2051 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2053 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2056 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2059 /* Login successful... */
2060 if (nResCode == 230)
2062 /* User name okay, need password... */
2063 else if (nResCode == 331)
2064 bSuccess = FTP_SendPassword(lpwfs);
2065 /* Need account for login... */
2066 else if (nResCode == 332)
2067 bSuccess = FTP_SendAccount(lpwfs);
2069 FTP_SetResponseError(nResCode);
2072 TRACE("Returning %d\n", bSuccess);
2078 /***********************************************************************
2079 * FTP_SendCommandA (internal)
2081 * Send command to server
2088 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2089 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2093 DWORD nBytesSent = 0;
2097 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2101 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2104 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2105 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2106 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2108 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2111 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2112 dwParamLen ? lpszParam : "", szCRLF);
2114 TRACE("Sending (%s) len(%d)\n", buf, len);
2115 while((nBytesSent < len) && (nRC != -1))
2117 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2121 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2125 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2126 &nBytesSent, sizeof(DWORD));
2129 TRACE("Sent %d bytes\n", nBytesSent);
2133 /***********************************************************************
2134 * FTP_SendCommand (internal)
2136 * Send command to server
2143 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2144 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2147 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2148 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2149 HeapFree(GetProcessHeap(), 0, lpszParamA);
2153 /***********************************************************************
2154 * FTP_ReceiveResponse (internal)
2156 * Receive response from server
2159 * Reply code on success
2163 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2165 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2168 char firstprefix[5];
2169 BOOL multiline = FALSE;
2170 LPWININETAPPINFOW hIC = NULL;
2172 TRACE("socket(%d)\n", lpwfs->sndSocket);
2174 hIC = lpwfs->lpAppInfo;
2175 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2179 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2186 if(lpszResponse[3] != '-')
2189 { /* Start of multiline repsonse. Loop until we get "nnn " */
2191 memcpy(firstprefix, lpszResponse, 3);
2192 firstprefix[3] = ' ';
2193 firstprefix[4] = '\0';
2198 if(!memcmp(firstprefix, lpszResponse, 4))
2206 rc = atoi(lpszResponse);
2208 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2209 &nRecv, sizeof(DWORD));
2213 TRACE("return %d\n", rc);
2218 /***********************************************************************
2219 * FTP_SendPassword (internal)
2221 * Send password to ftp server
2228 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2231 BOOL bSuccess = FALSE;
2234 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2237 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2240 TRACE("Received reply code %d\n", nResCode);
2241 /* Login successful... */
2242 if (nResCode == 230)
2244 /* Command not implemented, superfluous at the server site... */
2245 /* Need account for login... */
2246 else if (nResCode == 332)
2247 bSuccess = FTP_SendAccount(lpwfs);
2249 FTP_SetResponseError(nResCode);
2253 TRACE("Returning %d\n", bSuccess);
2258 /***********************************************************************
2259 * FTP_SendAccount (internal)
2268 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2271 BOOL bSuccess = FALSE;
2274 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2277 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2281 FTP_SetResponseError(nResCode);
2288 /***********************************************************************
2289 * FTP_SendStore (internal)
2291 * Send request to upload file to ftp server
2298 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2301 BOOL bSuccess = FALSE;
2304 if (!FTP_InitListenSocket(lpwfs))
2307 if (!FTP_SendType(lpwfs, dwType))
2310 if (!FTP_SendPortOrPasv(lpwfs))
2313 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2315 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2318 if (nResCode == 150 || nResCode == 125)
2321 FTP_SetResponseError(nResCode);
2325 if (!bSuccess && lpwfs->lstnSocket != -1)
2327 closesocket(lpwfs->lstnSocket);
2328 lpwfs->lstnSocket = -1;
2335 /***********************************************************************
2336 * FTP_InitListenSocket (internal)
2338 * Create a socket to listen for server response
2345 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2347 BOOL bSuccess = FALSE;
2348 socklen_t namelen = sizeof(struct sockaddr_in);
2352 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2353 if (lpwfs->lstnSocket == -1)
2355 TRACE("Unable to create listening socket\n");
2359 /* We obtain our ip addr from the name of the command channel socket */
2360 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2362 /* and get the system to assign us a port */
2363 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2365 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2367 TRACE("Unable to bind socket\n");
2371 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2373 TRACE("listen failed\n");
2377 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2381 if (!bSuccess && lpwfs->lstnSocket != -1)
2383 closesocket(lpwfs->lstnSocket);
2384 lpwfs->lstnSocket = -1;
2391 /***********************************************************************
2392 * FTP_SendType (internal)
2394 * Tell server type of data being transferred
2400 * W98SE doesn't cache the type that's currently set
2401 * (i.e. it sends it always),
2402 * so we probably don't want to do that either.
2404 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2407 WCHAR type[] = { 'I','\0' };
2408 BOOL bSuccess = FALSE;
2411 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2414 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2417 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2423 FTP_SetResponseError(nResCode);
2430 /***********************************************************************
2431 * FTP_GetFileSize (internal)
2433 * Retrieves from the server the size of the given file
2440 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2443 BOOL bSuccess = FALSE;
2447 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2450 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2453 if (nResCode == 213) {
2454 /* Now parses the output to get the actual file size */
2456 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2458 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2459 if (lpszResponseBuffer[i] == '\0') return FALSE;
2460 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2464 FTP_SetResponseError(nResCode);
2473 /***********************************************************************
2474 * FTP_SendPort (internal)
2476 * Tell server which port to use
2483 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2485 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2487 WCHAR szIPAddress[64];
2488 BOOL bSuccess = FALSE;
2491 sprintfW(szIPAddress, szIPFormat,
2492 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2493 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2494 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2495 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2496 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2497 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2499 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2502 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2505 if (nResCode == 200)
2508 FTP_SetResponseError(nResCode);
2516 /***********************************************************************
2517 * FTP_DoPassive (internal)
2519 * Tell server that we want to do passive transfers
2520 * and connect data socket
2527 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2530 BOOL bSuccess = FALSE;
2533 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2536 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2539 if (nResCode == 227)
2541 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2545 char *pAddr, *pPort;
2547 struct sockaddr_in dataSocketAddress;
2549 p = lpszResponseBuffer+4; /* skip status code */
2551 /* do a very strict check; we can improve that later. */
2553 if (strncmp(p, "Entering Passive Mode", 21))
2555 ERR("unknown response '%.*s', aborting\n", 21, p);
2558 p += 21; /* skip string */
2559 if ((*p++ != ' ') || (*p++ != '('))
2561 ERR("unknown response format, aborting\n");
2565 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2568 ERR("unknown response address format '%s', aborting\n", p);
2571 for (i=0; i < 6; i++)
2574 dataSocketAddress = lpwfs->socketAddress;
2575 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2576 pPort = (char *)&(dataSocketAddress.sin_port);
2584 nsocket = socket(AF_INET,SOCK_STREAM,0);
2588 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2590 ERR("can't connect passive FTP data port.\n");
2591 closesocket(nsocket);
2594 lpwfs->pasvSocket = nsocket;
2598 FTP_SetResponseError(nResCode);
2606 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2608 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2610 if (!FTP_DoPassive(lpwfs))
2615 if (!FTP_SendPort(lpwfs))
2622 /***********************************************************************
2623 * FTP_GetDataSocket (internal)
2625 * Either accepts an incoming data socket connection from the server
2626 * or just returns the already opened socket after a PASV command
2627 * in case of passive FTP.
2635 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2637 struct sockaddr_in saddr;
2638 socklen_t addrlen = sizeof(struct sockaddr);
2641 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2643 *nDataSocket = lpwfs->pasvSocket;
2647 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2648 closesocket(lpwfs->lstnSocket);
2649 lpwfs->lstnSocket = -1;
2651 return *nDataSocket != -1;
2655 /***********************************************************************
2656 * FTP_SendData (internal)
2658 * Send data to the server
2665 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2667 BY_HANDLE_FILE_INFORMATION fi;
2668 DWORD nBytesRead = 0;
2669 DWORD nBytesSent = 0;
2670 DWORD nTotalSent = 0;
2671 DWORD nBytesToSend, nLen;
2673 time_t s_long_time, e_long_time;
2678 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2679 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2681 /* Get the size of the file. */
2682 GetFileInformationByHandle(hFile, &fi);
2687 nBytesToSend = nBytesRead - nBytesSent;
2689 if (nBytesToSend <= 0)
2691 /* Read data from file. */
2693 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2694 ERR("Failed reading from file\n");
2697 nBytesToSend = nBytesRead;
2702 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2703 DATA_PACKET_SIZE : nBytesToSend;
2704 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2712 /* Do some computation to display the status. */
2714 nSeconds = e_long_time - s_long_time;
2715 if( nSeconds / 60 > 0 )
2717 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2718 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2719 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2723 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2724 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2725 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2727 } while (nRC != -1);
2729 TRACE("file transfer complete!\n");
2731 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2737 /***********************************************************************
2738 * FTP_SendRetrieve (internal)
2740 * Send request to retrieve a file
2743 * Number of bytes to be received on success
2747 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2753 if (!FTP_InitListenSocket(lpwfs))
2756 if (!FTP_SendType(lpwfs, dwType))
2759 if (!FTP_SendPortOrPasv(lpwfs))
2762 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2765 TRACE("Waiting to receive %d bytes\n", nResult);
2767 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2770 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2771 if ((nResCode != 125) && (nResCode != 150)) {
2772 /* That means that we got an error getting the file. */
2777 if (0 == nResult && lpwfs->lstnSocket != -1)
2779 closesocket(lpwfs->lstnSocket);
2780 lpwfs->lstnSocket = -1;
2787 /***********************************************************************
2788 * FTP_RetrieveData (internal)
2790 * Retrieve data from server
2797 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2799 DWORD nBytesWritten;
2800 DWORD nBytesReceived = 0;
2806 if (INVALID_HANDLE_VALUE == hFile)
2809 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2810 if (NULL == lpszBuffer)
2812 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2816 while (nBytesReceived < nBytes && nRC != -1)
2818 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2821 /* other side closed socket. */
2824 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2825 nBytesReceived += nRC;
2828 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2829 nBytesReceived * 100 / nBytes);
2832 TRACE("Data transfer complete\n");
2833 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2840 /***********************************************************************
2841 * FTP_CloseSessionHandle (internal)
2843 * Deallocate session handle
2850 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2852 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2856 WININET_Release(&lpwfs->lpAppInfo->hdr);
2858 if (lpwfs->download_in_progress != NULL)
2859 lpwfs->download_in_progress->session_deleted = TRUE;
2861 if (lpwfs->sndSocket != -1)
2862 closesocket(lpwfs->sndSocket);
2864 if (lpwfs->lstnSocket != -1)
2865 closesocket(lpwfs->lstnSocket);
2867 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2868 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2869 HeapFree(GetProcessHeap(), 0, lpwfs);
2873 /***********************************************************************
2874 * FTP_FindNextFileW (Internal)
2876 * Continues a file search from a previous call to FindFirstFile
2883 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2885 BOOL bSuccess = TRUE;
2886 LPWIN32_FIND_DATAW lpFindFileData;
2888 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2890 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2892 /* Clear any error information */
2893 INTERNET_SetLastError(0);
2895 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2896 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2898 if (lpwh->index >= lpwh->size)
2900 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2905 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2908 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2912 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2914 INTERNET_ASYNC_RESULT iar;
2916 iar.dwResult = (DWORD)bSuccess;
2917 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2918 INTERNET_GetLastError();
2920 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2921 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2922 sizeof(INTERNET_ASYNC_RESULT));
2929 /***********************************************************************
2930 * FTP_CloseFindNextHandle (internal)
2932 * Deallocate session handle
2939 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2941 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2946 WININET_Release(&lpwfn->lpFtpSession->hdr);
2948 for (i = 0; i < lpwfn->size; i++)
2950 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2953 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2954 HeapFree(GetProcessHeap(), 0, lpwfn);
2957 /***********************************************************************
2958 * FTP_CloseFileTransferHandle (internal)
2960 * Closes the file transfer handle. This also 'cleans' the data queue of
2961 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2964 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2966 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2967 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2972 WININET_Release(&lpwh->lpFtpSession->hdr);
2974 if (!lpwh->session_deleted)
2975 lpwfs->download_in_progress = NULL;
2977 /* This just serves to flush the control socket of any spurrious lines written
2978 to it (like '226 Transfer complete.').
2980 Wonder what to do if the server sends us an error code though...
2982 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2984 if (lpwh->nDataSocket != -1)
2985 closesocket(lpwh->nDataSocket);
2987 HeapFree(GetProcessHeap(), 0, lpwh);
2990 /***********************************************************************
2991 * FTP_ReceiveFileList (internal)
2993 * Read file list from server
2996 * Handle to file list on success
3000 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3001 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
3004 LPFILEPROPERTIESW lpafp = NULL;
3005 LPWININETFTPFINDNEXTW lpwfn = NULL;
3006 HINTERNET handle = 0;
3008 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3010 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3013 FTP_ConvertFileProp(lpafp, lpFindFileData);
3015 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3018 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3019 lpwfn->hdr.dwContext = dwContext;
3020 lpwfn->hdr.dwRefCount = 1;
3021 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3022 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3023 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3024 lpwfn->size = dwSize;
3025 lpwfn->lpafp = lpafp;
3027 WININET_AddRef( &lpwfs->hdr );
3028 lpwfn->lpFtpSession = lpwfs;
3030 handle = WININET_AllocHandle( &lpwfn->hdr );
3035 WININET_Release( &lpwfn->hdr );
3037 TRACE("Matched %d files\n", dwSize);
3042 /***********************************************************************
3043 * FTP_ConvertFileProp (internal)
3045 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3052 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3054 BOOL bSuccess = FALSE;
3056 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3060 /* Convert 'Unix' time to Windows time */
3061 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3062 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3063 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3064 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3066 /* Not all fields are filled in */
3067 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3068 lpFindFileData->nFileSizeLow = lpafp->nSize;
3070 if (lpafp->bIsDirectory)
3071 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3073 if (lpafp->lpszName)
3074 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3082 /***********************************************************************
3083 * FTP_ParseNextFile (internal)
3085 * Parse the next line in file listing
3091 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3093 static const char szSpace[] = " \t";
3101 lpfp->lpszName = NULL;
3103 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3106 pszToken = strtok(pszLine, szSpace);
3108 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3111 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3113 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3114 if(!FTP_ParsePermission(pszToken, lpfp))
3115 lpfp->bIsDirectory = FALSE;
3116 for(i=0; i<=3; i++) {
3117 if(!(pszToken = strtok(NULL, szSpace)))
3120 if(!pszToken) continue;
3121 if(lpfp->bIsDirectory) {
3122 TRACE("Is directory\n");
3126 TRACE("Size: %s\n", pszToken);
3127 lpfp->nSize = atol(pszToken);
3130 lpfp->tmLastModified.tm_sec = 0;
3131 lpfp->tmLastModified.tm_min = 0;
3132 lpfp->tmLastModified.tm_hour = 0;
3133 lpfp->tmLastModified.tm_mday = 0;
3134 lpfp->tmLastModified.tm_mon = 0;
3135 lpfp->tmLastModified.tm_year = 0;
3137 /* Determine month */
3138 pszToken = strtok(NULL, szSpace);
3139 if(!pszToken) continue;
3140 if(strlen(pszToken) >= 3) {
3142 if((pszTmp = StrStrIA(szMonths, pszToken)))
3143 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3146 pszToken = strtok(NULL, szSpace);
3147 if(!pszToken) continue;
3148 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3149 /* Determine time or year */
3150 pszToken = strtok(NULL, szSpace);
3151 if(!pszToken) continue;
3152 if((pszTmp = strchr(pszToken, ':'))) {
3157 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3158 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3160 apTM = localtime(&aTime);
3161 lpfp->tmLastModified.tm_year = apTM->tm_year;
3164 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3165 lpfp->tmLastModified.tm_hour = 12;
3167 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3168 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3169 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3170 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3172 pszToken = strtok(NULL, szSpace);
3173 if(!pszToken) continue;
3174 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3175 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3177 /* NT way of parsing ... :
3179 07-13-03 08:55PM <DIR> sakpatch
3180 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3182 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3183 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3185 sscanf(pszToken, "%d-%d-%d",
3186 &lpfp->tmLastModified.tm_mon,
3187 &lpfp->tmLastModified.tm_mday,
3188 &lpfp->tmLastModified.tm_year);
3190 /* Hacky and bad Y2K protection :-) */
3191 if (lpfp->tmLastModified.tm_year < 70)
3192 lpfp->tmLastModified.tm_year += 100;
3194 pszToken = strtok(NULL, szSpace);
3195 if(!pszToken) continue;
3196 sscanf(pszToken, "%d:%d",
3197 &lpfp->tmLastModified.tm_hour,
3198 &lpfp->tmLastModified.tm_min);
3199 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3200 lpfp->tmLastModified.tm_hour += 12;
3202 lpfp->tmLastModified.tm_sec = 0;
3204 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3205 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3206 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3207 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3209 pszToken = strtok(NULL, szSpace);
3210 if(!pszToken) continue;
3211 if(!strcasecmp(pszToken, "<DIR>")) {
3212 lpfp->bIsDirectory = TRUE;
3214 TRACE("Is directory\n");
3217 lpfp->bIsDirectory = FALSE;
3218 lpfp->nSize = atol(pszToken);
3219 TRACE("Size: %d\n", lpfp->nSize);
3222 pszToken = strtok(NULL, szSpace);
3223 if(!pszToken) continue;
3224 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3225 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3227 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3228 else if(pszToken[0] == '+') {
3229 FIXME("EPLF Format not implemented\n");
3232 if(lpfp->lpszName) {
3233 if((lpszSearchFile == NULL) ||
3234 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3236 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3239 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3240 lpfp->lpszName = NULL;
3247 /***********************************************************************
3248 * FTP_ParseDirectory (internal)
3250 * Parse string of directory information
3256 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3257 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3259 BOOL bSuccess = TRUE;
3260 INT sizeFilePropArray = 500;/*20; */
3261 INT indexFilePropArray = -1;
3265 /* Allocate intial file properties array */
3266 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3271 if (indexFilePropArray+1 >= sizeFilePropArray)
3273 LPFILEPROPERTIESW tmpafp;
3275 sizeFilePropArray *= 2;
3276 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3277 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3286 indexFilePropArray++;
3287 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3289 if (bSuccess && indexFilePropArray)
3291 if (indexFilePropArray < sizeFilePropArray - 1)
3293 LPFILEPROPERTIESW tmpafp;
3295 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3296 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3300 *dwfp = indexFilePropArray;
3304 HeapFree(GetProcessHeap(), 0, *lpafp);
3305 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3313 /***********************************************************************
3314 * FTP_ParsePermission (internal)
3316 * Parse permission string of directory information
3323 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3325 BOOL bSuccess = TRUE;
3326 unsigned short nPermission = 0;
3331 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3337 lpfp->bIsDirectory = (*lpszPermission == 'd');
3343 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3346 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3349 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3352 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3355 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3358 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3361 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3364 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3367 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3371 }while (nPos <= nLast);
3373 lpfp->permissions = nPermission;
3378 /***********************************************************************
3379 * FTP_SetResponseError (internal)
3381 * Set the appropriate error code for a given response from the server
3386 static DWORD FTP_SetResponseError(DWORD dwResponse)
3392 case 421: /* Service not available - Server may be shutting down. */
3393 dwCode = ERROR_INTERNET_TIMEOUT;
3396 case 425: /* Cannot open data connection. */
3397 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3400 case 426: /* Connection closed, transer aborted. */
3401 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3404 case 500: /* Syntax error. Command unrecognized. */
3405 case 501: /* Syntax error. Error in parameters or arguments. */
3406 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3409 case 530: /* Not logged in. Login incorrect. */
3410 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3413 case 550: /* File action not taken. File not found or no access. */
3414 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3417 case 450: /* File action not taken. File may be busy. */
3418 case 451: /* Action aborted. Server error. */
3419 case 452: /* Action not taken. Insufficient storage space on server. */
3420 case 502: /* Command not implemented. */
3421 case 503: /* Bad sequence of commands. */
3422 case 504: /* Command not implemented for that parameter. */
3423 case 532: /* Need account for storing files */
3424 case 551: /* Requested action aborted. Page type unknown */
3425 case 552: /* Action aborted. Exceeded storage allocation */
3426 case 553: /* Action not taken. File name not allowed. */
3429 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3433 INTERNET_SetLastError(dwCode);