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.asyncall = CALLASYNCPROC;
218 workRequest.asyncproc = AsyncFtpPutFileProc;
219 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
220 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
221 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
222 req->dwFlags = dwFlags;
223 req->dwContext = dwContext;
225 r = INTERNET_AsyncCall(&workRequest);
229 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
230 lpszNewRemoteFile, dwFlags, dwContext);
235 WININET_Release( &lpwfs->hdr );
240 /***********************************************************************
241 * FTP_FtpPutFileW (Internal)
243 * Uploads a file to the FTP server
250 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
251 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
254 BOOL bSuccess = FALSE;
255 LPWININETAPPINFOW hIC = NULL;
258 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
260 if (!lpszLocalFile || !lpszNewRemoteFile)
262 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
266 assert( WH_HFTPSESSION == lpwfs->hdr.htype);
268 /* Clear any error information */
269 INTERNET_SetLastError(0);
270 hIC = lpwfs->lpAppInfo;
272 /* Open file to be uploaded */
273 if (INVALID_HANDLE_VALUE ==
274 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
276 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
280 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
282 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
286 /* Get data socket to server */
287 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
289 FTP_SendData(lpwfs, nDataSocket, hFile);
290 closesocket(nDataSocket);
291 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
297 FTP_SetResponseError(nResCode);
303 if (lpwfs->lstnSocket != -1)
304 closesocket(lpwfs->lstnSocket);
306 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
308 INTERNET_ASYNC_RESULT iar;
310 iar.dwResult = (DWORD)bSuccess;
311 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
312 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
313 &iar, sizeof(INTERNET_ASYNC_RESULT));
323 /***********************************************************************
324 * FtpSetCurrentDirectoryA (WININET.@)
326 * Change the working directory on the FTP server
333 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
335 LPWSTR lpwzDirectory;
338 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
339 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
340 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
345 /***********************************************************************
346 * FtpSetCurrentDirectoryW (WININET.@)
348 * Change the working directory on the FTP server
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 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
368 LPWININETFTPSESSIONW lpwfs = NULL;
369 LPWININETAPPINFOW hIC = NULL;
374 SetLastError(ERROR_INVALID_PARAMETER);
378 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
379 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
381 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
385 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
387 hIC = lpwfs->lpAppInfo;
388 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
390 WORKREQUEST workRequest;
391 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
393 workRequest.asyncall = CALLASYNCPROC;
394 workRequest.asyncproc = AsyncFtpSetCurrentDirectoryProc;
395 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
396 req = &workRequest.u.FtpSetCurrentDirectoryW;
397 req->lpszDirectory = WININET_strdupW(lpszDirectory);
399 r = INTERNET_AsyncCall(&workRequest);
403 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
408 WININET_Release( &lpwfs->hdr );
414 /***********************************************************************
415 * FTP_FtpSetCurrentDirectoryW (Internal)
417 * Change the working directory on the FTP server
424 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
427 LPWININETAPPINFOW hIC = NULL;
428 DWORD bSuccess = FALSE;
430 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
432 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
434 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
438 /* Clear any error information */
439 INTERNET_SetLastError(0);
441 hIC = lpwfs->lpAppInfo;
442 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
443 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
446 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
453 FTP_SetResponseError(nResCode);
457 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
459 INTERNET_ASYNC_RESULT iar;
461 iar.dwResult = (DWORD)bSuccess;
462 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
463 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
464 &iar, sizeof(INTERNET_ASYNC_RESULT));
470 /***********************************************************************
471 * FtpCreateDirectoryA (WININET.@)
473 * Create new directory on the FTP server
480 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
482 LPWSTR lpwzDirectory;
485 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
486 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
487 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
492 /***********************************************************************
493 * FtpCreateDirectoryW (WININET.@)
495 * Create new directory on the FTP server
502 static void AsyncFtpCreateDirectoryProc(WORKREQUEST *workRequest)
504 struct WORKREQ_FTPCREATEDIRECTORYW const *req = &workRequest->u.FtpCreateDirectoryW;
505 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
507 TRACE(" %p\n", lpwfs);
509 FTP_FtpCreateDirectoryW(lpwfs, req->lpszDirectory);
510 HeapFree(GetProcessHeap(), 0, req->lpszDirectory);
513 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
515 LPWININETFTPSESSIONW lpwfs;
516 LPWININETAPPINFOW hIC = NULL;
519 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
520 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
522 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
526 hIC = lpwfs->lpAppInfo;
527 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
529 WORKREQUEST workRequest;
530 struct WORKREQ_FTPCREATEDIRECTORYW *req;
532 workRequest.asyncall = CALLASYNCPROC;
533 workRequest.asyncproc = AsyncFtpCreateDirectoryProc;
534 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
535 req = &workRequest.u.FtpCreateDirectoryW;
536 req->lpszDirectory = WININET_strdupW(lpszDirectory);
538 r = INTERNET_AsyncCall(&workRequest);
542 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
546 WININET_Release( &lpwfs->hdr );
552 /***********************************************************************
553 * FTP_FtpCreateDirectoryW (Internal)
555 * Create new directory on the FTP server
562 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
565 BOOL bSuccess = FALSE;
566 LPWININETAPPINFOW hIC = NULL;
568 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
570 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
572 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
576 /* Clear any error information */
577 INTERNET_SetLastError(0);
579 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
582 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
588 FTP_SetResponseError(nResCode);
592 hIC = lpwfs->lpAppInfo;
593 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
595 INTERNET_ASYNC_RESULT iar;
597 iar.dwResult = (DWORD)bSuccess;
598 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
599 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
600 &iar, sizeof(INTERNET_ASYNC_RESULT));
606 /***********************************************************************
607 * FtpFindFirstFileA (WININET.@)
609 * Search the specified directory
612 * HINTERNET on success
616 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
617 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
619 LPWSTR lpwzSearchFile;
620 WIN32_FIND_DATAW wfd;
621 LPWIN32_FIND_DATAW lpFindFileDataW;
624 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
625 lpFindFileDataW = lpFindFileData?&wfd:NULL;
626 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
627 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
630 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
636 /***********************************************************************
637 * FtpFindFirstFileW (WININET.@)
639 * Search the specified directory
642 * HINTERNET on success
646 static void AsyncFtpFindFirstFileProc(WORKREQUEST *workRequest)
648 struct WORKREQ_FTPFINDFIRSTFILEW const *req = &workRequest->u.FtpFindFirstFileW;
649 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) workRequest->hdr;
651 TRACE("%p\n", lpwfs);
653 FTP_FtpFindFirstFileW(lpwfs, req->lpszSearchFile,
654 req->lpFindFileData, req->dwFlags, req->dwContext);
655 HeapFree(GetProcessHeap(), 0, req->lpszSearchFile);
658 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
659 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
661 LPWININETFTPSESSIONW lpwfs;
662 LPWININETAPPINFOW hIC = NULL;
665 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
666 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
668 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
672 hIC = lpwfs->lpAppInfo;
673 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
675 WORKREQUEST workRequest;
676 struct WORKREQ_FTPFINDFIRSTFILEW *req;
678 workRequest.asyncall = CALLASYNCPROC;
679 workRequest.asyncproc = AsyncFtpFindFirstFileProc;
680 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
681 req = &workRequest.u.FtpFindFirstFileW;
682 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
683 req->lpFindFileData = lpFindFileData;
684 req->dwFlags = dwFlags;
685 req->dwContext= dwContext;
687 INTERNET_AsyncCall(&workRequest);
692 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
697 WININET_Release( &lpwfs->hdr );
703 /***********************************************************************
704 * FTP_FtpFindFirstFileW (Internal)
706 * Search the specified directory
709 * HINTERNET on success
713 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
714 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
717 LPWININETAPPINFOW hIC = NULL;
718 HINTERNET hFindNext = NULL;
722 assert(WH_HFTPSESSION == lpwfs->hdr.htype);
724 /* Clear any error information */
725 INTERNET_SetLastError(0);
727 if (!FTP_InitListenSocket(lpwfs))
730 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
733 if (!FTP_SendPortOrPasv(lpwfs))
736 hIC = lpwfs->lpAppInfo;
737 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
738 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
741 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
744 if (nResCode == 125 || nResCode == 150)
748 /* Get data socket to server */
749 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
751 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
752 closesocket(nDataSocket);
753 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
754 if (nResCode != 226 && nResCode != 250)
755 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
759 FTP_SetResponseError(nResCode);
763 if (lpwfs->lstnSocket != -1)
764 closesocket(lpwfs->lstnSocket);
766 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
768 INTERNET_ASYNC_RESULT iar;
772 iar.dwResult = (DWORD)hFindNext;
773 iar.dwError = ERROR_SUCCESS;
774 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
775 &iar, sizeof(INTERNET_ASYNC_RESULT));
778 iar.dwResult = (DWORD)hFindNext;
779 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
780 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
781 &iar, sizeof(INTERNET_ASYNC_RESULT));
788 /***********************************************************************
789 * FtpGetCurrentDirectoryA (WININET.@)
791 * Retrieves the current directory
798 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
799 LPDWORD lpdwCurrentDirectory)
805 if(lpdwCurrentDirectory) {
806 len = *lpdwCurrentDirectory;
807 if(lpszCurrentDirectory)
809 dir = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
812 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
817 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
818 if(lpdwCurrentDirectory) {
819 *lpdwCurrentDirectory = len;
820 if(lpszCurrentDirectory) {
821 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
822 HeapFree(GetProcessHeap(), 0, dir);
829 /***********************************************************************
830 * FtpGetCurrentDirectoryW (WININET.@)
832 * Retrieves the current directory
839 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
840 LPDWORD lpdwCurrentDirectory)
842 LPWININETFTPSESSIONW lpwfs;
843 LPWININETAPPINFOW hIC = NULL;
846 TRACE("len(%d)\n", *lpdwCurrentDirectory);
848 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
849 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
851 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
855 hIC = lpwfs->lpAppInfo;
856 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
858 WORKREQUEST workRequest;
859 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
861 workRequest.asyncall = FTPGETCURRENTDIRECTORYW;
862 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
863 req = &workRequest.u.FtpGetCurrentDirectoryW;
864 req->lpszDirectory = lpszCurrentDirectory;
865 req->lpdwDirectory = lpdwCurrentDirectory;
867 r = INTERNET_AsyncCall(&workRequest);
871 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
872 lpdwCurrentDirectory);
877 WININET_Release( &lpwfs->hdr );
883 /***********************************************************************
884 * FTP_FtpGetCurrentDirectoryA (Internal)
886 * Retrieves the current directory
893 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
894 LPDWORD lpdwCurrentDirectory)
897 LPWININETAPPINFOW hIC = NULL;
898 DWORD bSuccess = FALSE;
900 TRACE("len(%d)\n", *lpdwCurrentDirectory);
902 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
904 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
908 /* Clear any error information */
909 INTERNET_SetLastError(0);
911 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
913 hIC = lpwfs->lpAppInfo;
914 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
915 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
918 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
921 if (nResCode == 257) /* Extract directory name */
923 DWORD firstpos, lastpos, len;
924 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
926 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
928 if ('"' == lpszResponseBuffer[lastpos])
937 len = lastpos - firstpos - 1;
938 lstrcpynW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1], *lpdwCurrentDirectory);
939 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
940 *lpdwCurrentDirectory = len;
944 FTP_SetResponseError(nResCode);
948 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
950 INTERNET_ASYNC_RESULT iar;
952 iar.dwResult = (DWORD)bSuccess;
953 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
954 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
955 &iar, sizeof(INTERNET_ASYNC_RESULT));
958 return (DWORD) bSuccess;
961 /***********************************************************************
962 * FtpOpenFileA (WININET.@)
964 * Open a remote file for writing or reading
967 * HINTERNET handle on success
971 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
972 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
978 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
979 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
980 HeapFree(GetProcessHeap(), 0, lpwzFileName);
985 /***********************************************************************
986 * FtpOpenFileW (WININET.@)
988 * Open a remote file for writing or reading
991 * HINTERNET handle on success
995 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
996 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
999 LPWININETFTPSESSIONW lpwfs;
1000 LPWININETAPPINFOW hIC = NULL;
1003 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession,
1004 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
1006 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1007 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1009 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1013 if (lpwfs->download_in_progress != NULL) {
1014 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1017 hIC = lpwfs->lpAppInfo;
1018 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1020 WORKREQUEST workRequest;
1021 struct WORKREQ_FTPOPENFILEW *req;
1023 workRequest.asyncall = FTPOPENFILEW;
1024 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1025 req = &workRequest.u.FtpOpenFileW;
1026 req->lpszFilename = WININET_strdupW(lpszFileName);
1027 req->dwAccess = fdwAccess;
1028 req->dwFlags = dwFlags;
1029 req->dwContext = dwContext;
1031 INTERNET_AsyncCall(&workRequest);
1036 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
1041 WININET_Release( &lpwfs->hdr );
1047 /***********************************************************************
1048 * FTP_FtpOpenFileW (Internal)
1050 * Open a remote file for writing or reading
1053 * HINTERNET handle on success
1057 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
1058 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
1062 BOOL bSuccess = FALSE;
1063 LPWININETFTPFILE lpwh = NULL;
1064 LPWININETAPPINFOW hIC = NULL;
1065 HINTERNET handle = NULL;
1069 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1071 /* Clear any error information */
1072 INTERNET_SetLastError(0);
1074 if (GENERIC_READ == fdwAccess)
1076 /* Set up socket to retrieve data */
1077 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1079 else if (GENERIC_WRITE == fdwAccess)
1081 /* Set up socket to send data */
1082 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1085 /* Get data socket to server */
1086 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1088 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE));
1089 lpwh->hdr.htype = WH_HFILE;
1090 lpwh->hdr.dwFlags = dwFlags;
1091 lpwh->hdr.dwContext = dwContext;
1092 lpwh->hdr.dwRefCount = 1;
1093 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1094 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1095 lpwh->nDataSocket = nDataSocket;
1096 lpwh->session_deleted = FALSE;
1098 WININET_AddRef( &lpwfs->hdr );
1099 lpwh->lpFtpSession = lpwfs;
1101 handle = WININET_AllocHandle( &lpwh->hdr );
1105 /* Indicate that a download is currently in progress */
1106 lpwfs->download_in_progress = lpwh;
1109 if (lpwfs->lstnSocket != -1)
1110 closesocket(lpwfs->lstnSocket);
1112 hIC = lpwfs->lpAppInfo;
1113 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1115 INTERNET_ASYNC_RESULT iar;
1119 iar.dwResult = (DWORD)handle;
1120 iar.dwError = ERROR_SUCCESS;
1121 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1122 &iar, sizeof(INTERNET_ASYNC_RESULT));
1125 iar.dwResult = (DWORD)bSuccess;
1126 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1127 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1128 &iar, sizeof(INTERNET_ASYNC_RESULT));
1133 WININET_Release( &lpwh->hdr );
1139 /***********************************************************************
1140 * FtpGetFileA (WININET.@)
1142 * Retrieve file from the FTP server
1149 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1150 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1153 LPWSTR lpwzRemoteFile;
1157 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1158 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1159 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1160 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1161 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1162 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1167 /***********************************************************************
1168 * FtpGetFileW (WININET.@)
1170 * Retrieve file from the FTP server
1177 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1178 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1181 LPWININETFTPSESSIONW lpwfs;
1182 LPWININETAPPINFOW hIC = NULL;
1185 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1186 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1188 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1192 if (lpwfs->download_in_progress != NULL) {
1193 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1197 hIC = lpwfs->lpAppInfo;
1198 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1200 WORKREQUEST workRequest;
1201 struct WORKREQ_FTPGETFILEW *req;
1203 workRequest.asyncall = FTPGETFILEW;
1204 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1205 req = &workRequest.u.FtpGetFileW;
1206 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1207 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1208 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1209 req->fFailIfExists = fFailIfExists;
1210 req->dwFlags = dwInternetFlags;
1211 req->dwContext = dwContext;
1213 r = INTERNET_AsyncCall(&workRequest);
1217 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1218 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1223 WININET_Release( &lpwfs->hdr );
1229 /***********************************************************************
1230 * FTP_FtpGetFileW (Internal)
1232 * Retrieve file from the FTP server
1239 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1240 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1244 BOOL bSuccess = FALSE;
1246 LPWININETAPPINFOW hIC = NULL;
1248 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1250 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1252 /* Clear any error information */
1253 INTERNET_SetLastError(0);
1255 /* Ensure we can write to lpszNewfile by opening it */
1256 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1257 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1258 if (INVALID_HANDLE_VALUE == hFile)
1261 /* Set up socket to retrieve data */
1262 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1268 /* Get data socket to server */
1269 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1274 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1275 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1278 if (nResCode == 226)
1281 FTP_SetResponseError(nResCode);
1283 closesocket(nDataSocket);
1288 if (lpwfs->lstnSocket != -1)
1289 closesocket(lpwfs->lstnSocket);
1294 hIC = lpwfs->lpAppInfo;
1295 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1297 INTERNET_ASYNC_RESULT iar;
1299 iar.dwResult = (DWORD)bSuccess;
1300 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1301 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1302 &iar, sizeof(INTERNET_ASYNC_RESULT));
1308 /***********************************************************************
1309 * FtpGetFileSize (WININET.@)
1311 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1313 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1315 if (lpdwFileSizeHigh)
1316 *lpdwFileSizeHigh = 0;
1321 /***********************************************************************
1322 * FtpDeleteFileA (WININET.@)
1324 * Delete a file on the ftp server
1331 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1333 LPWSTR lpwzFileName;
1336 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1337 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1338 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1342 /***********************************************************************
1343 * FtpDeleteFileW (WININET.@)
1345 * Delete a file on the ftp server
1352 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1354 LPWININETFTPSESSIONW lpwfs;
1355 LPWININETAPPINFOW hIC = NULL;
1358 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1359 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1361 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1365 hIC = lpwfs->lpAppInfo;
1366 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1368 WORKREQUEST workRequest;
1369 struct WORKREQ_FTPDELETEFILEW *req;
1371 workRequest.asyncall = FTPDELETEFILEW;
1372 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1373 req = &workRequest.u.FtpDeleteFileW;
1374 req->lpszFilename = WININET_strdupW(lpszFileName);
1376 r = INTERNET_AsyncCall(&workRequest);
1380 r = FTP_FtpDeleteFileW(lpwfs, lpszFileName);
1385 WININET_Release( &lpwfs->hdr );
1390 /***********************************************************************
1391 * FTP_FtpDeleteFileW (Internal)
1393 * Delete a file on the ftp server
1400 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1403 BOOL bSuccess = FALSE;
1404 LPWININETAPPINFOW hIC = NULL;
1406 TRACE("%p\n", lpwfs);
1408 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1410 /* Clear any error information */
1411 INTERNET_SetLastError(0);
1413 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1416 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1419 if (nResCode == 250)
1422 FTP_SetResponseError(nResCode);
1425 hIC = lpwfs->lpAppInfo;
1426 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1428 INTERNET_ASYNC_RESULT iar;
1430 iar.dwResult = (DWORD)bSuccess;
1431 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1432 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1433 &iar, sizeof(INTERNET_ASYNC_RESULT));
1440 /***********************************************************************
1441 * FtpRemoveDirectoryA (WININET.@)
1443 * Remove a directory on the ftp server
1450 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1452 LPWSTR lpwzDirectory;
1455 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1456 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1457 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1461 /***********************************************************************
1462 * FtpRemoveDirectoryW (WININET.@)
1464 * Remove a directory on the ftp server
1471 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1473 LPWININETFTPSESSIONW lpwfs;
1474 LPWININETAPPINFOW hIC = NULL;
1477 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1478 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1480 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1484 hIC = lpwfs->lpAppInfo;
1485 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1487 WORKREQUEST workRequest;
1488 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1490 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1491 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1492 req = &workRequest.u.FtpRemoveDirectoryW;
1493 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1495 r = INTERNET_AsyncCall(&workRequest);
1499 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1504 WININET_Release( &lpwfs->hdr );
1509 /***********************************************************************
1510 * FTP_FtpRemoveDirectoryW (Internal)
1512 * Remove a directory on the ftp server
1519 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1522 BOOL bSuccess = FALSE;
1523 LPWININETAPPINFOW hIC = NULL;
1527 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1529 /* Clear any error information */
1530 INTERNET_SetLastError(0);
1532 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1535 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1538 if (nResCode == 250)
1541 FTP_SetResponseError(nResCode);
1545 hIC = lpwfs->lpAppInfo;
1546 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1548 INTERNET_ASYNC_RESULT iar;
1550 iar.dwResult = (DWORD)bSuccess;
1551 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1552 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1553 &iar, sizeof(INTERNET_ASYNC_RESULT));
1560 /***********************************************************************
1561 * FtpRenameFileA (WININET.@)
1563 * Rename a file on the ftp server
1570 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1576 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1577 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1578 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1579 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1580 HeapFree(GetProcessHeap(), 0, lpwzDest);
1584 /***********************************************************************
1585 * FtpRenameFileW (WININET.@)
1587 * Rename a file on the ftp server
1594 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1596 LPWININETFTPSESSIONW lpwfs;
1597 LPWININETAPPINFOW hIC = NULL;
1600 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1601 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1603 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1607 hIC = lpwfs->lpAppInfo;
1608 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1610 WORKREQUEST workRequest;
1611 struct WORKREQ_FTPRENAMEFILEW *req;
1613 workRequest.asyncall = FTPRENAMEFILEW;
1614 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1615 req = &workRequest.u.FtpRenameFileW;
1616 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1617 req->lpszDestFile = WININET_strdupW(lpszDest);
1619 r = INTERNET_AsyncCall(&workRequest);
1623 r = FTP_FtpRenameFileW(lpwfs, lpszSrc, lpszDest);
1628 WININET_Release( &lpwfs->hdr );
1633 /***********************************************************************
1634 * FTP_FtpRenameFileW (Internal)
1636 * Rename a file on the ftp server
1643 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1644 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1647 BOOL bSuccess = FALSE;
1648 LPWININETAPPINFOW hIC = NULL;
1652 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1654 /* Clear any error information */
1655 INTERNET_SetLastError(0);
1657 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1660 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1661 if (nResCode == 350)
1663 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1666 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1669 if (nResCode == 250)
1672 FTP_SetResponseError(nResCode);
1675 hIC = lpwfs->lpAppInfo;
1676 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1678 INTERNET_ASYNC_RESULT iar;
1680 iar.dwResult = (DWORD)bSuccess;
1681 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1682 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1683 &iar, sizeof(INTERNET_ASYNC_RESULT));
1689 /***********************************************************************
1690 * FtpCommandA (WININET.@)
1692 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1693 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1695 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1696 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1701 /***********************************************************************
1702 * FtpCommandW (WININET.@)
1704 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1705 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1707 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1708 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1713 /***********************************************************************
1714 * FTP_Connect (internal)
1716 * Connect to a ftp server
1719 * HINTERNET a session handle on success
1724 * Windows uses 'anonymous' as the username, when given a NULL username
1725 * and a NULL password. The password is first looked up in:
1727 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1729 * If this entry is not present it uses the current username as the password.
1733 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1734 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1735 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1736 DWORD dwInternalFlags)
1738 static const WCHAR szKey[] = {'S','o','f','t','w','a','r','e','\\',
1739 'M','i','c','r','o','s','o','f','t','\\',
1740 'W','i','n','d','o','w','s','\\',
1741 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1742 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1743 static const WCHAR szValue[] = {'E','m','a','i','l','N','a','m','e',0};
1744 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1745 static const WCHAR szEmpty[] = {'\0'};
1746 struct sockaddr_in socketAddr;
1749 BOOL bSuccess = FALSE;
1750 LPWININETFTPSESSIONW lpwfs = NULL;
1751 HINTERNET handle = NULL;
1753 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1754 hIC, debugstr_w(lpszServerName),
1755 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1757 assert( hIC->hdr.htype == WH_HINIT );
1759 if (NULL == lpszUserName && NULL != lpszPassword)
1761 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1765 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1768 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1772 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1773 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1775 lpwfs->hdr.htype = WH_HFTPSESSION;
1776 lpwfs->hdr.dwFlags = dwFlags;
1777 lpwfs->hdr.dwContext = dwContext;
1778 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1779 lpwfs->hdr.dwRefCount = 1;
1780 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1781 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1782 lpwfs->download_in_progress = NULL;
1784 WININET_AddRef( &hIC->hdr );
1785 lpwfs->lpAppInfo = hIC;
1787 handle = WININET_AllocHandle( &lpwfs->hdr );
1790 ERR("Failed to alloc handle\n");
1791 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1795 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1796 if(strchrW(hIC->lpszProxy, ' '))
1797 FIXME("Several proxies not implemented.\n");
1798 if(hIC->lpszProxyBypass)
1799 FIXME("Proxy bypass is ignored.\n");
1801 if ( !lpszUserName) {
1803 WCHAR szPassword[MAX_PATH];
1804 DWORD len = sizeof(szPassword);
1806 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1808 RegOpenKeyW(HKEY_CURRENT_USER, szKey, &key);
1809 if (RegQueryValueExW(key, szValue, NULL, NULL, (LPBYTE)szPassword, &len)) {
1810 /* Nothing in the registry, get the username and use that as the password */
1811 if (!GetUserNameW(szPassword, &len)) {
1812 /* Should never get here, but use an empty password as failsafe */
1813 strcpyW(szPassword, szEmpty);
1818 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword));
1819 lpwfs->lpszPassword = WININET_strdupW(szPassword);
1822 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1825 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1827 lpwfs->lpszPassword = WININET_strdupW(szEmpty);
1830 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1831 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1833 INTERNET_ASYNC_RESULT iar;
1835 iar.dwResult = (DWORD)handle;
1836 iar.dwError = ERROR_SUCCESS;
1838 SendAsyncCallback(&hIC->hdr, dwContext,
1839 INTERNET_STATUS_HANDLE_CREATED, &iar,
1840 sizeof(INTERNET_ASYNC_RESULT));
1843 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1844 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1846 if (!GetAddress(lpszServerName, nServerPort, &socketAddr))
1848 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1852 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1853 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1855 nsocket = socket(AF_INET,SOCK_STREAM,0);
1858 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1862 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1863 &socketAddr, sizeof(struct sockaddr_in));
1865 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1867 ERR("Unable to connect (%s)\n", strerror(errno));
1868 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1872 TRACE("Connected to server\n");
1873 lpwfs->sndSocket = nsocket;
1874 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1875 &socketAddr, sizeof(struct sockaddr_in));
1877 sock_namelen = sizeof(lpwfs->socketAddress);
1878 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1880 if (FTP_ConnectToHost(lpwfs))
1882 TRACE("Successfully logged into server\n");
1888 if (!bSuccess && nsocket == -1)
1889 closesocket(nsocket);
1891 if (!bSuccess && lpwfs)
1893 HeapFree(GetProcessHeap(), 0, lpwfs);
1894 WININET_FreeHandle( handle );
1899 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1901 INTERNET_ASYNC_RESULT iar;
1903 iar.dwResult = (DWORD)lpwfs;
1904 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1905 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1906 &iar, sizeof(INTERNET_ASYNC_RESULT));
1913 /***********************************************************************
1914 * FTP_ConnectToHost (internal)
1916 * Connect to a ftp server
1923 static BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1926 BOOL bSuccess = FALSE;
1929 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1931 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1934 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1937 /* Login successful... */
1938 if (nResCode == 230)
1940 /* User name okay, need password... */
1941 else if (nResCode == 331)
1942 bSuccess = FTP_SendPassword(lpwfs);
1943 /* Need account for login... */
1944 else if (nResCode == 332)
1945 bSuccess = FTP_SendAccount(lpwfs);
1947 FTP_SetResponseError(nResCode);
1950 TRACE("Returning %d\n", bSuccess);
1956 /***********************************************************************
1957 * FTP_SendCommandA (internal)
1959 * Send command to server
1966 static BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1967 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1971 DWORD nBytesSent = 0;
1975 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1979 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1982 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1983 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1984 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1986 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1989 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1990 dwParamLen ? lpszParam : "", szCRLF);
1992 TRACE("Sending (%s) len(%d)\n", buf, len);
1993 while((nBytesSent < len) && (nRC != -1))
1995 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1999 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
2003 lpfnStatusCB(hdr->hInternet, dwContext, INTERNET_STATUS_REQUEST_SENT,
2004 &nBytesSent, sizeof(DWORD));
2007 TRACE("Sent %d bytes\n", nBytesSent);
2011 /***********************************************************************
2012 * FTP_SendCommand (internal)
2014 * Send command to server
2021 static BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
2022 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
2025 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
2026 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
2027 HeapFree(GetProcessHeap(), 0, lpszParamA);
2031 /***********************************************************************
2032 * FTP_ReceiveResponse (internal)
2034 * Receive response from server
2037 * Reply code on success
2041 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
2043 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
2046 char firstprefix[5];
2047 BOOL multiline = FALSE;
2048 LPWININETAPPINFOW hIC = NULL;
2050 TRACE("socket(%d)\n", lpwfs->sndSocket);
2052 hIC = lpwfs->lpAppInfo;
2053 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2057 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
2064 if(lpszResponse[3] != '-')
2067 { /* Start of multiline repsonse. Loop until we get "nnn " */
2069 memcpy(firstprefix, lpszResponse, 3);
2070 firstprefix[3] = ' ';
2071 firstprefix[4] = '\0';
2076 if(!memcmp(firstprefix, lpszResponse, 4))
2084 rc = atoi(lpszResponse);
2086 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2087 &nRecv, sizeof(DWORD));
2091 TRACE("return %d\n", rc);
2096 /***********************************************************************
2097 * FTP_SendPassword (internal)
2099 * Send password to ftp server
2106 static BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2109 BOOL bSuccess = FALSE;
2112 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2115 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2118 TRACE("Received reply code %d\n", nResCode);
2119 /* Login successful... */
2120 if (nResCode == 230)
2122 /* Command not implemented, superfluous at the server site... */
2123 /* Need account for login... */
2124 else if (nResCode == 332)
2125 bSuccess = FTP_SendAccount(lpwfs);
2127 FTP_SetResponseError(nResCode);
2131 TRACE("Returning %d\n", bSuccess);
2136 /***********************************************************************
2137 * FTP_SendAccount (internal)
2146 static BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2149 BOOL bSuccess = FALSE;
2152 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2155 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2159 FTP_SetResponseError(nResCode);
2166 /***********************************************************************
2167 * FTP_SendStore (internal)
2169 * Send request to upload file to ftp server
2176 static BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2179 BOOL bSuccess = FALSE;
2182 if (!FTP_InitListenSocket(lpwfs))
2185 if (!FTP_SendType(lpwfs, dwType))
2188 if (!FTP_SendPortOrPasv(lpwfs))
2191 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2193 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2196 if (nResCode == 150 || nResCode == 125)
2199 FTP_SetResponseError(nResCode);
2203 if (!bSuccess && lpwfs->lstnSocket != -1)
2205 closesocket(lpwfs->lstnSocket);
2206 lpwfs->lstnSocket = -1;
2213 /***********************************************************************
2214 * FTP_InitListenSocket (internal)
2216 * Create a socket to listen for server response
2223 static BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2225 BOOL bSuccess = FALSE;
2226 size_t namelen = sizeof(struct sockaddr_in);
2230 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2231 if (lpwfs->lstnSocket == -1)
2233 TRACE("Unable to create listening socket\n");
2237 /* We obtain our ip addr from the name of the command channel socket */
2238 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2240 /* and get the system to assign us a port */
2241 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2243 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2245 TRACE("Unable to bind socket\n");
2249 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2251 TRACE("listen failed\n");
2255 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2259 if (!bSuccess && lpwfs->lstnSocket == -1)
2261 closesocket(lpwfs->lstnSocket);
2262 lpwfs->lstnSocket = -1;
2269 /***********************************************************************
2270 * FTP_SendType (internal)
2272 * Tell server type of data being transferred
2278 * W98SE doesn't cache the type that's currently set
2279 * (i.e. it sends it always),
2280 * so we probably don't want to do that either.
2282 static BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2285 WCHAR type[] = { 'I','\0' };
2286 BOOL bSuccess = FALSE;
2289 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2292 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2295 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2301 FTP_SetResponseError(nResCode);
2308 /***********************************************************************
2309 * FTP_GetFileSize (internal)
2311 * Retrieves from the server the size of the given file
2318 static BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2321 BOOL bSuccess = FALSE;
2325 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2328 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2331 if (nResCode == 213) {
2332 /* Now parses the output to get the actual file size */
2334 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2336 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2337 if (lpszResponseBuffer[i] == '\0') return FALSE;
2338 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2342 FTP_SetResponseError(nResCode);
2351 /***********************************************************************
2352 * FTP_SendPort (internal)
2354 * Tell server which port to use
2361 static BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2363 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2365 WCHAR szIPAddress[64];
2366 BOOL bSuccess = FALSE;
2369 sprintfW(szIPAddress, szIPFormat,
2370 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2371 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2372 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2373 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2374 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2375 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2377 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2380 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2383 if (nResCode == 200)
2386 FTP_SetResponseError(nResCode);
2394 /***********************************************************************
2395 * FTP_DoPassive (internal)
2397 * Tell server that we want to do passive transfers
2398 * and connect data socket
2405 static BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2408 BOOL bSuccess = FALSE;
2411 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2414 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2417 if (nResCode == 227)
2419 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2423 char *pAddr, *pPort;
2425 struct sockaddr_in dataSocketAddress;
2427 p = lpszResponseBuffer+4; /* skip status code */
2429 /* do a very strict check; we can improve that later. */
2431 if (strncmp(p, "Entering Passive Mode", 21))
2433 ERR("unknown response '%.*s', aborting\n", 21, p);
2436 p += 21; /* skip string */
2437 if ((*p++ != ' ') || (*p++ != '('))
2439 ERR("unknown response format, aborting\n");
2443 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2446 ERR("unknown response address format '%s', aborting\n", p);
2449 for (i=0; i < 6; i++)
2452 dataSocketAddress = lpwfs->socketAddress;
2453 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2454 pPort = (char *)&(dataSocketAddress.sin_port);
2462 nsocket = socket(AF_INET,SOCK_STREAM,0);
2466 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2468 ERR("can't connect passive FTP data port.\n");
2469 closesocket(nsocket);
2472 lpwfs->pasvSocket = nsocket;
2476 FTP_SetResponseError(nResCode);
2484 static BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2486 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2488 if (!FTP_DoPassive(lpwfs))
2493 if (!FTP_SendPort(lpwfs))
2500 /***********************************************************************
2501 * FTP_GetDataSocket (internal)
2503 * Either accepts an incoming data socket connection from the server
2504 * or just returns the already opened socket after a PASV command
2505 * in case of passive FTP.
2513 static BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2515 struct sockaddr_in saddr;
2516 size_t addrlen = sizeof(struct sockaddr);
2519 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2521 *nDataSocket = lpwfs->pasvSocket;
2525 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2526 closesocket(lpwfs->lstnSocket);
2527 lpwfs->lstnSocket = -1;
2529 return *nDataSocket != -1;
2533 /***********************************************************************
2534 * FTP_SendData (internal)
2536 * Send data to the server
2543 static BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2545 BY_HANDLE_FILE_INFORMATION fi;
2546 DWORD nBytesRead = 0;
2547 DWORD nBytesSent = 0;
2548 DWORD nTotalSent = 0;
2549 DWORD nBytesToSend, nLen;
2551 time_t s_long_time, e_long_time;
2556 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2557 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2559 /* Get the size of the file. */
2560 GetFileInformationByHandle(hFile, &fi);
2565 nBytesToSend = nBytesRead - nBytesSent;
2567 if (nBytesToSend <= 0)
2569 /* Read data from file. */
2571 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2572 ERR("Failed reading from file\n");
2575 nBytesToSend = nBytesRead;
2580 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2581 DATA_PACKET_SIZE : nBytesToSend;
2582 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2590 /* Do some computation to display the status. */
2592 nSeconds = e_long_time - s_long_time;
2593 if( nSeconds / 60 > 0 )
2595 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2596 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2597 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2601 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2602 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2603 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2605 } while (nRC != -1);
2607 TRACE("file transfer complete!\n");
2609 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2615 /***********************************************************************
2616 * FTP_SendRetrieve (internal)
2618 * Send request to retrieve a file
2621 * Number of bytes to be received on success
2625 static DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2631 if (!FTP_InitListenSocket(lpwfs))
2634 if (!FTP_SendType(lpwfs, dwType))
2637 if (!FTP_SendPortOrPasv(lpwfs))
2640 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2643 TRACE("Waiting to receive %d bytes\n", nResult);
2645 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2648 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2649 if ((nResCode != 125) && (nResCode != 150)) {
2650 /* That means that we got an error getting the file. */
2655 if (0 == nResult && lpwfs->lstnSocket != -1)
2657 closesocket(lpwfs->lstnSocket);
2658 lpwfs->lstnSocket = -1;
2665 /***********************************************************************
2666 * FTP_RetrieveData (internal)
2668 * Retrieve data from server
2675 static BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2677 DWORD nBytesWritten;
2678 DWORD nBytesReceived = 0;
2684 if (INVALID_HANDLE_VALUE == hFile)
2687 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2688 if (NULL == lpszBuffer)
2690 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2694 while (nBytesReceived < nBytes && nRC != -1)
2696 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2699 /* other side closed socket. */
2702 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2703 nBytesReceived += nRC;
2706 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived, nBytes,
2707 nBytesReceived * 100 / nBytes);
2710 TRACE("Data transfer complete\n");
2711 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2718 /***********************************************************************
2719 * FTP_CloseSessionHandle (internal)
2721 * Deallocate session handle
2728 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2730 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2734 WININET_Release(&lpwfs->lpAppInfo->hdr);
2736 if (lpwfs->download_in_progress != NULL)
2737 lpwfs->download_in_progress->session_deleted = TRUE;
2739 if (lpwfs->sndSocket != -1)
2740 closesocket(lpwfs->sndSocket);
2742 if (lpwfs->lstnSocket != -1)
2743 closesocket(lpwfs->lstnSocket);
2745 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2746 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2747 HeapFree(GetProcessHeap(), 0, lpwfs);
2751 /***********************************************************************
2752 * FTP_FindNextFileW (Internal)
2754 * Continues a file search from a previous call to FindFirstFile
2761 BOOL WINAPI FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh, LPVOID lpvFindData)
2763 BOOL bSuccess = TRUE;
2764 LPWIN32_FIND_DATAW lpFindFileData;
2766 TRACE("index(%d) size(%d)\n", lpwh->index, lpwh->size);
2768 assert (lpwh->hdr.htype == WH_HFTPFINDNEXT);
2770 /* Clear any error information */
2771 INTERNET_SetLastError(0);
2773 lpFindFileData = (LPWIN32_FIND_DATAW) lpvFindData;
2774 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAA));
2776 if (lpwh->index >= lpwh->size)
2778 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2783 FTP_ConvertFileProp(&lpwh->lpafp[lpwh->index], lpFindFileData);
2786 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData->cFileName), lpFindFileData->nFileSizeLow);
2790 if (lpwh->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2792 INTERNET_ASYNC_RESULT iar;
2794 iar.dwResult = (DWORD)bSuccess;
2795 iar.dwError = iar.dwError = bSuccess ? ERROR_SUCCESS :
2796 INTERNET_GetLastError();
2798 INTERNET_SendCallback(&lpwh->hdr, lpwh->hdr.dwContext,
2799 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2800 sizeof(INTERNET_ASYNC_RESULT));
2807 /***********************************************************************
2808 * FTP_CloseFindNextHandle (internal)
2810 * Deallocate session handle
2817 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2819 LPWININETFTPFINDNEXTW lpwfn = (LPWININETFTPFINDNEXTW) hdr;
2824 WININET_Release(&lpwfn->lpFtpSession->hdr);
2826 for (i = 0; i < lpwfn->size; i++)
2828 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2831 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2832 HeapFree(GetProcessHeap(), 0, lpwfn);
2835 /***********************************************************************
2836 * FTP_CloseFileTransferHandle (internal)
2838 * Closes the file transfer handle. This also 'cleans' the data queue of
2839 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2842 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2844 LPWININETFTPFILE lpwh = (LPWININETFTPFILE) hdr;
2845 LPWININETFTPSESSIONW lpwfs = lpwh->lpFtpSession;
2850 WININET_Release(&lpwh->lpFtpSession->hdr);
2852 if (!lpwh->session_deleted)
2853 lpwfs->download_in_progress = NULL;
2855 /* This just serves to flush the control socket of any spurrious lines written
2856 to it (like '226 Transfer complete.').
2858 Wonder what to do if the server sends us an error code though...
2860 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2862 if (lpwh->nDataSocket != -1)
2863 closesocket(lpwh->nDataSocket);
2865 HeapFree(GetProcessHeap(), 0, lpwh);
2868 /***********************************************************************
2869 * FTP_ReceiveFileList (internal)
2871 * Read file list from server
2874 * Handle to file list on success
2878 static HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2879 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2882 LPFILEPROPERTIESW lpafp = NULL;
2883 LPWININETFTPFINDNEXTW lpwfn = NULL;
2884 HINTERNET handle = 0;
2886 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2888 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2891 FTP_ConvertFileProp(lpafp, lpFindFileData);
2893 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFTPFINDNEXTW));
2896 lpwfn->hdr.htype = WH_HFTPFINDNEXT;
2897 lpwfn->hdr.dwContext = dwContext;
2898 lpwfn->hdr.dwRefCount = 1;
2899 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2900 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2901 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2902 lpwfn->size = dwSize;
2903 lpwfn->lpafp = lpafp;
2905 WININET_AddRef( &lpwfs->hdr );
2906 lpwfn->lpFtpSession = lpwfs;
2908 handle = WININET_AllocHandle( &lpwfn->hdr );
2913 WININET_Release( &lpwfn->hdr );
2915 TRACE("Matched %d files\n", dwSize);
2920 /***********************************************************************
2921 * FTP_ConvertFileProp (internal)
2923 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2930 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2932 BOOL bSuccess = FALSE;
2934 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2938 /* Convert 'Unix' time to Windows time */
2939 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2940 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2941 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2942 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2944 /* Not all fields are filled in */
2945 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2946 lpFindFileData->nFileSizeLow = lpafp->nSize;
2948 if (lpafp->bIsDirectory)
2949 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2951 if (lpafp->lpszName)
2952 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2960 /***********************************************************************
2961 * FTP_ParseNextFile (internal)
2963 * Parse the next line in file listing
2969 static BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2971 static const char szSpace[] = " \t";
2979 lpfp->lpszName = NULL;
2981 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2984 pszToken = strtok(pszLine, szSpace);
2986 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2989 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2991 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2992 if(!FTP_ParsePermission(pszToken, lpfp))
2993 lpfp->bIsDirectory = FALSE;
2994 for(i=0; i<=3; i++) {
2995 if(!(pszToken = strtok(NULL, szSpace)))
2998 if(!pszToken) continue;
2999 if(lpfp->bIsDirectory) {
3000 TRACE("Is directory\n");
3004 TRACE("Size: %s\n", pszToken);
3005 lpfp->nSize = atol(pszToken);
3008 lpfp->tmLastModified.tm_sec = 0;
3009 lpfp->tmLastModified.tm_min = 0;
3010 lpfp->tmLastModified.tm_hour = 0;
3011 lpfp->tmLastModified.tm_mday = 0;
3012 lpfp->tmLastModified.tm_mon = 0;
3013 lpfp->tmLastModified.tm_year = 0;
3015 /* Determine month */
3016 pszToken = strtok(NULL, szSpace);
3017 if(!pszToken) continue;
3018 if(strlen(pszToken) >= 3) {
3020 if((pszTmp = StrStrIA(szMonths, pszToken)))
3021 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
3024 pszToken = strtok(NULL, szSpace);
3025 if(!pszToken) continue;
3026 lpfp->tmLastModified.tm_mday = atoi(pszToken);
3027 /* Determine time or year */
3028 pszToken = strtok(NULL, szSpace);
3029 if(!pszToken) continue;
3030 if((pszTmp = strchr(pszToken, ':'))) {
3035 lpfp->tmLastModified.tm_min = atoi(pszTmp);
3036 lpfp->tmLastModified.tm_hour = atoi(pszToken);
3038 apTM = localtime(&aTime);
3039 lpfp->tmLastModified.tm_year = apTM->tm_year;
3042 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
3043 lpfp->tmLastModified.tm_hour = 12;
3045 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3046 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3047 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3048 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3050 pszToken = strtok(NULL, szSpace);
3051 if(!pszToken) continue;
3052 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3053 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
3055 /* NT way of parsing ... :
3057 07-13-03 08:55PM <DIR> sakpatch
3058 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3060 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
3061 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
3063 sscanf(pszToken, "%d-%d-%d",
3064 &lpfp->tmLastModified.tm_mon,
3065 &lpfp->tmLastModified.tm_mday,
3066 &lpfp->tmLastModified.tm_year);
3068 /* Hacky and bad Y2K protection :-) */
3069 if (lpfp->tmLastModified.tm_year < 70)
3070 lpfp->tmLastModified.tm_year += 100;
3072 pszToken = strtok(NULL, szSpace);
3073 if(!pszToken) continue;
3074 sscanf(pszToken, "%d:%d",
3075 &lpfp->tmLastModified.tm_hour,
3076 &lpfp->tmLastModified.tm_min);
3077 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
3078 lpfp->tmLastModified.tm_hour += 12;
3080 lpfp->tmLastModified.tm_sec = 0;
3082 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3083 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
3084 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
3085 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
3087 pszToken = strtok(NULL, szSpace);
3088 if(!pszToken) continue;
3089 if(!strcasecmp(pszToken, "<DIR>")) {
3090 lpfp->bIsDirectory = TRUE;
3092 TRACE("Is directory\n");
3095 lpfp->bIsDirectory = FALSE;
3096 lpfp->nSize = atol(pszToken);
3097 TRACE("Size: %d\n", lpfp->nSize);
3100 pszToken = strtok(NULL, szSpace);
3101 if(!pszToken) continue;
3102 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
3103 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
3105 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3106 else if(pszToken[0] == '+') {
3107 FIXME("EPLF Format not implemented\n");
3110 if(lpfp->lpszName) {
3111 if((lpszSearchFile == NULL) ||
3112 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
3114 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
3117 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
3118 lpfp->lpszName = NULL;
3125 /***********************************************************************
3126 * FTP_ParseDirectory (internal)
3128 * Parse string of directory information
3134 static BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
3135 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
3137 BOOL bSuccess = TRUE;
3138 INT sizeFilePropArray = 500;/*20; */
3139 INT indexFilePropArray = -1;
3143 /* Allocate intial file properties array */
3144 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
3149 if (indexFilePropArray+1 >= sizeFilePropArray)
3151 LPFILEPROPERTIESW tmpafp;
3153 sizeFilePropArray *= 2;
3154 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
3155 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3164 indexFilePropArray++;
3165 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3167 if (bSuccess && indexFilePropArray)
3169 if (indexFilePropArray < sizeFilePropArray - 1)
3171 LPFILEPROPERTIESW tmpafp;
3173 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3174 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3178 *dwfp = indexFilePropArray;
3182 HeapFree(GetProcessHeap(), 0, *lpafp);
3183 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3191 /***********************************************************************
3192 * FTP_ParsePermission (internal)
3194 * Parse permission string of directory information
3201 static BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3203 BOOL bSuccess = TRUE;
3204 unsigned short nPermission = 0;
3209 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3215 lpfp->bIsDirectory = (*lpszPermission == 'd');
3221 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3224 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3227 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3230 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3233 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3236 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3239 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3242 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3245 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3249 }while (nPos <= nLast);
3251 lpfp->permissions = nPermission;
3256 /***********************************************************************
3257 * FTP_SetResponseError (internal)
3259 * Set the appropriate error code for a given response from the server
3264 static DWORD FTP_SetResponseError(DWORD dwResponse)
3270 case 421: /* Service not available - Server may be shutting down. */
3271 dwCode = ERROR_INTERNET_TIMEOUT;
3274 case 425: /* Cannot open data connection. */
3275 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3278 case 426: /* Connection closed, transer aborted. */
3279 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3282 case 500: /* Syntax error. Command unrecognized. */
3283 case 501: /* Syntax error. Error in parameters or arguments. */
3284 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3287 case 530: /* Not logged in. Login incorrect. */
3288 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3291 case 550: /* File action not taken. File not found or no access. */
3292 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3295 case 450: /* File action not taken. File may be busy. */
3296 case 451: /* Action aborted. Server error. */
3297 case 452: /* Action not taken. Insufficient storage space on server. */
3298 case 502: /* Command not implemented. */
3299 case 503: /* Bad sequence of command. */
3300 case 504: /* Command not implemented for that parameter. */
3301 case 532: /* Need account for storing files */
3302 case 551: /* Requested action aborted. Page type unknown */
3303 case 552: /* Action aborted. Exceeded storage allocation */
3304 case 553: /* Action not taken. File name not allowed. */
3307 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3311 INTERNET_SetLastError(dwCode);