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.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);
1348 if (lpwfs->lstnSocket != -1)
1349 closesocket(lpwfs->lstnSocket);
1353 hIC = lpwfs->lpAppInfo;
1354 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1356 INTERNET_ASYNC_RESULT iar;
1358 iar.dwResult = (DWORD)bSuccess;
1359 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1360 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1361 &iar, sizeof(INTERNET_ASYNC_RESULT));
1367 /***********************************************************************
1368 * FtpGetFileSize (WININET.@)
1370 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1372 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1374 if (lpdwFileSizeHigh)
1375 *lpdwFileSizeHigh = 0;
1380 /***********************************************************************
1381 * FtpDeleteFileA (WININET.@)
1383 * Delete a file on the ftp server
1390 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1392 LPWSTR lpwzFileName;
1395 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1396 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1397 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1401 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1403 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1404 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1406 TRACE("%p\n", lpwfs);
1408 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1409 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1412 /***********************************************************************
1413 * FtpDeleteFileW (WININET.@)
1415 * Delete a file on the ftp server
1422 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1424 LPWININETFTPSESSIONW lpwfs;
1425 LPWININETAPPINFOW hIC = NULL;
1428 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1431 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1435 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1437 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1443 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1447 hIC = lpwfs->lpAppInfo;
1448 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1450 WORKREQUEST workRequest;
1451 struct WORKREQ_FTPDELETEFILEW *req;
1453 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1454 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1455 req = &workRequest.u.FtpDeleteFileW;
1456 req->lpszFilename = WININET_strdupW(lpszFileName);
1458 r = INTERNET_AsyncCall(&workRequest);
1462 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1466 WININET_Release( &lpwfs->hdr );
1471 /***********************************************************************
1472 * FTP_FtpDeleteFileW (Internal)
1474 * Delete a file on the ftp server
1481 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1484 BOOL bSuccess = FALSE;
1485 LPWININETAPPINFOW hIC = NULL;
1487 TRACE("%p\n", lpwfs);
1489 /* Clear any error information */
1490 INTERNET_SetLastError(0);
1492 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1495 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1498 if (nResCode == 250)
1501 FTP_SetResponseError(nResCode);
1504 hIC = lpwfs->lpAppInfo;
1505 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1507 INTERNET_ASYNC_RESULT iar;
1509 iar.dwResult = (DWORD)bSuccess;
1510 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1511 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1512 &iar, sizeof(INTERNET_ASYNC_RESULT));
1519 /***********************************************************************
1520 * FtpRemoveDirectoryA (WININET.@)
1522 * Remove a directory on the ftp server
1529 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1531 LPWSTR lpwzDirectory;
1534 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1535 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1536 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1540 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1542 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1543 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1545 TRACE("%p\n", lpwfs);
1547 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1548 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1551 /***********************************************************************
1552 * FtpRemoveDirectoryW (WININET.@)
1554 * Remove a directory on the ftp server
1561 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1563 LPWININETFTPSESSIONW lpwfs;
1564 LPWININETAPPINFOW hIC = NULL;
1567 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1570 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1574 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1576 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1582 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1586 hIC = lpwfs->lpAppInfo;
1587 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1589 WORKREQUEST workRequest;
1590 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1592 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1593 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1594 req = &workRequest.u.FtpRemoveDirectoryW;
1595 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1597 r = INTERNET_AsyncCall(&workRequest);
1601 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1605 WININET_Release( &lpwfs->hdr );
1610 /***********************************************************************
1611 * FTP_FtpRemoveDirectoryW (Internal)
1613 * Remove a directory on the ftp server
1620 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1623 BOOL bSuccess = FALSE;
1624 LPWININETAPPINFOW hIC = NULL;
1628 /* Clear any error information */
1629 INTERNET_SetLastError(0);
1631 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1634 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1637 if (nResCode == 250)
1640 FTP_SetResponseError(nResCode);
1644 hIC = lpwfs->lpAppInfo;
1645 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1647 INTERNET_ASYNC_RESULT iar;
1649 iar.dwResult = (DWORD)bSuccess;
1650 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1651 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1652 &iar, sizeof(INTERNET_ASYNC_RESULT));
1659 /***********************************************************************
1660 * FtpRenameFileA (WININET.@)
1662 * Rename a file on the ftp server
1669 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1675 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1676 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1677 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1678 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1679 HeapFree(GetProcessHeap(), 0, lpwzDest);
1683 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1685 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1686 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1688 TRACE("%p\n", lpwfs);
1690 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1691 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1692 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1695 /***********************************************************************
1696 * FtpRenameFileW (WININET.@)
1698 * Rename a file on the ftp server
1705 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1707 LPWININETFTPSESSIONW lpwfs;
1708 LPWININETAPPINFOW hIC = NULL;
1711 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1714 INTERNET_SetLastError(ERROR_INVALID_HANDLE);
1718 if (WH_HFTPSESSION != lpwfs->hdr.htype)
1720 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1724 if (!lpszSrc || !lpszDest)
1726 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1730 hIC = lpwfs->lpAppInfo;
1731 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1733 WORKREQUEST workRequest;
1734 struct WORKREQ_FTPRENAMEFILEW *req;
1736 workRequest.asyncproc = AsyncFtpRenameFileProc;
1737 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1738 req = &workRequest.u.FtpRenameFileW;
1739 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1740 req->lpszDestFile = WININET_strdupW(lpszDest);
1742 r = INTERNET_AsyncCall(&workRequest);
1746 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1750 WININET_Release( &lpwfs->hdr );
1755 /***********************************************************************
1756 * FTP_FtpRenameFileW (Internal)
1758 * Rename a file on the ftp server
1765 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1766 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1769 BOOL bSuccess = FALSE;
1770 LPWININETAPPINFOW hIC = NULL;
1774 /* Clear any error information */
1775 INTERNET_SetLastError(0);
1777 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1780 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1781 if (nResCode == 350)
1783 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1786 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1789 if (nResCode == 250)
1792 FTP_SetResponseError(nResCode);
1795 hIC = lpwfs->lpAppInfo;
1796 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1798 INTERNET_ASYNC_RESULT iar;
1800 iar.dwResult = (DWORD)bSuccess;
1801 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1802 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1803 &iar, sizeof(INTERNET_ASYNC_RESULT));
1809 /***********************************************************************
1810 * FtpCommandA (WININET.@)
1812 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1813 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1815 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1816 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1821 /***********************************************************************
1822 * FtpCommandW (WININET.@)
1824 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1825 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1827 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1828 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1833 /***********************************************************************
1834 * FTP_Connect (internal)
1836 * Connect to a ftp server
1839 * HINTERNET a session handle on success
1844 * Windows uses 'anonymous' as the username, when given a NULL username
1845 * and a NULL password. The password is first looked up in:
1847 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1849 * If this entry is not present it uses the current username as the password.
1853 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1854 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1855 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1856 DWORD dwInternalFlags)
1858 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1859 'M','i','c','r','o','s','o','f','t','\\',
1860 'W','i','n','d','o','w','s','\\',
1861 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1862 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1863 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1864 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1865 static const WCHAR szEmpty[] = {'\0'};
1866 struct sockaddr_in socketAddr;
1869 BOOL bSuccess = FALSE;
1870 LPWININETFTPSESSIONW lpwfs = NULL;
1871 HINTERNET handle = NULL;
1873 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1874 hIC, debugstr_w(lpszServerName),
1875 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1877 assert( hIC->hdr.htype == WH_HINIT );
1879 if (NULL == lpszUserName && NULL != lpszPassword)
1881 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1885 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1888 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1892 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1893 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1895 lpwfs->hdr.htype = WH_HFTPSESSION;
1896 lpwfs->hdr.dwFlags = dwFlags;
1897 lpwfs->hdr.dwContext = dwContext;
1898 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1899 lpwfs->hdr.dwRefCount = 1;
1900 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1901 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1902 lpwfs->download_in_progress = NULL;
1904 WININET_AddRef( &hIC->hdr );
1905 lpwfs->lpAppInfo = hIC;
1907 handle = WININET_AllocHandle( &lpwfs->hdr );
1910 ERR("Failed to alloc handle\n");
1911 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1915 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1916 if(strchrW(hIC->lpszProxy, ' '))
1917 FIXME("Several proxies not implemented.\n");
1918 if(hIC->lpszProxyBypass)
1919 FIXME("Proxy bypass is ignored.\n");
1921 if ( !lpszUserName) {
1923 WCHAR szPassword[MAX_PATH];
1924 DWORD len = sizeof(szPassword);
1926 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1928 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1929 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1930 /* Nothing in the registry, get the username and use that as the password */
1931 if (!GetUserNameW(szPassword, &len)) {
1932 /* Should never get here, but use an empty password as failsafe */
1933 strcpyW(szPassword, szEmpty);
1938 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1939 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1942 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1945 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1947 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1950 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1951 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1953 INTERNET_ASYNC_RESULT iar;
1955 iar.dwResult = (DWORD)handle;
1956 iar.dwError = ERROR_SUCCESS;
1958 SendAsyncCallback(&hIC->hdr, dwContext,
1959 INTERNET_STATUS_HANDLE_CREATED, &iar,
1960 sizeof(INTERNET_ASYNC_RESULT));
1963 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1964 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1966 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1968 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1972 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1973 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1975 nsocket = socket(AF_INET,SOCK_STREAM,0);
1978 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1982 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1983 &socketAddr, sizeof(struct sockaddr_in));
1985 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1987 ERR("Unable to connect (%s)\n", strerror(errno));
1988 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1992 TRACE("Connected to server\n");
1993 lpwfs->sndSocket = nsocket;
1994 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1995 &socketAddr, sizeof(struct sockaddr_in));
1997 sock_namelen = sizeof(lpwfs->socketAddress);
1998 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
2000 if (FTP_ConnectToHost(lpwfs))
2002 TRACE("Successfully logged into server\n");
2008 if (!bSuccess && nsocket != -1)
2009 closesocket(nsocket);
2011 if (!bSuccess && lpwfs)
2013 HeapFree(GetProcessHeap(), 0, lpwfs);
2014 WININET_FreeHandle( handle );
2019 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2021 INTERNET_ASYNC_RESULT iar;
2023 iar.dwResult = (DWORD)lpwfs;
2024 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
2025 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
2026 &iar, sizeof(INTERNET_ASYNC_RESULT));
2033 /***********************************************************************
2034 * FTP_ConnectToHost (internal)
2036 * Connect to a ftp server
2043 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
2046 BOOL bSuccess = FALSE;
2049 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2051 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
2054 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2057 /* Login successful... */
2058 if (nResCode == 230)
2060 /* User name okay, need password... */
2061 else if (nResCode == 331)
2062 bSuccess = FTP_SendPassword(lpwfs);
2063 /* Need account for login... */
2064 else if (nResCode == 332)
2065 bSuccess = FTP_SendAccount(lpwfs);
2067 FTP_SetResponseError(nResCode);
2070 TRACE("Returning %d\n", bSuccess);
2076 /***********************************************************************
2077 * FTP_SendCommandA (internal)
2079 * Send command to server
2086 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2087 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2091 DWORD nBytesSent = 0;
2095 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2099 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2102 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2103 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2104 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2106 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2109 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2110 dwParamLen ? lpszParam : "", szCRLF);
2112 TRACE("Sending (%s) len(%d)\n", buf, len);
2113 while((nBytesSent < len) && (nRC != -1))
2115 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2119 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2123 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2124 &nBytesSent, sizeof(DWORD));
2127 TRACE("Sent %d bytes\n", nBytesSent);
2131 /***********************************************************************
2132 * FTP_SendCommand (internal)
2134 * Send command to server
2141 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2142 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2145 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2146 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2147 HeapFree(GetProcessHeap(), 0, lpszParamA);
2151 /***********************************************************************
2152 * FTP_ReceiveResponse (internal)
2154 * Receive response from server
2157 * Reply code on success
2161 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2163 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2166 char firstprefix[5];
2167 BOOL multiline = FALSE;
2168 LPWININETAPPINFOW hIC = NULL;
2170 TRACE("socket(%d)\n", lpwfs->sndSocket);
2172 hIC = lpwfs->lpAppInfo;
2173 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2177 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2184 if(lpszResponse[3] != '-')
2187 { /* Start of multiline repsonse. Loop until we get "nnn " */
2189 memcpy(firstprefix, lpszResponse, 3);
2190 firstprefix[3] = ' ';
2191 firstprefix[4] = '\0';
2196 if(!memcmp(firstprefix, lpszResponse, 4))
2204 rc = atoi(lpszResponse);
2206 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2207 &nRecv, sizeof(DWORD));
2211 TRACE("return %d\n", rc);
2216 /***********************************************************************
2217 * FTP_SendPassword (internal)
2219 * Send password to ftp server
2226 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2229 BOOL bSuccess = FALSE;
2232 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2235 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2238 TRACE("Received reply code %d\n", nResCode);
2239 /* Login successful... */
2240 if (nResCode == 230)
2242 /* Command not implemented, superfluous at the server site... */
2243 /* Need account for login... */
2244 else if (nResCode == 332)
2245 bSuccess = FTP_SendAccount(lpwfs);
2247 FTP_SetResponseError(nResCode);
2251 TRACE("Returning %d\n", bSuccess);
2256 /***********************************************************************
2257 * FTP_SendAccount (internal)
2266 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2269 BOOL bSuccess = FALSE;
2272 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2275 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2279 FTP_SetResponseError(nResCode);
2286 /***********************************************************************
2287 * FTP_SendStore (internal)
2289 * Send request to upload file to ftp server
2296 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2299 BOOL bSuccess = FALSE;
2302 if (!FTP_InitListenSocket(lpwfs))
2305 if (!FTP_SendType(lpwfs, dwType))
2308 if (!FTP_SendPortOrPasv(lpwfs))
2311 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2313 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2316 if (nResCode == 150 || nResCode == 125)
2319 FTP_SetResponseError(nResCode);
2323 if (!bSuccess && lpwfs->lstnSocket != -1)
2325 closesocket(lpwfs->lstnSocket);
2326 lpwfs->lstnSocket = -1;
2333 /***********************************************************************
2334 * FTP_InitListenSocket (internal)
2336 * Create a socket to listen for server response
2343 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2345 BOOL bSuccess = FALSE;
2346 socklen_t namelen = sizeof(struct sockaddr_in);
2350 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2351 if (lpwfs->lstnSocket == -1)
2353 TRACE("Unable to create listening socket\n");
2357 /* We obtain our ip addr from the name of the command channel socket */
2358 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2360 /* and get the system to assign us a port */
2361 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2363 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2365 TRACE("Unable to bind socket\n");
2369 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2371 TRACE("listen failed\n");
2375 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2379 if (!bSuccess && lpwfs->lstnSocket != -1)
2381 closesocket(lpwfs->lstnSocket);
2382 lpwfs->lstnSocket = -1;
2389 /***********************************************************************
2390 * FTP_SendType (internal)
2392 * Tell server type of data being transferred
2398 * W98SE doesn't cache the type that's currently set
2399 * (i.e. it sends it always),
2400 * so we probably don't want to do that either.
2402 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2405 WCHAR type[] = { 'I','\0' };
2406 BOOL bSuccess = FALSE;
2409 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2412 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2415 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2421 FTP_SetResponseError(nResCode);
2428 /***********************************************************************
2429 * FTP_GetFileSize (internal)
2431 * Retrieves from the server the size of the given file
2438 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2441 BOOL bSuccess = FALSE;
2445 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2448 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2451 if (nResCode == 213) {
2452 /* Now parses the output to get the actual file size */
2454 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2456 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2457 if (lpszResponseBuffer[i] == '\0') return FALSE;
2458 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2462 FTP_SetResponseError(nResCode);
2471 /***********************************************************************
2472 * FTP_SendPort (internal)
2474 * Tell server which port to use
2481 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2483 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2485 WCHAR szIPAddress[64];
2486 BOOL bSuccess = FALSE;
2489 sprintfW(szIPAddress, szIPFormat,
2490 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2491 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2492 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2493 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2494 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2495 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2497 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2500 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2503 if (nResCode == 200)
2506 FTP_SetResponseError(nResCode);
2514 /***********************************************************************
2515 * FTP_DoPassive (internal)
2517 * Tell server that we want to do passive transfers
2518 * and connect data socket
2525 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2528 BOOL bSuccess = FALSE;
2531 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2534 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2537 if (nResCode == 227)
2539 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2543 char *pAddr, *pPort;
2545 struct sockaddr_in dataSocketAddress;
2547 p = lpszResponseBuffer+4; /* skip status code */
2548 while (*p != '\0' && (*p < '0' || *p > '9')) p++;
2552 ERR("no address found in response, aborting\n");
2556 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2559 ERR("unknown response address format '%s', aborting\n", p);
2562 for (i=0; i < 6; i++)
2565 dataSocketAddress = lpwfs->socketAddress;
2566 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2567 pPort = (char *)&(dataSocketAddress.sin_port);
2575 nsocket = socket(AF_INET,SOCK_STREAM,0);
2579 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2581 ERR("can't connect passive FTP data port.\n");
2582 closesocket(nsocket);
2585 lpwfs->pasvSocket = nsocket;
2589 FTP_SetResponseError(nResCode);
2597 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2599 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2601 if (!FTP_DoPassive(lpwfs))
2606 if (!FTP_SendPort(lpwfs))
2613 /***********************************************************************
2614 * FTP_GetDataSocket (internal)
2616 * Either accepts an incoming data socket connection from the server
2617 * or just returns the already opened socket after a PASV command
2618 * in case of passive FTP.
2626 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2628 struct sockaddr_in saddr;
2629 socklen_t addrlen = sizeof(struct sockaddr);
2632 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2634 *nDataSocket = lpwfs->pasvSocket;
2638 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2639 closesocket(lpwfs->lstnSocket);
2640 lpwfs->lstnSocket = -1;
2642 return *nDataSocket != -1;
2646 /***********************************************************************
2647 * FTP_SendData (internal)
2649 * Send data to the server
2656 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2658 BY_HANDLE_FILE_INFORMATION fi;
2659 DWORD nBytesRead = 0;
2660 DWORD nBytesSent = 0;
2661 DWORD nTotalSent = 0;
2662 DWORD nBytesToSend, nLen;
2664 time_t s_long_time, e_long_time;
2669 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2671 /* Get the size of the file. */
2672 GetFileInformationByHandle(hFile, &fi);
2677 nBytesToSend = nBytesRead - nBytesSent;
2679 if (nBytesToSend <= 0)
2681 /* Read data from file. */
2683 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2684 ERR("Failed reading from file\n");
2687 nBytesToSend = nBytesRead;
2692 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2693 DATA_PACKET_SIZE : nBytesToSend;
2694 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2702 /* Do some computation to display the status. */
2704 nSeconds = e_long_time - s_long_time;
2705 if( nSeconds / 60 > 0 )
2707 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2708 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2709 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2713 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2714 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2715 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2717 } while (nRC != -1);
2719 TRACE("file transfer complete!\n");
2721 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2727 /***********************************************************************
2728 * FTP_SendRetrieve (internal)
2730 * Send request to retrieve a file
2733 * Number of bytes to be received on success
2737 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2743 if (!FTP_InitListenSocket(lpwfs))
2746 if (!FTP_SendType(lpwfs, dwType))
2749 if (!FTP_SendPortOrPasv(lpwfs))
2752 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2755 TRACE("Waiting to receive %d bytes\n", nResult);
2757 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2760 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2761 if ((nResCode != 125) && (nResCode != 150)) {
2762 /* That means that we got an error getting the file. */
2767 if (0 == nResult && lpwfs->lstnSocket != -1)
2769 closesocket(lpwfs->lstnSocket);
2770 lpwfs->lstnSocket = -1;
2777 /***********************************************************************
2778 * FTP_RetrieveData (internal)
2780 * Retrieve data from server
2787 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2789 DWORD nBytesWritten;
2790 DWORD nBytesReceived = 0;
2796 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2797 if (NULL == lpszBuffer)
2799 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2803 while (nBytesReceived < nBytes && nRC != -1)
2805 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2808 /* other side closed socket. */
2811 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2812 nBytesReceived += nRC;
2815 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2816 nBytesReceived * 100 / nBytes);
2819 TRACE("Data transfer complete\n");
2822 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2828 /***********************************************************************
2829 * FTP_CloseSessionHandle (internal)
2831 * Deallocate session handle
2838 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2840 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2844 WININET_Release(&lpwfs->lpAppInfo->hdr);
2846 if (lpwfs->download_in_progress != NULL)
2847 lpwfs->download_in_progress->session_deleted = TRUE;
2849 if (lpwfs->sndSocket != -1)
2850 closesocket(lpwfs->sndSocket);
2852 if (lpwfs->lstnSocket != -1)
2853 closesocket(lpwfs->lstnSocket);
2855 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2856 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2857 HeapFree(GetProcessHeap(), 0, lpwfs);
2861 /***********************************************************************
2862 * FTP_FindNextFileW (Internal)
2864 * Continues a file search from a previous call to FindFirstFile
2871 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2873 BOOL bSuccess = TRUE;
2874 LPWIN32_FIND_DATAW lpFindFileData;
2876 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2878 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2880 /* Clear any error information */
2881 INTERNET_SetLastError(0);
2883 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2884 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2886 if (lpwh->index >= lpwh->size)
2888 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2893 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2896 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2900 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2902 INTERNET_ASYNC_RESULT iar;
2904 iar.dwResult = (DWORD)bSuccess;
2905 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2906 INTERNET_GetLastError();
2908 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2909 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2910 sizeof(INTERNET_ASYNC_RESULT));
2917 /***********************************************************************
2918 * FTP_CloseFindNextHandle (internal)
2920 * Deallocate session handle
2927 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2929 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2934 WININET_Release(&lpwfn->lpFtpSession->hdr);
2936 for (i = 0; i < lpwfn->size; i++)
2938 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2941 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2942 HeapFree(GetProcessHeap(), 0, lpwfn);
2945 /***********************************************************************
2946 * FTP_CloseFileTransferHandle (internal)
2948 * Closes the file transfer handle. This also 'cleans' the data queue of
2949 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2952 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2954 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2955 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2960 WININET_Release(&lpwh->lpFtpSession->hdr);
2962 if (!lpwh->session_deleted)
2963 lpwfs->download_in_progress = NULL;
2965 /* This just serves to flush the control socket of any spurrious lines written
2966 to it (like '226 Transfer complete.').
2968 Wonder what to do if the server sends us an error code though...
2970 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2972 if (lpwh->nDataSocket != -1)
2973 closesocket(lpwh->nDataSocket);
2975 HeapFree(GetProcessHeap(), 0, lpwh);
2978 /***********************************************************************
2979 * FTP_ReceiveFileList (internal)
2981 * Read file list from server
2984 * Handle to file list on success
2988 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2989 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2992 LPFILEPROPERTIESW lpafp = NULL;
2993 LPWININETFTPFINDNEXTW lpwfn = NULL;
2994 HINTERNET handle = 0;
2996 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2998 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
3001 FTP_ConvertFileProp(lpafp, lpFindFileData);
3003 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
3006 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
3007 lpwfn->hdr.dwContext = dwContext;
3008 lpwfn->hdr.dwRefCount = 1;
3009 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
3010 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
3011 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
3012 lpwfn->size = dwSize;
3013 lpwfn->lpafp = lpafp;
3015 WININET_AddRef( &lpwfs->hdr );
3016 lpwfn->lpFtpSession = lpwfs;
3018 handle = WININET_AllocHandle( &lpwfn->hdr );
3023 WININET_Release( &lpwfn->hdr );
3025 TRACE("Matched %d files\n", dwSize);
3030 /***********************************************************************
3031 * FTP_ConvertFileProp (internal)
3033 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3040 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
3042 BOOL bSuccess = FALSE;
3044 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
3048 /* Convert 'Unix' time to Windows time */
3049 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
3050 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
3051 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
3052 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
3054 /* Not all fields are filled in */
3055 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3056 lpFindFileData->nFileSizeLow = lpafp->nSize;
3058 if (lpafp->bIsDirectory)
3059 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
3061 if (lpafp->lpszName)
3062 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
3070 /***********************************************************************
3071 * FTP_ParseNextFile (internal)
3073 * Parse the next line in file listing
3079 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3081 static const char szSpace[] = " \t";
3089 lpfp->lpszName = NULL;
3091 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3094 pszToken = strtok(pszLine, szSpace);
3096 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3099 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3101 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3102 if(!FTP_ParsePermission(pszToken, lpfp))
3103 lpfp->bIsDirectory = FALSE;
3104 for(i=0; i<=3; i++) {
3105 if(!(pszToken = strtok(NULL, szSpace)))
3108 if(!pszToken) continue;
3109 if(lpfp->bIsDirectory) {
3110 TRACE("Is directory\n");
3114 TRACE("Size: %s\n", pszToken);
3115 lpfp->nSize = atol(pszToken);
3118 lpfp->tmLastModified.tm_sec = 0;
3119 lpfp->tmLastModified.tm_min = 0;
3120 lpfp->tmLastModified.tm_hour = 0;
3121 lpfp->tmLastModified.tm_mday = 0;
3122 lpfp->tmLastModified.tm_mon = 0;
3123 lpfp->tmLastModified.tm_year = 0;
3125 /* Determine month */
3126 pszToken = strtok(NULL, szSpace);
3127 if(!pszToken) continue;
3128 if(strlen(pszToken) >= 3) {
3130 if((pszTmp = StrStrIA(szMonths, pszToken)))
3131 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3134 pszToken = strtok(NULL, szSpace);
3135 if(!pszToken) continue;
3136 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3137 /* Determine time or year */
3138 pszToken = strtok(NULL, szSpace);
3139 if(!pszToken) continue;
3140 if((pszTmp = strchr(pszToken, ':'))) {
3145 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3146 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3148 apTM = localtime(&aTime);
3149 lpfp->tmLastModified.tm_year = apTM->tm_year;
3152 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3153 lpfp->tmLastModified.tm_hour = 12;
3155 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3156 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3157 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3158 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3160 pszToken = strtok(NULL, szSpace);
3161 if(!pszToken) continue;
3162 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3163 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3165 /* NT way of parsing ... :
3167 07-13-03 08:55PM <DIR> sakpatch
3168 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3170 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3171 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3173 sscanf(pszToken, "%d-%d-%d",
3174 &lpfp->tmLastModified.tm_mon,
3175 &lpfp->tmLastModified.tm_mday,
3176 &lpfp->tmLastModified.tm_year);
3178 /* Hacky and bad Y2K protection :-) */
3179 if (lpfp->tmLastModified.tm_year < 70)
3180 lpfp->tmLastModified.tm_year += 100;
3182 pszToken = strtok(NULL, szSpace);
3183 if(!pszToken) continue;
3184 sscanf(pszToken, "%d:%d",
3185 &lpfp->tmLastModified.tm_hour,
3186 &lpfp->tmLastModified.tm_min);
3187 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3188 lpfp->tmLastModified.tm_hour += 12;
3190 lpfp->tmLastModified.tm_sec = 0;
3192 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3193 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3194 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3195 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3197 pszToken = strtok(NULL, szSpace);
3198 if(!pszToken) continue;
3199 if(!strcasecmp(pszToken, "<DIR>")) {
3200 lpfp->bIsDirectory = TRUE;
3202 TRACE("Is directory\n");
3205 lpfp->bIsDirectory = FALSE;
3206 lpfp->nSize = atol(pszToken);
3207 TRACE("Size: %d\n", lpfp->nSize);
3210 pszToken = strtok(NULL, szSpace);
3211 if(!pszToken) continue;
3212 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3213 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3215 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3216 else if(pszToken[0] == '+') {
3217 FIXME("EPLF Format not implemented\n");
3220 if(lpfp->lpszName) {
3221 if((lpszSearchFile == NULL) ||
3222 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3224 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3227 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3228 lpfp->lpszName = NULL;
3235 /***********************************************************************
3236 * FTP_ParseDirectory (internal)
3238 * Parse string of directory information
3244 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3245 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3247 BOOL bSuccess = TRUE;
3248 INT sizeFilePropArray = 500;/*20; */
3249 INT indexFilePropArray = -1;
3253 /* Allocate intial file properties array */
3254 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3259 if (indexFilePropArray+1 >= sizeFilePropArray)
3261 LPFILEPROPERTIESW tmpafp;
3263 sizeFilePropArray *= 2;
3264 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3265 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3274 indexFilePropArray++;
3275 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3277 if (bSuccess && indexFilePropArray)
3279 if (indexFilePropArray < sizeFilePropArray - 1)
3281 LPFILEPROPERTIESW tmpafp;
3283 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3284 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3288 *dwfp = indexFilePropArray;
3292 HeapFree(GetProcessHeap(), 0, *lpafp);
3293 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3301 /***********************************************************************
3302 * FTP_ParsePermission (internal)
3304 * Parse permission string of directory information
3311 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3313 BOOL bSuccess = TRUE;
3314 unsigned short nPermission = 0;
3319 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3325 lpfp->bIsDirectory = (*lpszPermission == 'd');
3331 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3334 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3337 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3340 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3343 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3346 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3349 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3352 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3355 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3359 }while (nPos <= nLast);
3361 lpfp->permissions = nPermission;
3366 /***********************************************************************
3367 * FTP_SetResponseError (internal)
3369 * Set the appropriate error code for a given response from the server
3374 static DWORD FTP_SetResponseError(DWORD dwResponse)
3380 case 421: /* Service not available - Server may be shutting down. */
3381 dwCode = ERROR_INTERNET_TIMEOUT;
3384 case 425: /* Cannot open data connection. */
3385 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3388 case 426: /* Connection closed, transer aborted. */
3389 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3392 case 500: /* Syntax error. Command unrecognized. */
3393 case 501: /* Syntax error. Error in parameters or arguments. */
3394 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3397 case 530: /* Not logged in. Login incorrect. */
3398 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3401 case 550: /* File action not taken. File not found or no access. */
3402 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3405 case 450: /* File action not taken. File may be busy. */
3406 case 451: /* Action aborted. Server error. */
3407 case 452: /* Action not taken. Insufficient storage space on server. */
3408 case 502: /* Command not implemented. */
3409 case 503: /* Bad sequence of commands. */
3410 case 504: /* Command not implemented for that parameter. */
3411 case 532: /* Need account for storing files */
3412 case 551: /* Requested action aborted. Page type unknown */
3413 case 552: /* Action aborted. Exceeded storage allocation */
3414 case 553: /* Action not taken. File name not allowed. */
3417 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3421 INTERNET_SetLastError(dwCode);