2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
11 * Copyright 2000 Andreas Mohr
12 * Copyright 2002 Jaco Greeff
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
58 #include "wine/debug.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
63 #define DATA_PACKET_SIZE 0x2000
68 /* FTP commands with arguments. */
84 /* FTP commands without arguments. */
93 static const CHAR *szFtpCommands[] = {
116 static const CHAR szMonths[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
117 static const WCHAR szNoAccount[] = {'n','o','a','c','c','o','u','n','t','\0'};
119 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr);
120 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr);
121 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr);
122 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext);
124 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
126 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
127 static INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
128 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
129 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
130 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
131 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
132 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
133 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
134 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
135 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
136 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
137 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
138 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
139 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
140 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
141 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
142 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
143 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
144 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
145 static DWORD FTP_SetResponseError(DWORD dwResponse);
147 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
157 BOOL WINAPI FtpPutFileA(HINTERNET hConnect, LPCSTR lpszLocalFile,
158 LPCSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
160 LPWSTR lpwzLocalFile;
161 LPWSTR lpwzNewRemoteFile;
164 lpwzLocalFile = lpszLocalFile?WININET_strdup_AtoW(lpszLocalFile):NULL;
165 lpwzNewRemoteFile = lpszNewRemoteFile?WININET_strdup_AtoW(lpszNewRemoteFile):NULL;
166 ret = FtpPutFileW(hConnect, lpwzLocalFile, lpwzNewRemoteFile,
168 HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
169 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile);
173 /***********************************************************************
174 * FtpPutFileW (WININET.@)
176 * Uploads a file to the FTP server
183 static void AsyncFtpPutFileProc(WORKREQUEST *workRequest)
185 struct WORKREQ_FTPPUTFILEW const *req = &workRequest->u.FtpPutFileW;
186 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
188 TRACE("%p\n", lpwfs);
190 FTP_FtpPutFileW(lpwfs, req->lpszLocalFile,
191 req->lpszNewRemoteFile, req->dwFlags, req->dwContext);
193 HeapFree(GetProcessHeap(), 0, req->lpszLocalFile);
194 HeapFree(GetProcessHeap(), 0, req->lpszNewRemoteFile);
197 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
198 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
200 LPWININETFTPSESSIONW lpwfs;
201 LPWININETAPPINFOW hIC = NULL;
204 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
205 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
207 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
211 hIC = lpwfs->lpAppInfo;
212 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
214 WORKREQUEST workRequest;
215 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
217 workRequest.asyncproc = AsyncFtpPutFileProc;
218 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
219 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
220 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
221 req->dwFlags = dwFlags;
222 req->dwContext = dwContext;
224 r = INTERNET_AsyncCall(&workRequest);
228 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
229 lpszNewRemoteFile, dwFlags, dwContext);
234 WININET_Release( &lpwfs->hdr );
239 /***********************************************************************
240 * FTP_FtpPutFileW (Internal)
242 * Uploads a file to the FTP server
249 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
250 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
253 BOOL bSuccess = FALSE;
254 LPWININETAPPINFOW hIC = NULL;
257 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
259 if (!lpszLocalFile || !lpszNewRemoteFile)
261 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
265 /* Clear any error information */
266 INTERNET_SetLastError(0);
267 hIC = lpwfs->lpAppInfo;
269 /* Open file to be uploaded */
270 if (INVALID_HANDLE_VALUE ==
271 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
273 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
277 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
279 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
283 /* Get data socket to server */
284 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
286 FTP_SendData(lpwfs, nDataSocket, hFile);
287 closesocket(nDataSocket);
288 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
294 FTP_SetResponseError(nResCode);
300 if (lpwfs->lstnSocket != -1)
301 closesocket(lpwfs->lstnSocket);
303 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
305 INTERNET_ASYNC_RESULT iar;
307 iar.dwResult = (DWORD)bSuccess;
308 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
309 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
310 &iar, sizeof(INTERNET_ASYNC_RESULT));
320 /***********************************************************************
321 * FtpSetCurrentDirectoryA (WININET.@)
323 * Change the working directory on the FTP server
330 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
332 LPWSTR lpwzDirectory;
335 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
336 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
337 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
342 /***********************************************************************
343 * FtpSetCurrentDirectoryW (WININET.@)
345 * Change the working directory on the FTP server
352 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST *workRequest)
354 struct WORKREQ_FTPSETCURRENTDIRECTORYW const *req = &workRequest->u.FtpSetCurrentDirectoryW;
355 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
357 TRACE("%p\n", lpwfs);
359 FTP_FtpSetCurrentDirectoryW(lpwfs, req->lpszDirectory);
360 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
363 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
365 LPWININETFTPSESSIONW lpwfs = NULL;
366 LPWININETAPPINFOW hIC = NULL;
371 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
375 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
376 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
378 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
382 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
384 hIC = lpwfs->lpAppInfo;
385 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
387 WORKREQUEST workRequest;
388 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
390 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
391 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
392 req = &workRequest.u.FtpSetCurrentDirectoryW;
393 req->lpszDirectory = WININET_strdupW(lpszDirectory);
395 r = INTERNET_AsyncCall(&workRequest);
399 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
404 WININET_Release( &lpwfs->hdr );
410 /***********************************************************************
411 * FTP_FtpSetCurrentDirectoryW (Internal)
413 * Change the working directory on the FTP server
420 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
423 LPWININETAPPINFOW hIC = NULL;
424 DWORD bSuccess = FALSE;
426 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
428 /* Clear any error information */
429 INTERNET_SetLastError(0);
431 hIC = lpwfs->lpAppInfo;
432 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
433 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
436 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
443 FTP_SetResponseError(nResCode);
447 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
449 INTERNET_ASYNC_RESULT iar;
451 iar.dwResult = (DWORD)bSuccess;
452 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
453 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
454 &iar, sizeof(INTERNET_ASYNC_RESULT));
460 /***********************************************************************
461 * FtpCreateDirectoryA (WININET.@)
463 * Create new directory on the FTP server
470 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
472 LPWSTR lpwzDirectory;
475 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
476 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
477 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
482 /***********************************************************************
483 * FtpCreateDirectoryW (WININET.@)
485 * Create new directory on the FTP server
492 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
494 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
495 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
497 TRACE(" %p\n", lpwfs);
499 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
500 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
503 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
505 LPWININETFTPSESSIONW lpwfs;
506 LPWININETAPPINFOW hIC = NULL;
509 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
510 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
512 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
516 hIC = lpwfs->lpAppInfo;
517 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
519 WORKREQUEST workRequest;
520 struct WORKREQ_FTPCREATEDIRECTORYW *req;
522 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
523 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
524 req = &workRequest.u.FtpCreateDirectoryW;
525 req->lpszDirectory = WININET_strdupW(lpszDirectory);
527 r = INTERNET_AsyncCall(&workRequest);
531 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
535 WININET_Release( &lpwfs->hdr );
541 /***********************************************************************
542 * FTP_FtpCreateDirectoryW (Internal)
544 * Create new directory on the FTP server
551 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
554 BOOL bSuccess = FALSE;
555 LPWININETAPPINFOW hIC = NULL;
557 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
559 /* Clear any error information */
560 INTERNET_SetLastError(0);
562 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
565 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
571 FTP_SetResponseError(nResCode);
575 hIC = lpwfs->lpAppInfo;
576 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
578 INTERNET_ASYNC_RESULT iar;
580 iar.dwResult = (DWORD)bSuccess;
581 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
582 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
583 &iar, sizeof(INTERNET_ASYNC_RESULT));
589 /***********************************************************************
590 * FtpFindFirstFileA (WININET.@)
592 * Search the specified directory
595 * HINTERNET on success
599 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
600 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
602 LPWSTR lpwzSearchFile;
603 WIN32_FIND_DATAW wfd;
604 LPWIN32_FIND_DATAW lpFindFileDataW;
607 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
608 lpFindFileDataW = lpFindFileData?&wfd:NULL;
609 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
610 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
613 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
619 /***********************************************************************
620 * FtpFindFirstFileW (WININET.@)
622 * Search the specified directory
625 * HINTERNET on success
629 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
631 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
632 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
634 TRACE("%p\n", lpwfs);
636 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
637 req->lpFindFileData, req->dwFlags, req->dwContext);
638 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
641 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
642 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
644 LPWININETFTPSESSIONW lpwfs;
645 LPWININETAPPINFOW hIC = NULL;
648 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
649 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
651 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
655 hIC = lpwfs->lpAppInfo;
656 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
658 WORKREQUEST workRequest;
659 struct WORKREQ_FTPFINDFIRSTFILEW *req;
661 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
662 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
663 req = &workRequest.u.FtpFindFirstFileW;
664 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
665 req->lpFindFileData = lpFindFileData;
666 req->dwFlags = dwFlags;
667 req->dwContext= dwContext;
669 INTERNET_AsyncCall(&workRequest);
674 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
679 WININET_Release( &lpwfs->hdr );
685 /***********************************************************************
686 * FTP_FtpFindFirstFileW (Internal)
688 * Search the specified directory
691 * HINTERNET on success
695 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
696 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
699 LPWININETAPPINFOW hIC = NULL;
700 HINTERNET hFindNext = NULL;
704 /* Clear any error information */
705 INTERNET_SetLastError(0);
707 if (!FTP_InitListenSocket(lpwfs))
710 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
713 if (!FTP_SendPortOrPasv(lpwfs))
716 hIC = lpwfs->lpAppInfo;
717 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
718 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
721 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
724 if (nResCode == 125 || nResCode == 150)
728 /* Get data socket to server */
729 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
731 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
732 closesocket(nDataSocket);
733 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
734 if (nResCode != 226 && nResCode != 250)
735 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
739 FTP_SetResponseError(nResCode);
743 if (lpwfs->lstnSocket != -1)
744 closesocket(lpwfs->lstnSocket);
746 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
748 INTERNET_ASYNC_RESULT iar;
752 iar.dwResult = (DWORD)hFindNext;
753 iar.dwError = ERROR_SUCCESS;
754 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
755 &iar, sizeof(INTERNET_ASYNC_RESULT));
758 iar.dwResult = (DWORD)hFindNext;
759 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
760 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
761 &iar, sizeof(INTERNET_ASYNC_RESULT));
768 /***********************************************************************
769 * FtpGetCurrentDirectoryA (WININET.@)
771 * Retrieves the current directory
778 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
779 LPDWORD lpdwCurrentDirectory)
785 if(lpdwCurrentDirectory) {
786 len = *lpdwCurrentDirectory;
787 if(lpszCurrentDirectory)
789 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
792 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
797 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
798 if(lpdwCurrentDirectory) {
799 *lpdwCurrentDirectory = len;
800 if(lpszCurrentDirectory) {
801 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
802 HeapFree(GetProcessHeap(), 0, dir);
809 /***********************************************************************
810 * FtpGetCurrentDirectoryW (WININET.@)
812 * Retrieves the current directory
819 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST *workRequest)
821 struct WORKREQ_FTPGETCURRENTDIRECTORYW const *req = &workRequest->u.FtpGetCurrentDirectoryW;
822 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
824 TRACE("%p\n", lpwfs);
826 FTP_FtpGetCurrentDirectoryW(lpwfs, req->lpszDirectory, req->lpdwDirectory);
829 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
830 LPDWORD lpdwCurrentDirectory)
832 LPWININETFTPSESSIONW lpwfs;
833 LPWININETAPPINFOW hIC = NULL;
836 TRACE("len(%d)\n", *lpdwCurrentDirectory);
838 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
839 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
841 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
845 hIC = lpwfs->lpAppInfo;
846 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
848 WORKREQUEST workRequest;
849 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
851 workRequest.asyncproc = AsyncFtpGetCurrentDirectoryProc;
852 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
853 req = &workRequest.u.FtpGetCurrentDirectoryW;
854 req->lpszDirectory = lpszCurrentDirectory;
855 req->lpdwDirectory = lpdwCurrentDirectory;
857 r = INTERNET_AsyncCall(&workRequest);
861 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
862 lpdwCurrentDirectory);
867 WININET_Release( &lpwfs->hdr );
873 /***********************************************************************
874 * FTP_FtpGetCurrentDirectoryW (Internal)
876 * Retrieves the current directory
883 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
884 LPDWORD lpdwCurrentDirectory)
887 LPWININETAPPINFOW hIC = NULL;
888 DWORD bSuccess = FALSE;
890 TRACE("len(%d)\n", *lpdwCurrentDirectory);
892 /* Clear any error information */
893 INTERNET_SetLastError(0);
895 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
897 hIC = lpwfs->lpAppInfo;
898 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
899 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
902 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
905 if (nResCode == 257) /* Extract directory name */
907 DWORD firstpos, lastpos, len;
908 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
910 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
912 if ('"' == lpszResponseBuffer[lastpos])
921 len = lastpos - firstpos - 1;
922 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
923 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
924 *lpdwCurrentDirectory = len;
928 FTP_SetResponseError(nResCode);
932 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
934 INTERNET_ASYNC_RESULT iar;
936 iar.dwResult = (DWORD)bSuccess;
937 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
938 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
939 &iar, sizeof(INTERNET_ASYNC_RESULT));
942 return (DWORD) bSuccess;
945 /***********************************************************************
946 * FtpOpenFileA (WININET.@)
948 * Open a remote file for writing or reading
951 * HINTERNET handle on success
955 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
956 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
962 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
963 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
964 HeapFree(GetProcessHeap(), 0, lpwzFileName);
969 /***********************************************************************
970 * FtpOpenFileW (WININET.@)
972 * Open a remote file for writing or reading
975 * HINTERNET handle on success
979 static void AsyncFtpOpenFileProc(WORKREQUEST *workRequest)
981 struct WORKREQ_FTPOPENFILEW const *req = &workRequest->u.FtpOpenFileW;
982 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
984 TRACE("%p\n", lpwfs);
986 FTP_FtpOpenFileW(lpwfs, req->lpszFilename,
987 req->dwAccess, req->dwFlags, req->dwContext);
988 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
991 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
992 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
995 LPWININETFTPSESSIONW lpwfs;
996 LPWININETAPPINFOW hIC = NULL;
999 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession,
1000 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1002 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1003 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1005 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1009 if (lpwfs->download_in_progress != NULL) {
1010 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1013 hIC = lpwfs->lpAppInfo;
1014 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1016 WORKREQUEST workRequest;
1017 struct WORKREQ_FTPOPENFILEW *req;
1019 workRequest.asyncproc = AsyncFtpOpenFileProc;
1020 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1021 req = &workRequest.u.FtpOpenFileW;
1022 req->lpszFilename = WININET_strdupW(lpszFileName);
1023 req->dwAccess = fdwAccess;
1024 req->dwFlags = dwFlags;
1025 req->dwContext = dwContext;
1027 INTERNET_AsyncCall(&workRequest);
1032 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1037 WININET_Release( &lpwfs->hdr );
1043 /***********************************************************************
1044 * FTP_FtpOpenFileW (Internal)
1046 * Open a remote file for writing or reading
1049 * HINTERNET handle on success
1053 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1054 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1058 BOOL bSuccess = FALSE;
1059 LPWININETFTPFILE lpwh = NULL;
1060 LPWININETAPPINFOW hIC = NULL;
1061 HINTERNET handle = NULL;
1065 /* Clear any error information */
1066 INTERNET_SetLastError(0);
1068 if (GENERIC_READ == fdwAccess)
1070 /* Set up socket to retrieve data */
1071 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1073 else if (GENERIC_WRITE == fdwAccess)
1075 /* Set up socket to send data */
1076 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1079 /* Get data socket to server */
1080 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1082 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1083 lpwh->hdr.htype = WH_HFILE;
1084 lpwh->hdr.dwFlags = dwFlags;
1085 lpwh->hdr.dwContext = dwContext;
1086 lpwh->hdr.dwRefCount = 1;
1087 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1088 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1089 lpwh->nDataSocket = nDataSocket;
1090 lpwh->session_deleted = FALSE;
1092 WININET_AddRef( &lpwfs->hdr );
1093 lpwh->lpFtpSession = lpwfs;
1095 handle = WININET_AllocHandle( &lpwh->hdr );
1099 /* Indicate that a download is currently in progress */
1100 lpwfs->download_in_progress = lpwh;
1103 if (lpwfs->lstnSocket != -1)
1104 closesocket(lpwfs->lstnSocket);
1106 hIC = lpwfs->lpAppInfo;
1107 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1109 INTERNET_ASYNC_RESULT iar;
1113 iar.dwResult = (DWORD)handle;
1114 iar.dwError = ERROR_SUCCESS;
1115 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1116 &iar, sizeof(INTERNET_ASYNC_RESULT));
1119 iar.dwResult = (DWORD)bSuccess;
1120 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1121 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1122 &iar, sizeof(INTERNET_ASYNC_RESULT));
1127 WININET_Release( &lpwh->hdr );
1133 /***********************************************************************
1134 * FtpGetFileA (WININET.@)
1136 * Retrieve file from the FTP server
1143 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1144 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1147 LPWSTR lpwzRemoteFile;
1151 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1152 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1153 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1154 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1155 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1156 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1161 /***********************************************************************
1162 * FtpGetFileW (WININET.@)
1164 * Retrieve file from the FTP server
1171 static void AsyncFtpGetFileProc(WORKREQUEST *workRequest)
1173 struct WORKREQ_FTPGETFILEW const *req = &workRequest->u.FtpGetFileW;
1174 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1176 TRACE("%p\n", lpwfs);
1178 FTP_FtpGetFileW(lpwfs, req->lpszRemoteFile,
1179 req->lpszNewFile, req->fFailIfExists,
1180 req->dwLocalFlagsAttribute, req->dwFlags, req->dwContext);
1181 HeapFree(GetProcessHeap(), 0, req->lpszRemoteFile);
1182 HeapFree(GetProcessHeap(), 0, req->lpszNewFile);
1185 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1186 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1189 LPWININETFTPSESSIONW lpwfs;
1190 LPWININETAPPINFOW hIC = NULL;
1193 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1194 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1196 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1200 if (lpwfs->download_in_progress != NULL) {
1201 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1205 hIC = lpwfs->lpAppInfo;
1206 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1208 WORKREQUEST workRequest;
1209 struct WORKREQ_FTPGETFILEW *req;
1211 workRequest.asyncproc = AsyncFtpGetFileProc;
1212 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1213 req = &workRequest.u.FtpGetFileW;
1214 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1215 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1216 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1217 req->fFailIfExists = fFailIfExists;
1218 req->dwFlags = dwInternetFlags;
1219 req->dwContext = dwContext;
1221 r = INTERNET_AsyncCall(&workRequest);
1225 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1226 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1231 WININET_Release( &lpwfs->hdr );
1237 /***********************************************************************
1238 * FTP_FtpGetFileW (Internal)
1240 * Retrieve file from the FTP server
1247 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1248 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1252 BOOL bSuccess = FALSE;
1254 LPWININETAPPINFOW hIC = NULL;
1256 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1258 /* Clear any error information */
1259 INTERNET_SetLastError(0);
1261 /* Ensure we can write to lpszNewfile by opening it */
1262 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1263 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1264 if (INVALID_HANDLE_VALUE == hFile)
1267 /* Set up socket to retrieve data */
1268 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1274 /* Get data socket to server */
1275 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1280 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1281 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1284 if (nResCode == 226)
1287 FTP_SetResponseError(nResCode);
1289 closesocket(nDataSocket);
1294 if (lpwfs->lstnSocket != -1)
1295 closesocket(lpwfs->lstnSocket);
1300 hIC = lpwfs->lpAppInfo;
1301 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1303 INTERNET_ASYNC_RESULT iar;
1305 iar.dwResult = (DWORD)bSuccess;
1306 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1307 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1308 &iar, sizeof(INTERNET_ASYNC_RESULT));
1314 /***********************************************************************
1315 * FtpGetFileSize (WININET.@)
1317 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1319 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1321 if (lpdwFileSizeHigh)
1322 *lpdwFileSizeHigh = 0;
1327 /***********************************************************************
1328 * FtpDeleteFileA (WININET.@)
1330 * Delete a file on the ftp server
1337 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1339 LPWSTR lpwzFileName;
1342 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1343 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1344 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1348 /***********************************************************************
1349 * FtpDeleteFileW (WININET.@)
1351 * Delete a file on the ftp server
1358 static void AsyncFtpDeleteFileProc(WORKREQUEST *workRequest)
1360 struct WORKREQ_FTPDELETEFILEW const *req = &workRequest->u.FtpDeleteFileW;
1361 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1363 TRACE("%p\n", lpwfs);
1365 FTP_FtpDeleteFileW(lpwfs, req->lpszFilename);
1366 HeapFree(GetProcessHeap(), 0, req->lpszFilename);
1369 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1371 LPWININETFTPSESSIONW lpwfs;
1372 LPWININETAPPINFOW hIC = NULL;
1375 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1376 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1378 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1382 hIC = lpwfs->lpAppInfo;
1383 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1385 WORKREQUEST workRequest;
1386 struct WORKREQ_FTPDELETEFILEW *req;
1388 workRequest.asyncproc = AsyncFtpDeleteFileProc;
1389 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1390 req = &workRequest.u.FtpDeleteFileW;
1391 req->lpszFilename = WININET_strdupW(lpszFileName);
1393 r = INTERNET_AsyncCall(&workRequest);
1397 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1402 WININET_Release( &lpwfs->hdr );
1407 /***********************************************************************
1408 * FTP_FtpDeleteFileW (Internal)
1410 * Delete a file on the ftp server
1417 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1420 BOOL bSuccess = FALSE;
1421 LPWININETAPPINFOW hIC = NULL;
1423 TRACE("%p\n", lpwfs);
1425 /* Clear any error information */
1426 INTERNET_SetLastError(0);
1428 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1431 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1434 if (nResCode == 250)
1437 FTP_SetResponseError(nResCode);
1440 hIC = lpwfs->lpAppInfo;
1441 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1443 INTERNET_ASYNC_RESULT iar;
1445 iar.dwResult = (DWORD)bSuccess;
1446 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1447 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1448 &iar, sizeof(INTERNET_ASYNC_RESULT));
1455 /***********************************************************************
1456 * FtpRemoveDirectoryA (WININET.@)
1458 * Remove a directory on the ftp server
1465 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1467 LPWSTR lpwzDirectory;
1470 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1471 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1472 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1476 /***********************************************************************
1477 * FtpRemoveDirectoryW (WININET.@)
1479 * Remove a directory on the ftp server
1486 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST *workRequest)
1488 struct WORKREQ_FTPREMOVEDIRECTORYW const *req = &workRequest->u.FtpRemoveDirectoryW;
1489 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1491 TRACE("%p\n", lpwfs);
1493 FTP_FtpRemoveDirectoryW(lpwfs, req->lpszDirectory);
1494 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
1497 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1499 LPWININETFTPSESSIONW lpwfs;
1500 LPWININETAPPINFOW hIC = NULL;
1503 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1504 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1506 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1510 hIC = lpwfs->lpAppInfo;
1511 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1513 WORKREQUEST workRequest;
1514 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1516 workRequest.asyncproc = AsyncFtpRemoveDirectoryProc;
1517 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1518 req = &workRequest.u.FtpRemoveDirectoryW;
1519 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1521 r = INTERNET_AsyncCall(&workRequest);
1525 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1530 WININET_Release( &lpwfs->hdr );
1535 /***********************************************************************
1536 * FTP_FtpRemoveDirectoryW (Internal)
1538 * Remove a directory on the ftp server
1545 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1548 BOOL bSuccess = FALSE;
1549 LPWININETAPPINFOW hIC = NULL;
1553 /* Clear any error information */
1554 INTERNET_SetLastError(0);
1556 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1559 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1562 if (nResCode == 250)
1565 FTP_SetResponseError(nResCode);
1569 hIC = lpwfs->lpAppInfo;
1570 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1572 INTERNET_ASYNC_RESULT iar;
1574 iar.dwResult = (DWORD)bSuccess;
1575 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1576 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1577 &iar, sizeof(INTERNET_ASYNC_RESULT));
1584 /***********************************************************************
1585 * FtpRenameFileA (WININET.@)
1587 * Rename a file on the ftp server
1594 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1600 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1601 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1602 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1603 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1604 HeapFree(GetProcessHeap(), 0, lpwzDest);
1608 /***********************************************************************
1609 * FtpRenameFileW (WININET.@)
1611 * Rename a file on the ftp server
1618 static void AsyncFtpRenameFileProc(WORKREQUEST *workRequest)
1620 struct WORKREQ_FTPRENAMEFILEW const *req = &workRequest->u.FtpRenameFileW;
1621 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
1623 TRACE("%p\n", lpwfs);
1625 FTP_FtpRenameFileW(lpwfs, req->lpszSrcFile, req->lpszDestFile);
1626 HeapFree(GetProcessHeap(), 0, req->lpszSrcFile);
1627 HeapFree(GetProcessHeap(), 0, req->lpszDestFile);
1630 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1632 LPWININETFTPSESSIONW lpwfs;
1633 LPWININETAPPINFOW hIC = NULL;
1636 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1637 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1639 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1643 hIC = lpwfs->lpAppInfo;
1644 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1646 WORKREQUEST workRequest;
1647 struct WORKREQ_FTPRENAMEFILEW *req;
1649 workRequest.asyncproc = AsyncFtpRenameFileProc;
1650 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1651 req = &workRequest.u.FtpRenameFileW;
1652 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1653 req->lpszDestFile = WININET_strdupW(lpszDest);
1655 r = INTERNET_AsyncCall(&workRequest);
1659 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1664 WININET_Release( &lpwfs->hdr );
1669 /***********************************************************************
1670 * FTP_FtpRenameFileW (Internal)
1672 * Rename a file on the ftp server
1679 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1680 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1683 BOOL bSuccess = FALSE;
1684 LPWININETAPPINFOW hIC = NULL;
1688 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1690 /* Clear any error information */
1691 INTERNET_SetLastError(0);
1693 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1696 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1697 if (nResCode == 350)
1699 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1702 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1705 if (nResCode == 250)
1708 FTP_SetResponseError(nResCode);
1711 hIC = lpwfs->lpAppInfo;
1712 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1714 INTERNET_ASYNC_RESULT iar;
1716 iar.dwResult = (DWORD)bSuccess;
1717 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1718 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1719 &iar, sizeof(INTERNET_ASYNC_RESULT));
1725 /***********************************************************************
1726 * FtpCommandA (WININET.@)
1728 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1729 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1731 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1732 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1737 /***********************************************************************
1738 * FtpCommandW (WININET.@)
1740 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1741 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1743 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1744 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1749 /***********************************************************************
1750 * FTP_Connect (internal)
1752 * Connect to a ftp server
1755 * HINTERNET a session handle on success
1760 * Windows uses 'anonymous' as the username, when given a NULL username
1761 * and a NULL password. The password is first looked up in:
1763 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1765 * If this entry is not present it uses the current username as the password.
1769 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1770 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1771 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1772 DWORD dwInternalFlags)
1774 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1775 'M','i','c','r','o','s','o','f','t','\\',
1776 'W','i','n','d','o','w','s','\\',
1777 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1778 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1779 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1780 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1781 static const WCHAR szEmpty[] = {'\0'};
1782 struct sockaddr_in socketAddr;
1785 BOOL bSuccess = FALSE;
1786 LPWININETFTPSESSIONW lpwfs = NULL;
1787 HINTERNET handle = NULL;
1789 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1790 hIC, debugstr_w(lpszServerName),
1791 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1793 assert( hIC->hdr.htype == WH_HINIT );
1795 if (NULL == lpszUserName && NULL != lpszPassword)
1797 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1801 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1804 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1808 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1809 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1811 lpwfs->hdr.htype = WH_HFTPSESSION;
1812 lpwfs->hdr.dwFlags = dwFlags;
1813 lpwfs->hdr.dwContext = dwContext;
1814 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1815 lpwfs->hdr.dwRefCount = 1;
1816 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1817 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1818 lpwfs->download_in_progress = NULL;
1820 WININET_AddRef( &hIC->hdr );
1821 lpwfs->lpAppInfo = hIC;
1823 handle = WININET_AllocHandle( &lpwfs->hdr );
1826 ERR("Failed to alloc handle\n");
1827 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1831 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1832 if(strchrW(hIC->lpszProxy, ' '))
1833 FIXME("Several proxies not implemented.\n");
1834 if(hIC->lpszProxyBypass)
1835 FIXME("Proxy bypass is ignored.\n");
1837 if ( !lpszUserName) {
1839 WCHAR szPassword[MAX_PATH];
1840 DWORD len = sizeof(szPassword);
1842 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1844 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1845 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1846 /* Nothing in the registry, get the username and use that as the password */
1847 if (!GetUserNameW(szPassword, &len)) {
1848 /* Should never get here, but use an empty password as failsafe */
1849 strcpyW(szPassword, szEmpty);
1854 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1855 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1858 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1861 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1863 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1866 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1867 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1869 INTERNET_ASYNC_RESULT iar;
1871 iar.dwResult = (DWORD)handle;
1872 iar.dwError = ERROR_SUCCESS;
1874 SendAsyncCallback(&hIC->hdr, dwContext,
1875 INTERNET_STATUS_HANDLE_CREATED, &iar,
1876 sizeof(INTERNET_ASYNC_RESULT));
1879 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1880 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1882 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1884 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1888 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1889 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1891 nsocket = socket(AF_INET,SOCK_STREAM,0);
1894 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1898 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1899 &socketAddr, sizeof(struct sockaddr_in));
1901 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1903 ERR("Unable to connect (%s)\n", strerror(errno));
1904 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1908 TRACE("Connected to server\n");
1909 lpwfs->sndSocket = nsocket;
1910 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1911 &socketAddr, sizeof(struct sockaddr_in));
1913 sock_namelen = sizeof(lpwfs->socketAddress);
1914 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1916 if (FTP_ConnectToHost(lpwfs))
1918 TRACE("Successfully logged into server\n");
1924 if (!bSuccess && nsocket == -1)
1925 closesocket(nsocket);
1927 if (!bSuccess && lpwfs)
1929 HeapFree(GetProcessHeap(), 0, lpwfs);
1930 WININET_FreeHandle( handle );
1935 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1937 INTERNET_ASYNC_RESULT iar;
1939 iar.dwResult = (DWORD)lpwfs;
1940 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1941 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1942 &iar, sizeof(INTERNET_ASYNC_RESULT));
1949 /***********************************************************************
1950 * FTP_ConnectToHost (internal)
1952 * Connect to a ftp server
1959 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1962 BOOL bSuccess = FALSE;
1965 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1967 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1970 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1973 /* Login successful... */
1974 if (nResCode == 230)
1976 /* User name okay, need password... */
1977 else if (nResCode == 331)
1978 bSuccess = FTP_SendPassword(lpwfs);
1979 /* Need account for login... */
1980 else if (nResCode == 332)
1981 bSuccess = FTP_SendAccount(lpwfs);
1983 FTP_SetResponseError(nResCode);
1986 TRACE("Returning %d\n", bSuccess);
1992 /***********************************************************************
1993 * FTP_SendCommandA (internal)
1995 * Send command to server
2002 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
2003 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2007 DWORD nBytesSent = 0;
2011 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
2015 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2018 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
2019 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
2020 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
2022 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2025 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
2026 dwParamLen ? lpszParam : "", szCRLF);
2028 TRACE("Sending (%s) len(%d)\n", buf, len);
2029 while((nBytesSent < len) && (nRC != -1))
2031 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
2035 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2039 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2040 &nBytesSent, sizeof(DWORD));
2043 TRACE("Sent %d bytes\n", nBytesSent);
2047 /***********************************************************************
2048 * FTP_SendCommand (internal)
2050 * Send command to server
2057 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2058 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2061 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2062 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2063 HeapFree(GetProcessHeap(), 0, lpszParamA);
2067 /***********************************************************************
2068 * FTP_ReceiveResponse (internal)
2070 * Receive response from server
2073 * Reply code on success
2077 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2079 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2082 char firstprefix[5];
2083 BOOL multiline = FALSE;
2084 LPWININETAPPINFOW hIC = NULL;
2086 TRACE("socket(%d)\n", lpwfs->sndSocket);
2088 hIC = lpwfs->lpAppInfo;
2089 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2093 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2100 if(lpszResponse[3] != '-')
2103 { /* Start of multiline repsonse. Loop until we get "nnn " */
2105 memcpy(firstprefix, lpszResponse, 3);
2106 firstprefix[3] = ' ';
2107 firstprefix[4] = '\0';
2112 if(!memcmp(firstprefix, lpszResponse, 4))
2120 rc = atoi(lpszResponse);
2122 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2123 &nRecv, sizeof(DWORD));
2127 TRACE("return %d\n", rc);
2132 /***********************************************************************
2133 * FTP_SendPassword (internal)
2135 * Send password to ftp server
2142 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2145 BOOL bSuccess = FALSE;
2148 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2151 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2154 TRACE("Received reply code %d\n", nResCode);
2155 /* Login successful... */
2156 if (nResCode == 230)
2158 /* Command not implemented, superfluous at the server site... */
2159 /* Need account for login... */
2160 else if (nResCode == 332)
2161 bSuccess = FTP_SendAccount(lpwfs);
2163 FTP_SetResponseError(nResCode);
2167 TRACE("Returning %d\n", bSuccess);
2172 /***********************************************************************
2173 * FTP_SendAccount (internal)
2182 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2185 BOOL bSuccess = FALSE;
2188 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2191 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2195 FTP_SetResponseError(nResCode);
2202 /***********************************************************************
2203 * FTP_SendStore (internal)
2205 * Send request to upload file to ftp server
2212 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2215 BOOL bSuccess = FALSE;
2218 if (!FTP_InitListenSocket(lpwfs))
2221 if (!FTP_SendType(lpwfs, dwType))
2224 if (!FTP_SendPortOrPasv(lpwfs))
2227 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2229 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2232 if (nResCode == 150 || nResCode == 125)
2235 FTP_SetResponseError(nResCode);
2239 if (!bSuccess && lpwfs->lstnSocket != -1)
2241 closesocket(lpwfs->lstnSocket);
2242 lpwfs->lstnSocket = -1;
2249 /***********************************************************************
2250 * FTP_InitListenSocket (internal)
2252 * Create a socket to listen for server response
2259 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2261 BOOL bSuccess = FALSE;
2262 socklen_t namelen = sizeof(struct sockaddr_in);
2266 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2267 if (lpwfs->lstnSocket == -1)
2269 TRACE("Unable to create listening socket\n");
2273 /* We obtain our ip addr from the name of the command channel socket */
2274 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2276 /* and get the system to assign us a port */
2277 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2279 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2281 TRACE("Unable to bind socket\n");
2285 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2287 TRACE("listen failed\n");
2291 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2295 if (!bSuccess && lpwfs->lstnSocket == -1)
2297 closesocket(lpwfs->lstnSocket);
2298 lpwfs->lstnSocket = -1;
2305 /***********************************************************************
2306 * FTP_SendType (internal)
2308 * Tell server type of data being transferred
2314 * W98SE doesn't cache the type that's currently set
2315 * (i.e. it sends it always),
2316 * so we probably don't want to do that either.
2318 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2321 WCHAR type[] = { 'I','\0' };
2322 BOOL bSuccess = FALSE;
2325 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2328 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2331 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2337 FTP_SetResponseError(nResCode);
2344 /***********************************************************************
2345 * FTP_GetFileSize (internal)
2347 * Retrieves from the server the size of the given file
2354 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2357 BOOL bSuccess = FALSE;
2361 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2364 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2367 if (nResCode == 213) {
2368 /* Now parses the output to get the actual file size */
2370 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2372 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2373 if (lpszResponseBuffer[i] == '\0') return FALSE;
2374 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2378 FTP_SetResponseError(nResCode);
2387 /***********************************************************************
2388 * FTP_SendPort (internal)
2390 * Tell server which port to use
2397 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2399 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2401 WCHAR szIPAddress[64];
2402 BOOL bSuccess = FALSE;
2405 sprintfW(szIPAddress, szIPFormat,
2406 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2407 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2408 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2409 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2410 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2411 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2413 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2416 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2419 if (nResCode == 200)
2422 FTP_SetResponseError(nResCode);
2430 /***********************************************************************
2431 * FTP_DoPassive (internal)
2433 * Tell server that we want to do passive transfers
2434 * and connect data socket
2441 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2444 BOOL bSuccess = FALSE;
2447 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2450 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2453 if (nResCode == 227)
2455 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2459 char *pAddr, *pPort;
2461 struct sockaddr_in dataSocketAddress;
2463 p = lpszResponseBuffer+4; /* skip status code */
2465 /* do a very strict check; we can improve that later. */
2467 if (strncmp(p, "Entering Passive Mode", 21))
2469 ERR("unknown response '%.*s', aborting\n", 21, p);
2472 p += 21; /* skip string */
2473 if ((*p++ != ' ') || (*p++ != '('))
2475 ERR("unknown response format, aborting\n");
2479 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2482 ERR("unknown response address format '%s', aborting\n", p);
2485 for (i=0; i < 6; i++)
2488 dataSocketAddress = lpwfs->socketAddress;
2489 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2490 pPort = (char *)&(dataSocketAddress.sin_port);
2498 nsocket = socket(AF_INET,SOCK_STREAM,0);
2502 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2504 ERR("can't connect passive FTP data port.\n");
2505 closesocket(nsocket);
2508 lpwfs->pasvSocket = nsocket;
2512 FTP_SetResponseError(nResCode);
2520 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2522 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2524 if (!FTP_DoPassive(lpwfs))
2529 if (!FTP_SendPort(lpwfs))
2536 /***********************************************************************
2537 * FTP_GetDataSocket (internal)
2539 * Either accepts an incoming data socket connection from the server
2540 * or just returns the already opened socket after a PASV command
2541 * in case of passive FTP.
2549 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2551 struct sockaddr_in saddr;
2552 socklen_t addrlen = sizeof(struct sockaddr);
2555 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2557 *nDataSocket = lpwfs->pasvSocket;
2561 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2562 closesocket(lpwfs->lstnSocket);
2563 lpwfs->lstnSocket = -1;
2565 return *nDataSocket != -1;
2569 /***********************************************************************
2570 * FTP_SendData (internal)
2572 * Send data to the server
2579 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2581 BY_HANDLE_FILE_INFORMATION fi;
2582 DWORD nBytesRead = 0;
2583 DWORD nBytesSent = 0;
2584 DWORD nTotalSent = 0;
2585 DWORD nBytesToSend, nLen;
2587 time_t s_long_time, e_long_time;
2592 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2593 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2595 /* Get the size of the file. */
2596 GetFileInformationByHandle(hFile, &fi);
2601 nBytesToSend = nBytesRead - nBytesSent;
2603 if (nBytesToSend <= 0)
2605 /* Read data from file. */
2607 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2608 ERR("Failed reading from file\n");
2611 nBytesToSend = nBytesRead;
2616 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2617 DATA_PACKET_SIZE : nBytesToSend;
2618 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2626 /* Do some computation to display the status. */
2628 nSeconds = e_long_time - s_long_time;
2629 if( nSeconds / 60 > 0 )
2631 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2632 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2633 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2637 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2638 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2639 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2641 } while (nRC != -1);
2643 TRACE("file transfer complete!\n");
2645 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2651 /***********************************************************************
2652 * FTP_SendRetrieve (internal)
2654 * Send request to retrieve a file
2657 * Number of bytes to be received on success
2661 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2667 if (!FTP_InitListenSocket(lpwfs))
2670 if (!FTP_SendType(lpwfs, dwType))
2673 if (!FTP_SendPortOrPasv(lpwfs))
2676 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2679 TRACE("Waiting to receive %d bytes\n", nResult);
2681 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2684 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2685 if ((nResCode != 125) && (nResCode != 150)) {
2686 /* That means that we got an error getting the file. */
2691 if (0 == nResult && lpwfs->lstnSocket != -1)
2693 closesocket(lpwfs->lstnSocket);
2694 lpwfs->lstnSocket = -1;
2701 /***********************************************************************
2702 * FTP_RetrieveData (internal)
2704 * Retrieve data from server
2711 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2713 DWORD nBytesWritten;
2714 DWORD nBytesReceived = 0;
2720 if (INVALID_HANDLE_VALUE == hFile)
2723 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2724 if (NULL == lpszBuffer)
2726 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2730 while (nBytesReceived < nBytes && nRC != -1)
2732 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2735 /* other side closed socket. */
2738 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2739 nBytesReceived += nRC;
2742 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2743 nBytesReceived * 100 / nBytes);
2746 TRACE("Data transfer complete\n");
2747 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2754 /***********************************************************************
2755 * FTP_CloseSessionHandle (internal)
2757 * Deallocate session handle
2764 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2766 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2770 WININET_Release(&lpwfs->lpAppInfo->hdr);
2772 if (lpwfs->download_in_progress != NULL)
2773 lpwfs->download_in_progress->session_deleted = TRUE;
2775 if (lpwfs->sndSocket != -1)
2776 closesocket(lpwfs->sndSocket);
2778 if (lpwfs->lstnSocket != -1)
2779 closesocket(lpwfs->lstnSocket);
2781 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2782 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2783 HeapFree(GetProcessHeap(), 0, lpwfs);
2787 /***********************************************************************
2788 * FTP_FindNextFileW (Internal)
2790 * Continues a file search from a previous call to FindFirstFile
2797 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2799 BOOL bSuccess = TRUE;
2800 LPWIN32_FIND_DATAW lpFindFileData;
2802 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2804 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2806 /* Clear any error information */
2807 INTERNET_SetLastError(0);
2809 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2810 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2812 if (lpwh->index >= lpwh->size)
2814 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2819 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2822 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2826 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2828 INTERNET_ASYNC_RESULT iar;
2830 iar.dwResult = (DWORD)bSuccess;
2831 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2832 INTERNET_GetLastError();
2834 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2835 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2836 sizeof(INTERNET_ASYNC_RESULT));
2843 /***********************************************************************
2844 * FTP_CloseFindNextHandle (internal)
2846 * Deallocate session handle
2853 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2855 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2860 WININET_Release(&lpwfn->lpFtpSession->hdr);
2862 for (i = 0; i < lpwfn->size; i++)
2864 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2867 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2868 HeapFree(GetProcessHeap(), 0, lpwfn);
2871 /***********************************************************************
2872 * FTP_CloseFileTransferHandle (internal)
2874 * Closes the file transfer handle. This also 'cleans' the data queue of
2875 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2878 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2880 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2881 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2886 WININET_Release(&lpwh->lpFtpSession->hdr);
2888 if (!lpwh->session_deleted)
2889 lpwfs->download_in_progress = NULL;
2891 /* This just serves to flush the control socket of any spurrious lines written
2892 to it (like '226 Transfer complete.').
2894 Wonder what to do if the server sends us an error code though...
2896 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2898 if (lpwh->nDataSocket != -1)
2899 closesocket(lpwh->nDataSocket);
2901 HeapFree(GetProcessHeap(), 0, lpwh);
2904 /***********************************************************************
2905 * FTP_ReceiveFileList (internal)
2907 * Read file list from server
2910 * Handle to file list on success
2914 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2915 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2918 LPFILEPROPERTIESW lpafp = NULL;
2919 LPWININETFTPFINDNEXTW lpwfn = NULL;
2920 HINTERNET handle = 0;
2922 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2924 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2927 FTP_ConvertFileProp(lpafp, lpFindFileData);
2929 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
2932 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
2933 lpwfn->hdr.dwContext = dwContext;
2934 lpwfn->hdr.dwRefCount = 1;
2935 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2936 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2937 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2938 lpwfn->size = dwSize;
2939 lpwfn->lpafp = lpafp;
2941 WININET_AddRef( &lpwfs->hdr );
2942 lpwfn->lpFtpSession = lpwfs;
2944 handle = WININET_AllocHandle( &lpwfn->hdr );
2949 WININET_Release( &lpwfn->hdr );
2951 TRACE("Matched %d files\n", dwSize);
2956 /***********************************************************************
2957 * FTP_ConvertFileProp (internal)
2959 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2966 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2968 BOOL bSuccess = FALSE;
2970 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2974 /* Convert 'Unix' time to Windows time */
2975 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2976 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2977 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2978 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2980 /* Not all fields are filled in */
2981 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2982 lpFindFileData->nFileSizeLow = lpafp->nSize;
2984 if (lpafp->bIsDirectory)
2985 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2987 if (lpafp->lpszName)
2988 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2996 /***********************************************************************
2997 * FTP_ParseNextFile (internal)
2999 * Parse the next line in file listing
3005 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
3007 static const char szSpace[] = " \t";
3015 lpfp->lpszName = NULL;
3017 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
3020 pszToken = strtok(pszLine, szSpace);
3022 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3025 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3027 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
3028 if(!FTP_ParsePermission(pszToken, lpfp))
3029 lpfp->bIsDirectory = FALSE;
3030 for(i=0; i<=3; i++) {
3031 if(!(pszToken = strtok(NULL, szSpace)))
3034 if(!pszToken) continue;
3035 if(lpfp->bIsDirectory) {
3036 TRACE("Is directory\n");
3040 TRACE("Size: %s\n", pszToken);
3041 lpfp->nSize = atol(pszToken);
3044 lpfp->tmLastModified.tm_sec = 0;
3045 lpfp->tmLastModified.tm_min = 0;
3046 lpfp->tmLastModified.tm_hour = 0;
3047 lpfp->tmLastModified.tm_mday = 0;
3048 lpfp->tmLastModified.tm_mon = 0;
3049 lpfp->tmLastModified.tm_year = 0;
3051 /* Determine month */
3052 pszToken = strtok(NULL, szSpace);
3053 if(!pszToken) continue;
3054 if(strlen(pszToken) >= 3) {
3056 if((pszTmp = StrStrIA(szMonths, pszToken)))
3057 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3060 pszToken = strtok(NULL, szSpace);
3061 if(!pszToken) continue;
3062 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3063 /* Determine time or year */
3064 pszToken = strtok(NULL, szSpace);
3065 if(!pszToken) continue;
3066 if((pszTmp = strchr(pszToken, ':'))) {
3071 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3072 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3074 apTM = localtime(&aTime);
3075 lpfp->tmLastModified.tm_year = apTM->tm_year;
3078 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3079 lpfp->tmLastModified.tm_hour = 12;
3081 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3082 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3083 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3084 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3086 pszToken = strtok(NULL, szSpace);
3087 if(!pszToken) continue;
3088 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3089 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3091 /* NT way of parsing ... :
3093 07-13-03 08:55PM <DIR> sakpatch
3094 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3096 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3097 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3099 sscanf(pszToken, "%d-%d-%d",
3100 &lpfp->tmLastModified.tm_mon,
3101 &lpfp->tmLastModified.tm_mday,
3102 &lpfp->tmLastModified.tm_year);
3104 /* Hacky and bad Y2K protection :-) */
3105 if (lpfp->tmLastModified.tm_year < 70)
3106 lpfp->tmLastModified.tm_year += 100;
3108 pszToken = strtok(NULL, szSpace);
3109 if(!pszToken) continue;
3110 sscanf(pszToken, "%d:%d",
3111 &lpfp->tmLastModified.tm_hour,
3112 &lpfp->tmLastModified.tm_min);
3113 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3114 lpfp->tmLastModified.tm_hour += 12;
3116 lpfp->tmLastModified.tm_sec = 0;
3118 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3119 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3120 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3121 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3123 pszToken = strtok(NULL, szSpace);
3124 if(!pszToken) continue;
3125 if(!strcasecmp(pszToken, "<DIR>")) {
3126 lpfp->bIsDirectory = TRUE;
3128 TRACE("Is directory\n");
3131 lpfp->bIsDirectory = FALSE;
3132 lpfp->nSize = atol(pszToken);
3133 TRACE("Size: %d\n", lpfp->nSize);
3136 pszToken = strtok(NULL, szSpace);
3137 if(!pszToken) continue;
3138 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3139 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3141 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3142 else if(pszToken[0] == '+') {
3143 FIXME("EPLF Format not implemented\n");
3146 if(lpfp->lpszName) {
3147 if((lpszSearchFile == NULL) ||
3148 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3150 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3153 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3154 lpfp->lpszName = NULL;
3161 /***********************************************************************
3162 * FTP_ParseDirectory (internal)
3164 * Parse string of directory information
3170 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3171 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3173 BOOL bSuccess = TRUE;
3174 INT sizeFilePropArray = 500;/*20; */
3175 INT indexFilePropArray = -1;
3179 /* Allocate intial file properties array */
3180 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3185 if (indexFilePropArray+1 >= sizeFilePropArray)
3187 LPFILEPROPERTIESW tmpafp;
3189 sizeFilePropArray *= 2;
3190 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3191 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3200 indexFilePropArray++;
3201 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3203 if (bSuccess && indexFilePropArray)
3205 if (indexFilePropArray < sizeFilePropArray - 1)
3207 LPFILEPROPERTIESW tmpafp;
3209 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3210 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3214 *dwfp = indexFilePropArray;
3218 HeapFree(GetProcessHeap(), 0, *lpafp);
3219 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3227 /***********************************************************************
3228 * FTP_ParsePermission (internal)
3230 * Parse permission string of directory information
3237 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3239 BOOL bSuccess = TRUE;
3240 unsigned short nPermission = 0;
3245 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3251 lpfp->bIsDirectory = (*lpszPermission == 'd');
3257 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3260 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3263 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3266 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3269 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3272 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3275 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3278 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3281 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3285 }while (nPos <= nLast);
3287 lpfp->permissions = nPermission;
3292 /***********************************************************************
3293 * FTP_SetResponseError (internal)
3295 * Set the appropriate error code for a given response from the server
3300 static DWORD FTP_SetResponseError(DWORD dwResponse)
3306 case 421: /* Service not available - Server may be shutting down. */
3307 dwCode = ERROR_INTERNET_TIMEOUT;
3310 case 425: /* Cannot open data connection. */
3311 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3314 case 426: /* Connection closed, transer aborted. */
3315 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3318 case 500: /* Syntax error. Command unrecognized. */
3319 case 501: /* Syntax error. Error in parameters or arguments. */
3320 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3323 case 530: /* Not logged in. Login incorrect. */
3324 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3327 case 550: /* File action not taken. File not found or no access. */
3328 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3331 case 450: /* File action not taken. File may be busy. */
3332 case 451: /* Action aborted. Server error. */
3333 case 452: /* Action not taken. Insufficient storage space on server. */
3334 case 502: /* Command not implemented. */
3335 case 503: /* Bad sequence of command. */
3336 case 504: /* Command not implemented for that parameter. */
3337 case 532: /* Need account for storing files */
3338 case 551: /* Requested action aborted. Page type unknown */
3339 case 552: /* Action aborted. Exceeded storage allocation */
3340 case 553: /* Action not taken. File name not allowed. */
3343 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3347 INTERNET_SetLastError(dwCode);