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 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
741 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
744 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
747 if (nResCode == 125 || nResCode == 150)
751 /* Get data socket to server */
752 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
754 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
755 closesocket(nDataSocket);
756 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
757 if (nResCode != 226 && nResCode != 250)
758 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
762 FTP_SetResponseError(nResCode);
766 if (lpwfs->lstnSocket != -1)
767 closesocket(lpwfs->lstnSocket);
769 hIC = lpwfs->lpAppInfo;
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.close_connection = NULL;
1125 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1126 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1127 lpwh->nDataSocket = nDataSocket;
1128 lpwh->session_deleted = FALSE;
1130 WININET_AddRef( &lpwfs->hdr );
1131 lpwh->lpFtpSession = lpwfs;
1133 handle = WININET_AllocHandle( &lpwh->hdr );
1137 /* Indicate that a download is currently in progress */
1138 lpwfs->download_in_progress = lpwh;
1141 if (lpwfs->lstnSocket != -1)
1142 closesocket(lpwfs->lstnSocket);
1144 hIC = lpwfs->lpAppInfo;
1145 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1147 INTERNET_ASYNC_RESULT iar;
1151 iar.dwResult = (DWORD)handle;
1152 iar.dwError = ERROR_SUCCESS;
1153 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1154 &iar, sizeof(INTERNET_ASYNC_RESULT));
1157 iar.dwResult = (DWORD)bSuccess;
1158 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1159 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1160 &iar, sizeof(INTERNET_ASYNC_RESULT));
1165 WININET_Release( &lpwh->hdr );
1171 /***********************************************************************
1172 * FtpGetFileA (WININET.@)
1174 * Retrieve file from the FTP server
1181 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1182 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1185 LPWSTR lpwzRemoteFile;
1189 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1190 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1191 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1192 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1193 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1194 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1199 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1201 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1202 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1204 TRACE("%p\n", lpwfs);
1206 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1207 req->lpszNewFile, req->fFailIfExists,
1208 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1209 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1210 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1214 /***********************************************************************
1215 * FtpGetFileW (WININET.@)
1217 * Retrieve file from the FTP server
1224 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1225 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1228 LPWININETFTPSESSIONW lpwfs;
1229 LPWININETAPPINFOW hIC = NULL;
1232 if (!lpszRemoteFile || !lpszNewFile)
1234 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1238 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1241 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1245 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1247 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1251 if ((dwInternetFlags & FTP_CONDITION_MASK) > FTP_TRANSFER_TYPE_BINARY)
1253 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1257 if (lpwfs->download_in_progress != NULL) {
1258 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1262 hIC = lpwfs->lpAppInfo;
1263 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1265 WORKREQUEST workRequest;
1266 struct WORKREQ_FTPGETFILEW *req;
1268 workRequest.asyncproc = AsyncFtpGetFileProc;
1269 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1270 req = &workRequest.u.FtpGetFileW;
1271 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1272 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1273 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1274 req->fFailIfExists = fFailIfExists;
1275 req->dwFlags = dwInternetFlags;
1276 req->dwContext = dwContext;
1278 r = INTERNET_AsyncCall(&workRequest);
1282 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1283 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1287 WININET_Release( &lpwfs->hdr );
1293 /***********************************************************************
1294 * FTP_FtpGetFileW (Internal)
1296 * Retrieve file from the FTP server
1303 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1304 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1308 BOOL bSuccess = FALSE;
1310 LPWININETAPPINFOW hIC = NULL;
1312 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1314 /* Clear any error information */
1315 INTERNET_SetLastError(0);
1317 /* Ensure we can write to lpszNewfile by opening it */
1318 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1319 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1320 if (INVALID_HANDLE_VALUE == hFile)
1323 /* Set up socket to retrieve data */
1324 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1330 /* Get data socket to server */
1331 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1336 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1337 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1340 if (nResCode == 226)
1343 FTP_SetResponseError(nResCode);
1345 closesocket(nDataSocket);
1349 if (lpwfs->lstnSocket != -1)
1350 closesocket(lpwfs->lstnSocket);
1354 hIC = lpwfs->lpAppInfo;
1355 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1357 INTERNET_ASYNC_RESULT iar;
1359 iar.dwResult = (DWORD)bSuccess;
1360 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1361 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1362 &iar, sizeof(INTERNET_ASYNC_RESULT));
1368 /***********************************************************************
1369 * FtpGetFileSize (WININET.@)
1371 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1373 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1375 if (lpdwFileSizeHigh)
1376 *lpdwFileSizeHigh = 0;
1381 /***********************************************************************
1382 * FtpDeleteFileA (WININET.@)
1384 * Delete a file on the ftp server
1391 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1393 LPWSTR lpwzFileName;
1396 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1397 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1398 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1402 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1404 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1405 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1407 TRACE("%p\n", lpwfs);
1409 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1410 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1413 /***********************************************************************
1414 * FtpDeleteFileW (WININET.@)
1416 * Delete a file on the ftp server
1423 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1425 LPWININETFTPSESSIONW lpwfs;
1426 LPWININETAPPINFOW hIC = NULL;
1429 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1432 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1436 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1438 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1444 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1448 hIC = lpwfs->lpAppInfo;
1449 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1451 WORKREQUEST workRequest;
1452 struct WORKREQ_FTPDELETEFILEW *req;
1454 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1455 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1456 req = &workRequest.u.FtpDeleteFileW;
1457 req->lpszFilename = WININET_strdupW(lpszFileName);
1459 r = INTERNET_AsyncCall(&workRequest);
1463 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1467 WININET_Release( &lpwfs->hdr );
1472 /***********************************************************************
1473 * FTP_FtpDeleteFileW (Internal)
1475 * Delete a file on the ftp server
1482 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1485 BOOL bSuccess = FALSE;
1486 LPWININETAPPINFOW hIC = NULL;
1488 TRACE("%p\n", lpwfs);
1490 /* Clear any error information */
1491 INTERNET_SetLastError(0);
1493 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1496 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1499 if (nResCode == 250)
1502 FTP_SetResponseError(nResCode);
1505 hIC = lpwfs->lpAppInfo;
1506 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1508 INTERNET_ASYNC_RESULT iar;
1510 iar.dwResult = (DWORD)bSuccess;
1511 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1512 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1513 &iar, sizeof(INTERNET_ASYNC_RESULT));
1520 /***********************************************************************
1521 * FtpRemoveDirectoryA (WININET.@)
1523 * Remove a directory on the ftp server
1530 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1532 LPWSTR lpwzDirectory;
1535 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1536 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1537 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1541 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1543 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1544 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1546 TRACE("%p\n", lpwfs);
1548 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1549 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1552 /***********************************************************************
1553 * FtpRemoveDirectoryW (WININET.@)
1555 * Remove a directory on the ftp server
1562 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1564 LPWININETFTPSESSIONW lpwfs;
1565 LPWININETAPPINFOW hIC = NULL;
1568 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1571 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1575 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1577 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1583 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1587 hIC = lpwfs->lpAppInfo;
1588 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1590 WORKREQUEST workRequest;
1591 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1593 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1594 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1595 req = &workRequest.u.FtpRemoveDirectoryW;
1596 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1598 r = INTERNET_AsyncCall(&workRequest);
1602 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1606 WININET_Release( &lpwfs->hdr );
1611 /***********************************************************************
1612 * FTP_FtpRemoveDirectoryW (Internal)
1614 * Remove a directory on the ftp server
1621 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1624 BOOL bSuccess = FALSE;
1625 LPWININETAPPINFOW hIC = NULL;
1629 /* Clear any error information */
1630 INTERNET_SetLastError(0);
1632 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1635 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1638 if (nResCode == 250)
1641 FTP_SetResponseError(nResCode);
1645 hIC = lpwfs->lpAppInfo;
1646 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1648 INTERNET_ASYNC_RESULT iar;
1650 iar.dwResult = (DWORD)bSuccess;
1651 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1652 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1653 &iar, sizeof(INTERNET_ASYNC_RESULT));
1660 /***********************************************************************
1661 * FtpRenameFileA (WININET.@)
1663 * Rename a file on the ftp server
1670 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1676 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1677 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1678 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1679 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1680 HeapFree(GetProcessHeap(), 0, lpwzDest);
1684 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1686 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1687 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1689 TRACE("%p\n", lpwfs);
1691 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1692 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1693 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1696 /***********************************************************************
1697 * FtpRenameFileW (WININET.@)
1699 * Rename a file on the ftp server
1706 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1708 LPWININETFTPSESSIONW lpwfs;
1709 LPWININETAPPINFOW hIC = NULL;
1712 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1715 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1719 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1721 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1725 if (!lpszSrc || !lpszDest)
1727 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1731 hIC = lpwfs->lpAppInfo;
1732 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1734 WORKREQUEST workRequest;
1735 struct WORKREQ_FTPRENAMEFILEW *req;
1737 workRequest.asyncproc = AsyncFtpRenameFileProc;
1738 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1739 req = &workRequest.u.FtpRenameFileW;
1740 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1741 req->lpszDestFile = WININET_strdupW(lpszDest);
1743 r = INTERNET_AsyncCall(&workRequest);
1747 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1751 WININET_Release( &lpwfs->hdr );
1756 /***********************************************************************
1757 * FTP_FtpRenameFileW (Internal)
1759 * Rename a file on the ftp server
1766 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1767 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1770 BOOL bSuccess = FALSE;
1771 LPWININETAPPINFOW hIC = NULL;
1775 /* Clear any error information */
1776 INTERNET_SetLastError(0);
1778 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1781 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1782 if (nResCode == 350)
1784 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1787 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1790 if (nResCode == 250)
1793 FTP_SetResponseError(nResCode);
1796 hIC = lpwfs->lpAppInfo;
1797 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1799 INTERNET_ASYNC_RESULT iar;
1801 iar.dwResult = (DWORD)bSuccess;
1802 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1803 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1804 &iar, sizeof(INTERNET_ASYNC_RESULT));
1810 /***********************************************************************
1811 * FtpCommandA (WININET.@)
1813 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1814 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1816 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1817 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1822 /***********************************************************************
1823 * FtpCommandW (WININET.@)
1825 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1826 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1828 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1829 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1834 /***********************************************************************
1835 * FTP_Connect (internal)
1837 * Connect to a ftp server
1840 * HINTERNET a session handle on success
1845 * Windows uses 'anonymous' as the username, when given a NULL username
1846 * and a NULL password. The password is first looked up in:
1848 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1850 * If this entry is not present it uses the current username as the password.
1854 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1855 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1856 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1857 DWORD dwInternalFlags)
1859 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1860 'M','i','c','r','o','s','o','f','t','\\',
1861 'W','i','n','d','o','w','s','\\',
1862 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1863 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1864 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1865 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1866 static const WCHAR szEmpty[] = {'\0'};
1867 struct sockaddr_in socketAddr;
1870 BOOL bSuccess = FALSE;
1871 LPWININETFTPSESSIONW lpwfs = NULL;
1872 HINTERNET handle = NULL;
1874 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1875 hIC, debugstr_w(lpszServerName),
1876 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1878 assert( hIC->hdr.htype == WH_HINIT );
1880 if (NULL == lpszUserName && NULL != lpszPassword)
1882 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1886 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1889 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1893 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1894 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1896 lpwfs->hdr.htype = WH_HFTPSESSION;
1897 lpwfs->hdr.dwFlags = dwFlags;
1898 lpwfs->hdr.dwContext = dwContext;
1899 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1900 lpwfs->hdr.dwRefCount = 1;
1901 /* FIXME: Native sends INTERNET_STATUS_CLOSING_CONNECTION and
1902 * INTERNET_STATUS_CONNECTION_CLOSED, need an equivalent FTP_CloseConnection
1904 lpwfs->hdr.close_connection = NULL;
1905 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1906 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1907 lpwfs->download_in_progress = NULL;
1909 WININET_AddRef( &hIC->hdr );
1910 lpwfs->lpAppInfo = hIC;
1912 handle = WININET_AllocHandle( &lpwfs->hdr );
1915 ERR("Failed to alloc handle\n");
1916 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1920 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1921 if(strchrW(hIC->lpszProxy, ' '))
1922 FIXME("Several proxies not implemented.\n");
1923 if(hIC->lpszProxyBypass)
1924 FIXME("Proxy bypass is ignored.\n");
1926 if ( !lpszUserName) {
1928 WCHAR szPassword[MAX_PATH];
1929 DWORD len = sizeof(szPassword);
1931 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1933 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1934 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1935 /* Nothing in the registry, get the username and use that as the password */
1936 if (!GetUserNameW(szPassword, &len)) {
1937 /* Should never get here, but use an empty password as failsafe */
1938 strcpyW(szPassword, szEmpty);
1943 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1944 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1947 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1950 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1952 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1955 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1956 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1958 INTERNET_ASYNC_RESULT iar;
1960 iar.dwResult = (DWORD)handle;
1961 iar.dwError = ERROR_SUCCESS;
1963 SendAsyncCallback(&hIC->hdr, dwContext,
1964 INTERNET_STATUS_HANDLE_CREATED, &iar,
1965 sizeof(INTERNET_ASYNC_RESULT));
1968 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1969 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1971 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1973 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1977 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1978 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1980 nsocket = socket(AF_INET,SOCK_STREAM,0);
1983 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1987 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1988 &socketAddr, sizeof(struct sockaddr_in));
1990 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1992 ERR("Unable to connect (%s)\n", strerror(errno));
1993 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1997 TRACE("Connected to server\n");
1998 lpwfs->sndSocket = nsocket;
1999 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
2000 &socketAddr, sizeof(struct sockaddr_in));
2002 sock_namelen = sizeof(lpwfs->socketAddress);
2003 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2005 if (FTP_ConnectToHost(lpwfs))
2007 TRACE("Successfully logged into server\n");
2013 if (!bSuccess && nsocket != -1)
2014 closesocket(nsocket);
2016 if (!bSuccess && lpwfs)
2018 HeapFree(GetProcessHeap(), 0, lpwfs);
2019 WININET_FreeHandle( handle );
2024 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2026 INTERNET_ASYNC_RESULT iar;
2028 iar.dwResult = (DWORD)lpwfs;
2029 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2030 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2031 &iar, sizeof(INTERNET_ASYNC_RESULT));
2038 /***********************************************************************
2039 * FTP_ConnectToHost (internal)
2041 * Connect to a ftp server
2048 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2051 BOOL bSuccess = FALSE;
2054 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2056 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2059 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2062 /* Login successful... */
2063 if (nResCode == 230)
2065 /* User name okay, need password... */
2066 else if (nResCode == 331)
2067 bSuccess = FTP_SendPassword(lpwfs);
2068 /* Need account for login... */
2069 else if (nResCode == 332)
2070 bSuccess = FTP_SendAccount(lpwfs);
2072 FTP_SetResponseError(nResCode);
2075 TRACE("Returning %d\n", bSuccess);
2081 /***********************************************************************
2082 * FTP_SendCommandA (internal)
2084 * Send command to server
2091 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2092 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2096 DWORD nBytesSent = 0;
2100 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2104 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2107 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2108 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2109 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2111 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2114 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2115 dwParamLen ? lpszParam : "", szCRLF);
2117 TRACE("Sending (%s) len(%d)\n", buf, len);
2118 while((nBytesSent < len) && (nRC != -1))
2120 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2124 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2128 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2129 &nBytesSent, sizeof(DWORD));
2132 TRACE("Sent %d bytes\n", nBytesSent);
2136 /***********************************************************************
2137 * FTP_SendCommand (internal)
2139 * Send command to server
2146 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2147 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2150 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2151 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2152 HeapFree(GetProcessHeap(), 0, lpszParamA);
2156 /***********************************************************************
2157 * FTP_ReceiveResponse (internal)
2159 * Receive response from server
2162 * Reply code on success
2166 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2168 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2171 char firstprefix[5];
2172 BOOL multiline = FALSE;
2173 LPWININETAPPINFOW hIC = NULL;
2175 TRACE("socket(%d)\n", lpwfs->sndSocket);
2177 hIC = lpwfs->lpAppInfo;
2178 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2182 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2189 if(lpszResponse[3] != '-')
2192 { /* Start of multiline repsonse. Loop until we get "nnn " */
2194 memcpy(firstprefix, lpszResponse, 3);
2195 firstprefix[3] = ' ';
2196 firstprefix[4] = '\0';
2201 if(!memcmp(firstprefix, lpszResponse, 4))
2209 rc = atoi(lpszResponse);
2211 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2212 &nRecv, sizeof(DWORD));
2216 TRACE("return %d\n", rc);
2221 /***********************************************************************
2222 * FTP_SendPassword (internal)
2224 * Send password to ftp server
2231 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2234 BOOL bSuccess = FALSE;
2237 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2240 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2243 TRACE("Received reply code %d\n", nResCode);
2244 /* Login successful... */
2245 if (nResCode == 230)
2247 /* Command not implemented, superfluous at the server site... */
2248 /* Need account for login... */
2249 else if (nResCode == 332)
2250 bSuccess = FTP_SendAccount(lpwfs);
2252 FTP_SetResponseError(nResCode);
2256 TRACE("Returning %d\n", bSuccess);
2261 /***********************************************************************
2262 * FTP_SendAccount (internal)
2271 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2274 BOOL bSuccess = FALSE;
2277 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2280 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2284 FTP_SetResponseError(nResCode);
2291 /***********************************************************************
2292 * FTP_SendStore (internal)
2294 * Send request to upload file to ftp server
2301 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2304 BOOL bSuccess = FALSE;
2307 if (!FTP_InitListenSocket(lpwfs))
2310 if (!FTP_SendType(lpwfs, dwType))
2313 if (!FTP_SendPortOrPasv(lpwfs))
2316 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2318 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2321 if (nResCode == 150 || nResCode == 125)
2324 FTP_SetResponseError(nResCode);
2328 if (!bSuccess && lpwfs->lstnSocket != -1)
2330 closesocket(lpwfs->lstnSocket);
2331 lpwfs->lstnSocket = -1;
2338 /***********************************************************************
2339 * FTP_InitListenSocket (internal)
2341 * Create a socket to listen for server response
2348 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2350 BOOL bSuccess = FALSE;
2351 socklen_t namelen = sizeof(struct sockaddr_in);
2355 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2356 if (lpwfs->lstnSocket == -1)
2358 TRACE("Unable to create listening socket\n");
2362 /* We obtain our ip addr from the name of the command channel socket */
2363 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2365 /* and get the system to assign us a port */
2366 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2368 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2370 TRACE("Unable to bind socket\n");
2374 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2376 TRACE("listen failed\n");
2380 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2384 if (!bSuccess && lpwfs->lstnSocket != -1)
2386 closesocket(lpwfs->lstnSocket);
2387 lpwfs->lstnSocket = -1;
2394 /***********************************************************************
2395 * FTP_SendType (internal)
2397 * Tell server type of data being transferred
2403 * W98SE doesn't cache the type that's currently set
2404 * (i.e. it sends it always),
2405 * so we probably don't want to do that either.
2407 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2410 WCHAR type[] = { 'I','\0' };
2411 BOOL bSuccess = FALSE;
2414 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2417 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2420 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2426 FTP_SetResponseError(nResCode);
2433 /***********************************************************************
2434 * FTP_GetFileSize (internal)
2436 * Retrieves from the server the size of the given file
2443 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2446 BOOL bSuccess = FALSE;
2450 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2453 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2456 if (nResCode == 213) {
2457 /* Now parses the output to get the actual file size */
2459 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2461 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2462 if (lpszResponseBuffer[i] == '\0') return FALSE;
2463 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2467 FTP_SetResponseError(nResCode);
2476 /***********************************************************************
2477 * FTP_SendPort (internal)
2479 * Tell server which port to use
2486 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2488 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2490 WCHAR szIPAddress[64];
2491 BOOL bSuccess = FALSE;
2494 sprintfW(szIPAddress, szIPFormat,
2495 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2496 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2497 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2498 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2499 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2500 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2502 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2505 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2508 if (nResCode == 200)
2511 FTP_SetResponseError(nResCode);
2519 /***********************************************************************
2520 * FTP_DoPassive (internal)
2522 * Tell server that we want to do passive transfers
2523 * and connect data socket
2530 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2533 BOOL bSuccess = FALSE;
2536 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2539 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2542 if (nResCode == 227)
2544 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2548 char *pAddr, *pPort;
2550 struct sockaddr_in dataSocketAddress;
2552 p = lpszResponseBuffer+4; /* skip status code */
2553 while (*p != '\0' && (*p < '0' || *p > '9')) p++;
2557 ERR("no address found in response, aborting\n");
2561 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2564 ERR("unknown response address format '%s', aborting\n", p);
2567 for (i=0; i < 6; i++)
2570 dataSocketAddress = lpwfs->socketAddress;
2571 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2572 pPort = (char *)&(dataSocketAddress.sin_port);
2580 nsocket = socket(AF_INET,SOCK_STREAM,0);
2584 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2586 ERR("can't connect passive FTP data port.\n");
2587 closesocket(nsocket);
2590 lpwfs->pasvSocket = nsocket;
2594 FTP_SetResponseError(nResCode);
2602 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2604 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2606 if (!FTP_DoPassive(lpwfs))
2611 if (!FTP_SendPort(lpwfs))
2618 /***********************************************************************
2619 * FTP_GetDataSocket (internal)
2621 * Either accepts an incoming data socket connection from the server
2622 * or just returns the already opened socket after a PASV command
2623 * in case of passive FTP.
2631 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2633 struct sockaddr_in saddr;
2634 socklen_t addrlen = sizeof(struct sockaddr);
2637 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2639 *nDataSocket = lpwfs->pasvSocket;
2643 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2644 closesocket(lpwfs->lstnSocket);
2645 lpwfs->lstnSocket = -1;
2647 return *nDataSocket != -1;
2651 /***********************************************************************
2652 * FTP_SendData (internal)
2654 * Send data to the server
2661 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2663 BY_HANDLE_FILE_INFORMATION fi;
2664 DWORD nBytesRead = 0;
2665 DWORD nBytesSent = 0;
2666 DWORD nTotalSent = 0;
2667 DWORD nBytesToSend, nLen;
2669 time_t s_long_time, e_long_time;
2674 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2676 /* Get the size of the file. */
2677 GetFileInformationByHandle(hFile, &fi);
2682 nBytesToSend = nBytesRead - nBytesSent;
2684 if (nBytesToSend <= 0)
2686 /* Read data from file. */
2688 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2689 ERR("Failed reading from file\n");
2692 nBytesToSend = nBytesRead;
2697 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2698 DATA_PACKET_SIZE : nBytesToSend;
2699 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2707 /* Do some computation to display the status. */
2709 nSeconds = e_long_time - s_long_time;
2710 if( nSeconds / 60 > 0 )
2712 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2713 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2714 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2718 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2719 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2720 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2722 } while (nRC != -1);
2724 TRACE("file transfer complete!\n");
2726 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2732 /***********************************************************************
2733 * FTP_SendRetrieve (internal)
2735 * Send request to retrieve a file
2738 * Number of bytes to be received on success
2742 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2748 if (!FTP_InitListenSocket(lpwfs))
2751 if (!FTP_SendType(lpwfs, dwType))
2754 if (!FTP_SendPortOrPasv(lpwfs))
2757 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2760 TRACE("Waiting to receive %d bytes\n", nResult);
2762 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2765 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2766 if ((nResCode != 125) && (nResCode != 150)) {
2767 /* That means that we got an error getting the file. */
2772 if (0 == nResult && lpwfs->lstnSocket != -1)
2774 closesocket(lpwfs->lstnSocket);
2775 lpwfs->lstnSocket = -1;
2782 /***********************************************************************
2783 * FTP_RetrieveData (internal)
2785 * Retrieve data from server
2792 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2794 DWORD nBytesWritten;
2795 DWORD nBytesReceived = 0;
2801 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2802 if (NULL == lpszBuffer)
2804 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2808 while (nBytesReceived < nBytes && nRC != -1)
2810 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2813 /* other side closed socket. */
2816 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2817 nBytesReceived += nRC;
2820 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2821 nBytesReceived * 100 / nBytes);
2824 TRACE("Data transfer complete\n");
2827 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2833 /***********************************************************************
2834 * FTP_CloseSessionHandle (internal)
2836 * Deallocate session handle
2843 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2845 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2849 WININET_Release(&lpwfs->lpAppInfo->hdr);
2851 if (lpwfs->download_in_progress != NULL)
2852 lpwfs->download_in_progress->session_deleted = TRUE;
2854 if (lpwfs->sndSocket != -1)
2855 closesocket(lpwfs->sndSocket);
2857 if (lpwfs->lstnSocket != -1)
2858 closesocket(lpwfs->lstnSocket);
2860 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2861 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2862 HeapFree(GetProcessHeap(), 0, lpwfs);
2866 /***********************************************************************
2867 * FTP_FindNextFileW (Internal)
2869 * Continues a file search from a previous call to FindFirstFile
2876 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2878 BOOL bSuccess = TRUE;
2879 LPWIN32_FIND_DATAW lpFindFileData;
2881 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2883 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2885 /* Clear any error information */
2886 INTERNET_SetLastError(0);
2888 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2889 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2891 if (lpwh->index >= lpwh->size)
2893 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2898 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2901 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2905 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2907 INTERNET_ASYNC_RESULT iar;
2909 iar.dwResult = (DWORD)bSuccess;
2910 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2911 INTERNET_GetLastError();
2913 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2914 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2915 sizeof(INTERNET_ASYNC_RESULT));
2922 /***********************************************************************
2923 * FTP_CloseFindNextHandle (internal)
2925 * Deallocate session handle
2932 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2934 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2939 WININET_Release(&lpwfn->lpFtpSession->hdr);
2941 for (i = 0; i < lpwfn->size; i++)
2943 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2946 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2947 HeapFree(GetProcessHeap(), 0, lpwfn);
2950 /***********************************************************************
2951 * FTP_CloseFileTransferHandle (internal)
2953 * Closes the file transfer handle. This also 'cleans' the data queue of
2954 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2957 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2959 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2960 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2965 WININET_Release(&lpwh->lpFtpSession->hdr);
2967 if (!lpwh->session_deleted)
2968 lpwfs->download_in_progress = NULL;
2970 /* This just serves to flush the control socket of any spurrious lines written
2971 to it (like '226 Transfer complete.').
2973 Wonder what to do if the server sends us an error code though...
2975 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2977 if (lpwh->nDataSocket != -1)
2978 closesocket(lpwh->nDataSocket);
2980 HeapFree(GetProcessHeap(), 0, lpwh);
2983 /***********************************************************************
2984 * FTP_ReceiveFileList (internal)
2986 * Read file list from server
2989 * Handle to file list on success
2993 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2994 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2997 LPFILEPROPERTIESW lpafp = NULL;
2998 LPWININETFTPFINDNEXTW lpwfn = NULL;
2999 HINTERNET handle = 0;
3001 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
3003 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3006 FTP_ConvertFileProp(lpafp, lpFindFileData);
3008 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3011 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3012 lpwfn->hdr.dwContext = dwContext;
3013 lpwfn->hdr.dwRefCount = 1;
3014 lpwfn->hdr.close_connection = NULL;
3015 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3016 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3017 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3018 lpwfn->size = dwSize;
3019 lpwfn->lpafp = lpafp;
3021 WININET_AddRef( &lpwfs->hdr );
3022 lpwfn->lpFtpSession = lpwfs;
3024 handle = WININET_AllocHandle( &lpwfn->hdr );
3029 WININET_Release( &lpwfn->hdr );
3031 TRACE("Matched %d files\n", dwSize);
3036 /***********************************************************************
3037 * FTP_ConvertFileProp (internal)
3039 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3046 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3048 BOOL bSuccess = FALSE;
3050 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3054 /* Convert 'Unix' time to Windows time */
3055 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3056 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3057 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3058 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3060 /* Not all fields are filled in */
3061 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3062 lpFindFileData->nFileSizeLow = lpafp->nSize;
3064 if (lpafp->bIsDirectory)
3065 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3067 if (lpafp->lpszName)
3068 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3076 /***********************************************************************
3077 * FTP_ParseNextFile (internal)
3079 * Parse the next line in file listing
3085 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3087 static const char szSpace[] = " \t";
3095 lpfp->lpszName = NULL;
3097 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3100 pszToken = strtok(pszLine, szSpace);
3102 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3105 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3107 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3108 if(!FTP_ParsePermission(pszToken, lpfp))
3109 lpfp->bIsDirectory = FALSE;
3110 for(i=0; i<=3; i++) {
3111 if(!(pszToken = strtok(NULL, szSpace)))
3114 if(!pszToken) continue;
3115 if(lpfp->bIsDirectory) {
3116 TRACE("Is directory\n");
3120 TRACE("Size: %s\n", pszToken);
3121 lpfp->nSize = atol(pszToken);
3124 lpfp->tmLastModified.tm_sec = 0;
3125 lpfp->tmLastModified.tm_min = 0;
3126 lpfp->tmLastModified.tm_hour = 0;
3127 lpfp->tmLastModified.tm_mday = 0;
3128 lpfp->tmLastModified.tm_mon = 0;
3129 lpfp->tmLastModified.tm_year = 0;
3131 /* Determine month */
3132 pszToken = strtok(NULL, szSpace);
3133 if(!pszToken) continue;
3134 if(strlen(pszToken) >= 3) {
3136 if((pszTmp = StrStrIA(szMonths, pszToken)))
3137 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3140 pszToken = strtok(NULL, szSpace);
3141 if(!pszToken) continue;
3142 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3143 /* Determine time or year */
3144 pszToken = strtok(NULL, szSpace);
3145 if(!pszToken) continue;
3146 if((pszTmp = strchr(pszToken, ':'))) {
3151 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3152 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3154 apTM = localtime(&aTime);
3155 lpfp->tmLastModified.tm_year = apTM->tm_year;
3158 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3159 lpfp->tmLastModified.tm_hour = 12;
3161 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3162 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3163 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3164 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3166 pszToken = strtok(NULL, szSpace);
3167 if(!pszToken) continue;
3168 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3169 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3171 /* NT way of parsing ... :
3173 07-13-03 08:55PM <DIR> sakpatch
3174 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3176 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3177 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3179 sscanf(pszToken, "%d-%d-%d",
3180 &lpfp->tmLastModified.tm_mon,
3181 &lpfp->tmLastModified.tm_mday,
3182 &lpfp->tmLastModified.tm_year);
3184 /* Hacky and bad Y2K protection :-) */
3185 if (lpfp->tmLastModified.tm_year < 70)
3186 lpfp->tmLastModified.tm_year += 100;
3188 pszToken = strtok(NULL, szSpace);
3189 if(!pszToken) continue;
3190 sscanf(pszToken, "%d:%d",
3191 &lpfp->tmLastModified.tm_hour,
3192 &lpfp->tmLastModified.tm_min);
3193 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3194 lpfp->tmLastModified.tm_hour += 12;
3196 lpfp->tmLastModified.tm_sec = 0;
3198 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3199 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3200 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3201 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3203 pszToken = strtok(NULL, szSpace);
3204 if(!pszToken) continue;
3205 if(!strcasecmp(pszToken, "<DIR>")) {
3206 lpfp->bIsDirectory = TRUE;
3208 TRACE("Is directory\n");
3211 lpfp->bIsDirectory = FALSE;
3212 lpfp->nSize = atol(pszToken);
3213 TRACE("Size: %d\n", lpfp->nSize);
3216 pszToken = strtok(NULL, szSpace);
3217 if(!pszToken) continue;
3218 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3219 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3221 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3222 else if(pszToken[0] == '+') {
3223 FIXME("EPLF Format not implemented\n");
3226 if(lpfp->lpszName) {
3227 if((lpszSearchFile == NULL) ||
3228 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3230 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3233 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3234 lpfp->lpszName = NULL;
3241 /***********************************************************************
3242 * FTP_ParseDirectory (internal)
3244 * Parse string of directory information
3250 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3251 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3253 BOOL bSuccess = TRUE;
3254 INT sizeFilePropArray = 500;/*20; */
3255 INT indexFilePropArray = -1;
3259 /* Allocate intial file properties array */
3260 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3265 if (indexFilePropArray+1 >= sizeFilePropArray)
3267 LPFILEPROPERTIESW tmpafp;
3269 sizeFilePropArray *= 2;
3270 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3271 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3280 indexFilePropArray++;
3281 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3283 if (bSuccess && indexFilePropArray)
3285 if (indexFilePropArray < sizeFilePropArray - 1)
3287 LPFILEPROPERTIESW tmpafp;
3289 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3290 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3294 *dwfp = indexFilePropArray;
3298 HeapFree(GetProcessHeap(), 0, *lpafp);
3299 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3307 /***********************************************************************
3308 * FTP_ParsePermission (internal)
3310 * Parse permission string of directory information
3317 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3319 BOOL bSuccess = TRUE;
3320 unsigned short nPermission = 0;
3325 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3331 lpfp->bIsDirectory = (*lpszPermission == 'd');
3337 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3340 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3343 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3346 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3349 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3352 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3355 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3358 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3361 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3365 }while (nPos <= nLast);
3367 lpfp->permissions = nPermission;
3372 /***********************************************************************
3373 * FTP_SetResponseError (internal)
3375 * Set the appropriate error code for a given response from the server
3380 static DWORD FTP_SetResponseError(DWORD dwResponse)
3386 case 421: /* Service not available - Server may be shutting down. */
3387 dwCode = ERROR_INTERNET_TIMEOUT;
3390 case 425: /* Cannot open data connection. */
3391 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3394 case 426: /* Connection closed, transer aborted. */
3395 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3398 case 500: /* Syntax error. Command unrecognized. */
3399 case 501: /* Syntax error. Error in parameters or arguments. */
3400 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3403 case 530: /* Not logged in. Login incorrect. */
3404 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3407 case 550: /* File action not taken. File not found or no access. */
3408 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3411 case 450: /* File action not taken. File may be busy. */
3412 case 451: /* Action aborted. Server error. */
3413 case 452: /* Action not taken. Insufficient storage space on server. */
3414 case 502: /* Command not implemented. */
3415 case 503: /* Bad sequence of commands. */
3416 case 504: /* Command not implemented for that parameter. */
3417 case 532: /* Need account for storing files */
3418 case 551: /* Requested action aborted. Page type unknown */
3419 case 552: /* Action aborted. Exceeded storage allocation */
3420 case 553: /* Action not taken. File name not allowed. */
3423 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3427 INTERNET_SetLastError(dwCode);