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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext);
124 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
125 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket);
126 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile);
127 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext);
128 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType);
129 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile);
130 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs);
131 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs);
132 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs);
133 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs);
134 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType);
135 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize);
136 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs);
137 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs);
138 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs);
139 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp);
140 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW fileprop);
141 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
142 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp);
143 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
144 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext);
145 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 BOOL WINAPI FtpPutFileW(HINTERNET hConnect, LPCWSTR lpszLocalFile,
184 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
186 LPWININETFTPSESSIONW lpwfs;
187 LPWININETAPPINFOW hIC = NULL;
190 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
191 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
193 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
197 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
198 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
200 WORKREQUEST workRequest;
201 struct WORKREQ_FTPPUTFILEW *req = &workRequest.u.FtpPutFileW;
203 workRequest.asyncall = FTPPUTFILEW;
204 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
205 req->lpszLocalFile = WININET_strdupW(lpszLocalFile);
206 req->lpszNewRemoteFile = WININET_strdupW(lpszNewRemoteFile);
207 req->dwFlags = dwFlags;
208 req->dwContext = dwContext;
210 r = INTERNET_AsyncCall(&workRequest);
214 r = FTP_FtpPutFileW(lpwfs, lpszLocalFile,
215 lpszNewRemoteFile, dwFlags, dwContext);
220 WININET_Release( &lpwfs->hdr );
225 /***********************************************************************
226 * FTP_FtpPutFileW (Internal)
228 * Uploads a file to the FTP server
235 BOOL WINAPI FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszLocalFile,
236 LPCWSTR lpszNewRemoteFile, DWORD dwFlags, DWORD dwContext)
239 BOOL bSuccess = FALSE;
240 LPWININETAPPINFOW hIC = NULL;
243 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile), debugstr_w(lpszNewRemoteFile));
245 if (!lpszLocalFile || !lpszNewRemoteFile)
247 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
251 assert( WH_HFTPSESSION == lpwfs->hdr.htype);
253 /* Clear any error information */
254 INTERNET_SetLastError(0);
256 /* Open file to be uploaded */
257 if (INVALID_HANDLE_VALUE ==
258 (hFile = CreateFileW(lpszLocalFile, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)))
260 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND);
264 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
265 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
267 if (FTP_SendStore(lpwfs, lpszNewRemoteFile, dwFlags))
271 /* Get data socket to server */
272 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
274 FTP_SendData(lpwfs, nDataSocket, hFile);
275 closesocket(nDataSocket);
276 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
282 FTP_SetResponseError(nResCode);
288 if (lpwfs->lstnSocket != -1)
289 closesocket(lpwfs->lstnSocket);
291 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
293 INTERNET_ASYNC_RESULT iar;
295 iar.dwResult = (DWORD)bSuccess;
296 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
297 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
298 &iar, sizeof(INTERNET_ASYNC_RESULT));
308 /***********************************************************************
309 * FtpSetCurrentDirectoryA (WININET.@)
311 * Change the working directory on the FTP server
318 BOOL WINAPI FtpSetCurrentDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
320 LPWSTR lpwzDirectory;
323 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
324 ret = FtpSetCurrentDirectoryW(hConnect, lpwzDirectory);
325 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
330 /***********************************************************************
331 * FtpSetCurrentDirectoryW (WININET.@)
333 * Change the working directory on the FTP server
340 BOOL WINAPI FtpSetCurrentDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
342 LPWININETFTPSESSIONW lpwfs;
343 LPWININETAPPINFOW hIC = NULL;
346 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
347 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
349 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
353 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
355 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
356 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
358 WORKREQUEST workRequest;
359 struct WORKREQ_FTPSETCURRENTDIRECTORYW *req;
361 workRequest.asyncall = FTPSETCURRENTDIRECTORYW;
362 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
363 req = &workRequest.u.FtpSetCurrentDirectoryW;
364 req->lpszDirectory = WININET_strdupW(lpszDirectory);
366 r = INTERNET_AsyncCall(&workRequest);
370 r = FTP_FtpSetCurrentDirectoryW(lpwfs, lpszDirectory);
375 WININET_Release( &lpwfs->hdr );
381 /***********************************************************************
382 * FTP_FtpSetCurrentDirectoryW (Internal)
384 * Change the working directory on the FTP server
391 BOOL WINAPI FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
394 LPWININETAPPINFOW hIC = NULL;
395 DWORD bSuccess = FALSE;
397 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
399 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
401 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
405 /* Clear any error information */
406 INTERNET_SetLastError(0);
408 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
409 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_CWD, lpszDirectory,
410 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
413 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
420 FTP_SetResponseError(nResCode);
424 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
426 INTERNET_ASYNC_RESULT iar;
428 iar.dwResult = (DWORD)bSuccess;
429 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
430 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
431 &iar, sizeof(INTERNET_ASYNC_RESULT));
437 /***********************************************************************
438 * FtpCreateDirectoryA (WININET.@)
440 * Create new directory on the FTP server
447 BOOL WINAPI FtpCreateDirectoryA(HINTERNET hConnect, LPCSTR lpszDirectory)
449 LPWSTR lpwzDirectory;
452 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
453 ret = FtpCreateDirectoryW(hConnect, lpwzDirectory);
454 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
459 /***********************************************************************
460 * FtpCreateDirectoryW (WININET.@)
462 * Create new directory on the FTP server
469 BOOL WINAPI FtpCreateDirectoryW(HINTERNET hConnect, LPCWSTR lpszDirectory)
471 LPWININETFTPSESSIONW lpwfs;
472 LPWININETAPPINFOW hIC = NULL;
475 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
476 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
478 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
482 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
483 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
485 WORKREQUEST workRequest;
486 struct WORKREQ_FTPCREATEDIRECTORYW *req;
488 workRequest.asyncall = FTPCREATEDIRECTORYW;
489 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
490 req = &workRequest.u.FtpCreateDirectoryW;
491 req->lpszDirectory = WININET_strdupW(lpszDirectory);
493 r = INTERNET_AsyncCall(&workRequest);
497 r = FTP_FtpCreateDirectoryW(lpwfs, lpszDirectory);
501 WININET_Release( &lpwfs->hdr );
507 /***********************************************************************
508 * FTP_FtpCreateDirectoryW (Internal)
510 * Create new directory on the FTP server
517 BOOL WINAPI FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
520 BOOL bSuccess = FALSE;
521 LPWININETAPPINFOW hIC = NULL;
523 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory));
525 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
527 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
531 /* Clear any error information */
532 INTERNET_SetLastError(0);
534 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_MKD, lpszDirectory, 0, 0, 0))
537 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
543 FTP_SetResponseError(nResCode);
547 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
548 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
550 INTERNET_ASYNC_RESULT iar;
552 iar.dwResult = (DWORD)bSuccess;
553 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
554 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
555 &iar, sizeof(INTERNET_ASYNC_RESULT));
561 /***********************************************************************
562 * FtpFindFirstFileA (WININET.@)
564 * Search the specified directory
567 * HINTERNET on success
571 HINTERNET WINAPI FtpFindFirstFileA(HINTERNET hConnect,
572 LPCSTR lpszSearchFile, LPWIN32_FIND_DATAA lpFindFileData, DWORD dwFlags, DWORD dwContext)
574 LPWSTR lpwzSearchFile;
575 WIN32_FIND_DATAW wfd;
576 LPWIN32_FIND_DATAW lpFindFileDataW;
579 lpwzSearchFile = lpszSearchFile?WININET_strdup_AtoW(lpszSearchFile):NULL;
580 lpFindFileDataW = lpFindFileData?&wfd:NULL;
581 ret = FtpFindFirstFileW(hConnect, lpwzSearchFile, lpFindFileDataW, dwFlags, dwContext);
582 HeapFree(GetProcessHeap(), 0, lpwzSearchFile);
585 WININET_find_data_WtoA(lpFindFileDataW, lpFindFileData);
591 /***********************************************************************
592 * FtpFindFirstFileW (WININET.@)
594 * Search the specified directory
597 * HINTERNET on success
601 HINTERNET WINAPI FtpFindFirstFileW(HINTERNET hConnect,
602 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
604 LPWININETFTPSESSIONW lpwfs;
605 LPWININETAPPINFOW hIC = NULL;
608 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hConnect );
609 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
611 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
615 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
616 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
618 WORKREQUEST workRequest;
619 struct WORKREQ_FTPFINDFIRSTFILEW *req;
621 workRequest.asyncall = FTPFINDFIRSTFILEW;
622 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
623 req = &workRequest.u.FtpFindFirstFileW;
624 req->lpszSearchFile = (lpszSearchFile == NULL) ? NULL : WININET_strdupW(lpszSearchFile);
625 req->lpFindFileData = lpFindFileData;
626 req->dwFlags = dwFlags;
627 req->dwContext= dwContext;
629 INTERNET_AsyncCall(&workRequest);
634 r = FTP_FtpFindFirstFileW(lpwfs, lpszSearchFile, lpFindFileData,
639 WININET_Release( &lpwfs->hdr );
645 /***********************************************************************
646 * FTP_FtpFindFirstFileW (Internal)
648 * Search the specified directory
651 * HINTERNET on success
655 HINTERNET WINAPI FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs,
656 LPCWSTR lpszSearchFile, LPWIN32_FIND_DATAW lpFindFileData, DWORD dwFlags, DWORD dwContext)
659 LPWININETAPPINFOW hIC = NULL;
660 HINTERNET hFindNext = NULL;
664 assert(WH_HFTPSESSION == lpwfs->hdr.htype);
666 /* Clear any error information */
667 INTERNET_SetLastError(0);
669 if (!FTP_InitListenSocket(lpwfs))
672 if (!FTP_SendType(lpwfs, INTERNET_FLAG_TRANSFER_ASCII))
675 if (!FTP_SendPortOrPasv(lpwfs))
678 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
679 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_LIST, NULL,
680 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
683 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
686 if (nResCode == 125 || nResCode == 150)
690 /* Get data socket to server */
691 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
693 hFindNext = FTP_ReceiveFileList(lpwfs, nDataSocket, lpszSearchFile, lpFindFileData, dwContext);
694 closesocket(nDataSocket);
695 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
696 if (nResCode != 226 && nResCode != 250)
697 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
701 FTP_SetResponseError(nResCode);
705 if (lpwfs->lstnSocket != -1)
706 closesocket(lpwfs->lstnSocket);
708 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
710 INTERNET_ASYNC_RESULT iar;
714 iar.dwResult = (DWORD)hFindNext;
715 iar.dwError = ERROR_SUCCESS;
716 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
717 &iar, sizeof(INTERNET_ASYNC_RESULT));
720 iar.dwResult = (DWORD)hFindNext;
721 iar.dwError = hFindNext ? ERROR_SUCCESS : INTERNET_GetLastError();
722 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
723 &iar, sizeof(INTERNET_ASYNC_RESULT));
730 /***********************************************************************
731 * FtpGetCurrentDirectoryA (WININET.@)
733 * Retrieves the current directory
740 BOOL WINAPI FtpGetCurrentDirectoryA(HINTERNET hFtpSession, LPSTR lpszCurrentDirectory,
741 LPDWORD lpdwCurrentDirectory)
747 if(lpdwCurrentDirectory) len = *lpdwCurrentDirectory;
748 ret = FtpGetCurrentDirectoryW(hFtpSession, lpszCurrentDirectory?dir:NULL, lpdwCurrentDirectory?&len:NULL);
749 if(lpdwCurrentDirectory) {
750 *lpdwCurrentDirectory = len;
751 if(lpszCurrentDirectory)
752 WideCharToMultiByte(CP_ACP, 0, dir, len, lpszCurrentDirectory, *lpdwCurrentDirectory, NULL, NULL);
758 /***********************************************************************
759 * FtpGetCurrentDirectoryW (WININET.@)
761 * Retrieves the current directory
768 BOOL WINAPI FtpGetCurrentDirectoryW(HINTERNET hFtpSession, LPWSTR lpszCurrentDirectory,
769 LPDWORD lpdwCurrentDirectory)
771 LPWININETFTPSESSIONW lpwfs;
772 LPWININETAPPINFOW hIC = NULL;
775 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
777 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
778 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
780 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
784 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
785 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
787 WORKREQUEST workRequest;
788 struct WORKREQ_FTPGETCURRENTDIRECTORYW *req;
790 workRequest.asyncall = FTPGETCURRENTDIRECTORYW;
791 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
792 req = &workRequest.u.FtpGetCurrentDirectoryW;
793 req->lpszDirectory = lpszCurrentDirectory;
794 req->lpdwDirectory = lpdwCurrentDirectory;
796 r = INTERNET_AsyncCall(&workRequest);
800 r = FTP_FtpGetCurrentDirectoryW(lpwfs, lpszCurrentDirectory,
801 lpdwCurrentDirectory);
806 WININET_Release( &lpwfs->hdr );
812 /***********************************************************************
813 * FTP_FtpGetCurrentDirectoryA (Internal)
815 * Retrieves the current directory
822 BOOL WINAPI FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs, LPWSTR lpszCurrentDirectory,
823 LPDWORD lpdwCurrentDirectory)
826 LPWININETAPPINFOW hIC = NULL;
827 DWORD bSuccess = FALSE;
829 TRACE("len(%ld)\n", *lpdwCurrentDirectory);
831 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
833 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
837 /* Clear any error information */
838 INTERNET_SetLastError(0);
840 ZeroMemory(lpszCurrentDirectory, *lpdwCurrentDirectory);
842 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
843 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PWD, NULL,
844 lpwfs->hdr.lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
847 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
850 if (nResCode == 257) /* Extract directory name */
852 DWORD firstpos, lastpos, len;
853 LPWSTR lpszResponseBuffer = WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
855 for (firstpos = 0, lastpos = 0; lpszResponseBuffer[lastpos]; lastpos++)
857 if ('"' == lpszResponseBuffer[lastpos])
866 len = lastpos - firstpos - 1;
867 strncpyW(lpszCurrentDirectory, &lpszResponseBuffer[firstpos+1],
868 len < *lpdwCurrentDirectory ? len : *lpdwCurrentDirectory);
869 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer);
870 *lpdwCurrentDirectory = len;
874 FTP_SetResponseError(nResCode);
878 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
880 INTERNET_ASYNC_RESULT iar;
882 iar.dwResult = (DWORD)bSuccess;
883 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
884 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
885 &iar, sizeof(INTERNET_ASYNC_RESULT));
888 return (DWORD) bSuccess;
891 /***********************************************************************
892 * FtpOpenFileA (WININET.@)
894 * Open a remote file for writing or reading
897 * HINTERNET handle on success
901 HINTERNET WINAPI FtpOpenFileA(HINTERNET hFtpSession,
902 LPCSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
908 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
909 ret = FtpOpenFileW(hFtpSession, lpwzFileName, fdwAccess, dwFlags, dwContext);
910 HeapFree(GetProcessHeap(), 0, lpwzFileName);
915 /***********************************************************************
916 * FtpOpenFileW (WININET.@)
918 * Open a remote file for writing or reading
921 * HINTERNET handle on success
925 HINTERNET WINAPI FtpOpenFileW(HINTERNET hFtpSession,
926 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
929 LPWININETFTPSESSIONW lpwfs;
930 LPWININETAPPINFOW hIC = NULL;
933 TRACE("(%p,%s,0x%08lx,0x%08lx,0x%08lx)\n", hFtpSession,
934 debugstr_w(lpszFileName), fdwAccess, dwFlags, dwContext);
936 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
937 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
939 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
943 if (lpwfs->download_in_progress != NULL) {
944 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
947 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
948 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
950 WORKREQUEST workRequest;
951 struct WORKREQ_FTPOPENFILEW *req;
953 workRequest.asyncall = FTPOPENFILEW;
954 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
955 req = &workRequest.u.FtpOpenFileW;
956 req->lpszFilename = WININET_strdupW(lpszFileName);
957 req->dwAccess = fdwAccess;
958 req->dwFlags = dwFlags;
959 req->dwContext = dwContext;
961 INTERNET_AsyncCall(&workRequest);
966 r = FTP_FtpOpenFileW(lpwfs, lpszFileName, fdwAccess, dwFlags, dwContext);
971 WININET_Release( &lpwfs->hdr );
977 /***********************************************************************
978 * FTP_FtpOpenFileW (Internal)
980 * Open a remote file for writing or reading
983 * HINTERNET handle on success
987 HINTERNET FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs,
988 LPCWSTR lpszFileName, DWORD fdwAccess, DWORD dwFlags,
992 BOOL bSuccess = FALSE;
993 LPWININETFILE lpwh = NULL;
994 LPWININETAPPINFOW hIC = NULL;
995 HINTERNET handle = NULL;
999 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1001 /* Clear any error information */
1002 INTERNET_SetLastError(0);
1004 if (GENERIC_READ == fdwAccess)
1006 /* Set up socket to retrieve data */
1007 bSuccess = FTP_SendRetrieve(lpwfs, lpszFileName, dwFlags);
1009 else if (GENERIC_WRITE == fdwAccess)
1011 /* Set up socket to send data */
1012 bSuccess = FTP_SendStore(lpwfs, lpszFileName, dwFlags);
1015 /* Get data socket to server */
1016 if (bSuccess && FTP_GetDataSocket(lpwfs, &nDataSocket))
1018 lpwh = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE));
1019 lpwh->hdr.htype = WH_HFILE;
1020 lpwh->hdr.dwFlags = dwFlags;
1021 lpwh->hdr.dwContext = dwContext;
1022 lpwh->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
1023 lpwh->hdr.dwRefCount = 1;
1024 lpwh->hdr.destroy = FTP_CloseFileTransferHandle;
1025 lpwh->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
1026 lpwh->nDataSocket = nDataSocket;
1027 lpwh->session_deleted = FALSE;
1029 handle = WININET_AllocHandle( &lpwh->hdr );
1033 /* Indicate that a download is currently in progress */
1034 lpwfs->download_in_progress = lpwh;
1037 if (lpwfs->lstnSocket != -1)
1038 closesocket(lpwfs->lstnSocket);
1040 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1041 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1043 INTERNET_ASYNC_RESULT iar;
1047 iar.dwResult = (DWORD)handle;
1048 iar.dwError = ERROR_SUCCESS;
1049 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1050 &iar, sizeof(INTERNET_ASYNC_RESULT));
1053 iar.dwResult = (DWORD)bSuccess;
1054 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1055 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1056 &iar, sizeof(INTERNET_ASYNC_RESULT));
1061 WININET_Release( &lpwh->hdr );
1067 /***********************************************************************
1068 * FtpGetFileA (WININET.@)
1070 * Retrieve file from the FTP server
1077 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1078 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1081 LPWSTR lpwzRemoteFile;
1085 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1086 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1087 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1088 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1089 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1090 HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1095 /***********************************************************************
1096 * FtpGetFileW (WININET.@)
1098 * Retrieve file from the FTP server
1105 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1106 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1109 LPWININETFTPSESSIONW lpwfs;
1110 LPWININETAPPINFOW hIC = NULL;
1113 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1114 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1116 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1120 if (lpwfs->download_in_progress != NULL) {
1121 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1125 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1126 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1128 WORKREQUEST workRequest;
1129 struct WORKREQ_FTPGETFILEW *req;
1131 workRequest.asyncall = FTPGETFILEW;
1132 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1133 req = &workRequest.u.FtpGetFileW;
1134 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1135 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1136 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1137 req->fFailIfExists = fFailIfExists;
1138 req->dwFlags = dwInternetFlags;
1139 req->dwContext = dwContext;
1141 r = INTERNET_AsyncCall(&workRequest);
1145 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1146 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1151 WININET_Release( &lpwfs->hdr );
1157 /***********************************************************************
1158 * FTP_FtpGetFileW (Internal)
1160 * Retrieve file from the FTP server
1167 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1168 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1172 BOOL bSuccess = FALSE;
1174 LPWININETAPPINFOW hIC = NULL;
1176 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1178 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1180 /* Clear any error information */
1181 INTERNET_SetLastError(0);
1183 /* Ensure we can write to lpszNewfile by opening it */
1184 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1185 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1186 if (INVALID_HANDLE_VALUE == hFile)
1189 /* Set up socket to retrieve data */
1190 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1196 /* Get data socket to server */
1197 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1202 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1203 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1206 if (nResCode == 226)
1209 FTP_SetResponseError(nResCode);
1211 closesocket(nDataSocket);
1216 if (lpwfs->lstnSocket != -1)
1217 closesocket(lpwfs->lstnSocket);
1222 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1223 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1225 INTERNET_ASYNC_RESULT iar;
1227 iar.dwResult = (DWORD)bSuccess;
1228 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1229 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1230 &iar, sizeof(INTERNET_ASYNC_RESULT));
1236 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1238 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1240 if (lpdwFileSizeHigh)
1241 *lpdwFileSizeHigh = 0;
1246 /***********************************************************************
1247 * FtpDeleteFileA (WININET.@)
1249 * Delete a file on the ftp server
1256 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1258 LPWSTR lpwzFileName;
1261 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1262 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1263 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1267 /***********************************************************************
1268 * FtpDeleteFileW (WININET.@)
1270 * Delete a file on the ftp server
1277 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1279 LPWININETFTPSESSIONW lpwfs;
1280 LPWININETAPPINFOW hIC = NULL;
1283 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1284 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1286 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1290 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1291 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1293 WORKREQUEST workRequest;
1294 struct WORKREQ_FTPDELETEFILEW *req;
1296 workRequest.asyncall = FTPDELETEFILEW;
1297 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1298 req = &workRequest.u.FtpDeleteFileW;
1299 req->lpszFilename = WININET_strdupW(lpszFileName);
1301 r = INTERNET_AsyncCall(&workRequest);
1305 r = FTP_FtpDeleteFileW(hFtpSession, lpszFileName);
1310 WININET_Release( &lpwfs->hdr );
1315 /***********************************************************************
1316 * FTP_FtpDeleteFileW (Internal)
1318 * Delete a file on the ftp server
1325 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1328 BOOL bSuccess = FALSE;
1329 LPWININETAPPINFOW hIC = NULL;
1331 TRACE("%p\n", lpwfs);
1333 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1335 /* Clear any error information */
1336 INTERNET_SetLastError(0);
1338 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1341 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1344 if (nResCode == 250)
1347 FTP_SetResponseError(nResCode);
1350 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1351 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1353 INTERNET_ASYNC_RESULT iar;
1355 iar.dwResult = (DWORD)bSuccess;
1356 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1357 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1358 &iar, sizeof(INTERNET_ASYNC_RESULT));
1365 /***********************************************************************
1366 * FtpRemoveDirectoryA (WININET.@)
1368 * Remove a directory on the ftp server
1375 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1377 LPWSTR lpwzDirectory;
1380 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1381 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1382 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1386 /***********************************************************************
1387 * FtpRemoveDirectoryW (WININET.@)
1389 * Remove a directory on the ftp server
1396 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1398 LPWININETFTPSESSIONW lpwfs;
1399 LPWININETAPPINFOW hIC = NULL;
1402 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1403 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1405 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1409 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1410 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1412 WORKREQUEST workRequest;
1413 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1415 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1416 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1417 req = &workRequest.u.FtpRemoveDirectoryW;
1418 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1420 r = INTERNET_AsyncCall(&workRequest);
1424 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1429 WININET_Release( &lpwfs->hdr );
1434 /***********************************************************************
1435 * FTP_FtpRemoveDirectoryW (Internal)
1437 * Remove a directory on the ftp server
1444 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1447 BOOL bSuccess = FALSE;
1448 LPWININETAPPINFOW hIC = NULL;
1452 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1454 /* Clear any error information */
1455 INTERNET_SetLastError(0);
1457 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1460 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1463 if (nResCode == 250)
1466 FTP_SetResponseError(nResCode);
1470 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1471 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1473 INTERNET_ASYNC_RESULT iar;
1475 iar.dwResult = (DWORD)bSuccess;
1476 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1477 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1478 &iar, sizeof(INTERNET_ASYNC_RESULT));
1485 /***********************************************************************
1486 * FtpRenameFileA (WININET.@)
1488 * Rename a file on the ftp server
1495 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1501 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1502 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1503 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1504 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1505 HeapFree(GetProcessHeap(), 0, lpwzDest);
1509 /***********************************************************************
1510 * FtpRenameFileW (WININET.@)
1512 * Rename a file on the ftp server
1519 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1521 LPWININETFTPSESSIONW lpwfs;
1522 LPWININETAPPINFOW hIC = NULL;
1525 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1526 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1528 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1532 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1533 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1535 WORKREQUEST workRequest;
1536 struct WORKREQ_FTPRENAMEFILEW *req;
1538 workRequest.asyncall = FTPRENAMEFILEW;
1539 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1540 req = &workRequest.u.FtpRenameFileW;
1541 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1542 req->lpszDestFile = WININET_strdupW(lpszDest);
1544 r = INTERNET_AsyncCall(&workRequest);
1548 r = FTP_FtpRenameFileW(hFtpSession, lpszSrc, lpszDest);
1553 WININET_Release( &lpwfs->hdr );
1558 /***********************************************************************
1559 * FTP_FtpRenameFileA (Internal)
1561 * Rename a file on the ftp server
1568 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1569 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1572 BOOL bSuccess = FALSE;
1573 LPWININETAPPINFOW hIC = NULL;
1577 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1579 /* Clear any error information */
1580 INTERNET_SetLastError(0);
1582 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1585 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1586 if (nResCode == 350)
1588 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1591 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1594 if (nResCode == 250)
1597 FTP_SetResponseError(nResCode);
1600 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1601 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1603 INTERNET_ASYNC_RESULT iar;
1605 iar.dwResult = (DWORD)bSuccess;
1606 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1607 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1608 &iar, sizeof(INTERNET_ASYNC_RESULT));
1614 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1615 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1617 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1618 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1623 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1624 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1626 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1627 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1632 /***********************************************************************
1633 * FTP_Connect (internal)
1635 * Connect to a ftp server
1638 * HINTERNET a session handle on success
1643 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1644 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1645 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1646 DWORD dwInternalFlags)
1648 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1649 static const WCHAR szDefaultPassword[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1650 struct sockaddr_in socketAddr;
1651 struct hostent *phe = NULL;
1654 BOOL bSuccess = FALSE;
1655 LPWININETFTPSESSIONW lpwfs = NULL;
1656 HINTERNET handle = NULL;
1658 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1659 hIC, debugstr_w(lpszServerName),
1660 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1662 assert( hIC->hdr.htype == WH_HINIT );
1664 if (NULL == lpszUserName && NULL != lpszPassword)
1666 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1670 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1673 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1677 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1678 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1680 lpwfs->hdr.htype = WH_HFTPSESSION;
1681 lpwfs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1682 lpwfs->hdr.dwFlags = dwFlags;
1683 lpwfs->hdr.dwContext = dwContext;
1684 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1685 lpwfs->hdr.dwRefCount = 1;
1686 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1687 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1688 lpwfs->download_in_progress = NULL;
1690 handle = WININET_AllocHandle( &lpwfs->hdr );
1693 ERR("Failed to alloc handle\n");
1694 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1698 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1699 if(strchrW(hIC->lpszProxy, ' '))
1700 FIXME("Several proxies not implemented.\n");
1701 if(hIC->lpszProxyBypass)
1702 FIXME("Proxy bypass is ignored.\n");
1704 if ( !lpszUserName) {
1705 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1706 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1709 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1710 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1713 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1714 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1716 INTERNET_ASYNC_RESULT iar;
1718 iar.dwResult = (DWORD)handle;
1719 iar.dwError = ERROR_SUCCESS;
1721 SendAsyncCallback(&hIC->hdr, dwContext,
1722 INTERNET_STATUS_HANDLE_CREATED, &iar,
1723 sizeof(INTERNET_ASYNC_RESULT));
1726 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1727 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1729 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1731 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1735 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1736 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1738 nsocket = socket(AF_INET,SOCK_STREAM,0);
1741 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1745 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1746 &socketAddr, sizeof(struct sockaddr_in));
1748 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1750 ERR("Unable to connect (%s)\n", strerror(errno));
1751 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1755 TRACE("Connected to server\n");
1756 lpwfs->sndSocket = nsocket;
1757 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1758 &socketAddr, sizeof(struct sockaddr_in));
1760 sock_namelen = sizeof(lpwfs->socketAddress);
1761 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1762 lpwfs->phostent = phe;
1764 if (FTP_ConnectToHost(lpwfs))
1766 TRACE("Successfully logged into server\n");
1772 if (!bSuccess && nsocket == -1)
1773 closesocket(nsocket);
1775 if (!bSuccess && lpwfs)
1777 HeapFree(GetProcessHeap(), 0, lpwfs);
1778 WININET_FreeHandle( handle );
1782 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1784 INTERNET_ASYNC_RESULT iar;
1786 iar.dwResult = (DWORD)lpwfs;
1787 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1788 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1789 &iar, sizeof(INTERNET_ASYNC_RESULT));
1796 /***********************************************************************
1797 * FTP_ConnectToHost (internal)
1799 * Connect to a ftp server
1806 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1809 BOOL bSuccess = FALSE;
1812 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1814 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1817 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1820 /* Login successful... */
1821 if (nResCode == 230)
1823 /* User name okay, need password... */
1824 else if (nResCode == 331)
1825 bSuccess = FTP_SendPassword(lpwfs);
1826 /* Need account for login... */
1827 else if (nResCode == 332)
1828 bSuccess = FTP_SendAccount(lpwfs);
1830 FTP_SetResponseError(nResCode);
1833 TRACE("Returning %d\n", bSuccess);
1839 /***********************************************************************
1840 * FTP_SendCommandA (internal)
1842 * Send command to server
1849 BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1850 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1854 DWORD nBytesSent = 0;
1858 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1862 HINTERNET hHandle = WININET_FindHandle( hdr );
1865 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1866 WININET_Release( hdr );
1870 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1871 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1872 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1874 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1877 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1878 dwParamLen ? lpszParam : "", szCRLF);
1880 TRACE("Sending (%s) len(%ld)\n", buf, len);
1881 while((nBytesSent < len) && (nRC != -1))
1883 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1887 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1891 HINTERNET hHandle = WININET_FindHandle( hdr );
1894 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1895 &nBytesSent, sizeof(DWORD));
1896 WININET_Release( hdr );
1900 TRACE("Sent %ld bytes\n", nBytesSent);
1904 /***********************************************************************
1905 * FTP_SendCommand (internal)
1907 * Send command to server
1914 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1915 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1918 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1919 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
1920 HeapFree(GetProcessHeap(), 0, lpszParamA);
1924 /***********************************************************************
1925 * FTP_ReceiveResponse (internal)
1927 * Receive response from server
1930 * Reply code on success
1934 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1936 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1939 char firstprefix[5];
1940 BOOL multiline = FALSE;
1941 LPWININETAPPINFOW hIC = NULL;
1943 TRACE("socket(%d) \n", lpwfs->sndSocket);
1945 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1946 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1950 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1957 if(lpszResponse[3] != '-')
1960 { /* Start of multiline repsonse. Loop until we get "nnn " */
1962 memcpy(firstprefix, lpszResponse, 3);
1963 firstprefix[3] = ' ';
1964 firstprefix[4] = '\0';
1969 if(!memcmp(firstprefix, lpszResponse, 4))
1977 rc = atoi(lpszResponse);
1979 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1980 &nRecv, sizeof(DWORD));
1984 TRACE("return %d\n", rc);
1989 /***********************************************************************
1990 * FTP_SendPassword (internal)
1992 * Send password to ftp server
1999 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2002 BOOL bSuccess = FALSE;
2005 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2008 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2011 TRACE("Received reply code %d\n", nResCode);
2012 /* Login successful... */
2013 if (nResCode == 230)
2015 /* Command not implemented, superfluous at the server site... */
2016 /* Need account for login... */
2017 else if (nResCode == 332)
2018 bSuccess = FTP_SendAccount(lpwfs);
2020 FTP_SetResponseError(nResCode);
2024 TRACE("Returning %d\n", bSuccess);
2029 /***********************************************************************
2030 * FTP_SendAccount (internal)
2039 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2042 BOOL bSuccess = FALSE;
2045 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2048 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2052 FTP_SetResponseError(nResCode);
2059 /***********************************************************************
2060 * FTP_SendStore (internal)
2062 * Send request to upload file to ftp server
2069 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2072 BOOL bSuccess = FALSE;
2075 if (!FTP_InitListenSocket(lpwfs))
2078 if (!FTP_SendType(lpwfs, dwType))
2081 if (!FTP_SendPortOrPasv(lpwfs))
2084 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2086 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2089 if (nResCode == 150)
2092 FTP_SetResponseError(nResCode);
2096 if (!bSuccess && lpwfs->lstnSocket != -1)
2098 closesocket(lpwfs->lstnSocket);
2099 lpwfs->lstnSocket = -1;
2106 /***********************************************************************
2107 * FTP_InitListenSocket (internal)
2109 * Create a socket to listen for server response
2116 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2118 BOOL bSuccess = FALSE;
2119 size_t namelen = sizeof(struct sockaddr_in);
2123 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2124 if (lpwfs->lstnSocket == -1)
2126 TRACE("Unable to create listening socket\n");
2130 /* We obtain our ip addr from the name of the command channel socket */
2131 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2133 /* and get the system to assign us a port */
2134 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2136 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2138 TRACE("Unable to bind socket\n");
2142 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2144 TRACE("listen failed\n");
2148 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2152 if (!bSuccess && lpwfs->lstnSocket == -1)
2154 closesocket(lpwfs->lstnSocket);
2155 lpwfs->lstnSocket = -1;
2162 /***********************************************************************
2163 * FTP_SendType (internal)
2165 * Tell server type of data being transferred
2171 * W98SE doesn't cache the type that's currently set
2172 * (i.e. it sends it always),
2173 * so we probably don't want to do that either.
2175 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2178 WCHAR type[] = { 'I','\0' };
2179 BOOL bSuccess = FALSE;
2182 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2185 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2188 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2194 FTP_SetResponseError(nResCode);
2201 /***********************************************************************
2202 * FTP_GetFileSize (internal)
2204 * Retrieves from the server the size of the given file
2211 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2214 BOOL bSuccess = FALSE;
2218 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2221 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2224 if (nResCode == 213) {
2225 /* Now parses the output to get the actual file size */
2227 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2229 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2230 if (lpszResponseBuffer[i] == '\0') return FALSE;
2231 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2235 FTP_SetResponseError(nResCode);
2244 /***********************************************************************
2245 * FTP_SendPort (internal)
2247 * Tell server which port to use
2254 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2256 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2258 WCHAR szIPAddress[64];
2259 BOOL bSuccess = FALSE;
2262 sprintfW(szIPAddress, szIPFormat,
2263 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2264 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2265 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2266 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2267 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2268 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2270 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2273 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2276 if (nResCode == 200)
2279 FTP_SetResponseError(nResCode);
2287 /***********************************************************************
2288 * FTP_DoPassive (internal)
2290 * Tell server that we want to do passive transfers
2291 * and connect data socket
2298 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2301 BOOL bSuccess = FALSE;
2304 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2307 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2310 if (nResCode == 227)
2312 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2316 char *pAddr, *pPort;
2318 struct sockaddr_in dataSocketAddress;
2320 p = lpszResponseBuffer+4; /* skip status code */
2322 /* do a very strict check; we can improve that later. */
2324 if (strncmp(p, "Entering Passive Mode", 21))
2326 ERR("unknown response '%.*s', aborting\n", 21, p);
2329 p += 21; /* skip string */
2330 if ((*p++ != ' ') || (*p++ != '('))
2332 ERR("unknown response format, aborting\n");
2336 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2339 ERR("unknown response address format '%s', aborting\n", p);
2342 for (i=0; i < 6; i++)
2345 dataSocketAddress = lpwfs->socketAddress;
2346 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2347 pPort = (char *)&(dataSocketAddress.sin_port);
2355 nsocket = socket(AF_INET,SOCK_STREAM,0);
2359 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2361 ERR("can't connect passive FTP data port.\n");
2364 lpwfs->pasvSocket = nsocket;
2368 FTP_SetResponseError(nResCode);
2376 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2378 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2380 if (!FTP_DoPassive(lpwfs))
2385 if (!FTP_SendPort(lpwfs))
2392 /***********************************************************************
2393 * FTP_GetDataSocket (internal)
2395 * Either accepts an incoming data socket connection from the server
2396 * or just returns the already opened socket after a PASV command
2397 * in case of passive FTP.
2405 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2407 struct sockaddr_in saddr;
2408 size_t addrlen = sizeof(struct sockaddr);
2411 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2413 *nDataSocket = lpwfs->pasvSocket;
2417 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2418 closesocket(lpwfs->lstnSocket);
2419 lpwfs->lstnSocket = -1;
2421 return *nDataSocket != -1;
2425 /***********************************************************************
2426 * FTP_SendData (internal)
2428 * Send data to the server
2435 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2437 BY_HANDLE_FILE_INFORMATION fi;
2438 DWORD nBytesRead = 0;
2439 DWORD nBytesSent = 0;
2440 DWORD nTotalSent = 0;
2441 DWORD nBytesToSend, nLen;
2443 time_t s_long_time, e_long_time;
2448 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2449 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2451 /* Get the size of the file. */
2452 GetFileInformationByHandle(hFile, &fi);
2457 nBytesToSend = nBytesRead - nBytesSent;
2459 if (nBytesToSend <= 0)
2461 /* Read data from file. */
2463 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2464 ERR("Failed reading from file\n");
2467 nBytesToSend = nBytesRead;
2472 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2473 DATA_PACKET_SIZE : nBytesToSend;
2474 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2482 /* Do some computation to display the status. */
2484 nSeconds = e_long_time - s_long_time;
2485 if( nSeconds / 60 > 0 )
2487 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2488 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2489 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2493 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2494 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2495 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2497 } while (nRC != -1);
2499 TRACE("file transfer complete!\n");
2501 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2507 /***********************************************************************
2508 * FTP_SendRetrieve (internal)
2510 * Send request to retrieve a file
2513 * Number of bytes to be received on success
2517 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2523 if (!FTP_InitListenSocket(lpwfs))
2526 if (!FTP_SendType(lpwfs, dwType))
2529 if (!FTP_SendPortOrPasv(lpwfs))
2532 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2535 TRACE("Waiting to receive %ld bytes\n", nResult);
2537 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2540 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2541 if ((nResCode != 125) && (nResCode != 150)) {
2542 /* That means that we got an error getting the file. */
2547 if (0 == nResult && lpwfs->lstnSocket != -1)
2549 closesocket(lpwfs->lstnSocket);
2550 lpwfs->lstnSocket = -1;
2557 /***********************************************************************
2558 * FTP_RetrieveData (internal)
2560 * Retrieve data from server
2567 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2569 DWORD nBytesWritten;
2570 DWORD nBytesReceived = 0;
2576 if (INVALID_HANDLE_VALUE == hFile)
2579 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2580 if (NULL == lpszBuffer)
2582 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2586 while (nBytesReceived < nBytes && nRC != -1)
2588 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2591 /* other side closed socket. */
2594 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2595 nBytesReceived += nRC;
2598 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2599 nBytesReceived * 100 / nBytes);
2602 TRACE("Data transfer complete\n");
2603 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2610 /***********************************************************************
2611 * FTP_CloseSessionHandle (internal)
2613 * Deallocate session handle
2620 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2622 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2626 if (lpwfs->download_in_progress != NULL)
2627 lpwfs->download_in_progress->session_deleted = TRUE;
2629 if (lpwfs->sndSocket != -1)
2630 closesocket(lpwfs->sndSocket);
2632 if (lpwfs->lstnSocket != -1)
2633 closesocket(lpwfs->lstnSocket);
2635 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2636 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2637 HeapFree(GetProcessHeap(), 0, lpwfs);
2641 /***********************************************************************
2642 * FTP_CloseFindNextHandle (internal)
2644 * Deallocate session handle
2651 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2653 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2658 for (i = 0; i < lpwfn->size; i++)
2660 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2663 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2664 HeapFree(GetProcessHeap(), 0, lpwfn);
2667 /***********************************************************************
2668 * FTP_CloseFileTransferHandle (internal)
2670 * Closes the file transfer handle. This also 'cleans' the data queue of
2671 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2674 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2676 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2677 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2682 if (!lpwh->session_deleted)
2683 lpwfs->download_in_progress = NULL;
2685 /* This just serves to flush the control socket of any spurrious lines written
2686 to it (like '226 Transfer complete.').
2688 Wonder what to do if the server sends us an error code though...
2690 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2692 if (lpwh->nDataSocket != -1)
2693 closesocket(lpwh->nDataSocket);
2695 HeapFree(GetProcessHeap(), 0, lpwh);
2698 /***********************************************************************
2699 * FTP_ReceiveFileList (internal)
2701 * Read file list from server
2704 * Handle to file list on success
2708 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2709 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2712 LPFILEPROPERTIESW lpafp = NULL;
2713 LPWININETFINDNEXTW lpwfn = NULL;
2714 HINTERNET handle = 0;
2716 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2718 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2721 FTP_ConvertFileProp(lpafp, lpFindFileData);
2723 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2726 lpwfn->hdr.htype = WH_HFINDNEXT;
2727 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2728 lpwfn->hdr.dwContext = dwContext;
2729 lpwfn->hdr.dwRefCount = 1;
2730 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2731 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2732 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2733 lpwfn->size = dwSize;
2734 lpwfn->lpafp = lpafp;
2736 handle = WININET_AllocHandle( &lpwfn->hdr );
2741 WININET_Release( &lpwfn->hdr );
2743 TRACE("Matched %ld files\n", dwSize);
2748 /***********************************************************************
2749 * FTP_ConvertFileProp (internal)
2751 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2758 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2760 BOOL bSuccess = FALSE;
2762 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2766 /* Convert 'Unix' time to Windows time */
2767 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2768 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2769 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2770 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2772 /* Not all fields are filled in */
2773 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2774 lpFindFileData->nFileSizeLow = lpafp->nSize;
2776 if (lpafp->bIsDirectory)
2777 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2779 if (lpafp->lpszName)
2780 strncpyW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2788 /***********************************************************************
2789 * FTP_ParseNextFile (internal)
2791 * Parse the next line in file listing
2797 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2799 static const char szSpace[] = " \t";
2807 lpfp->lpszName = NULL;
2809 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2812 pszToken = strtok(pszLine, szSpace);
2814 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2817 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2819 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2820 if(!FTP_ParsePermission(pszToken, lpfp))
2821 lpfp->bIsDirectory = FALSE;
2822 for(i=0; i<=3; i++) {
2823 if(!(pszToken = strtok(NULL, szSpace)))
2826 if(!pszToken) continue;
2827 if(lpfp->bIsDirectory) {
2828 TRACE("Is directory\n");
2832 TRACE("Size: %s\n", pszToken);
2833 lpfp->nSize = atol(pszToken);
2836 lpfp->tmLastModified.tm_sec = 0;
2837 lpfp->tmLastModified.tm_min = 0;
2838 lpfp->tmLastModified.tm_hour = 0;
2839 lpfp->tmLastModified.tm_mday = 0;
2840 lpfp->tmLastModified.tm_mon = 0;
2841 lpfp->tmLastModified.tm_year = 0;
2843 /* Determine month */
2844 pszToken = strtok(NULL, szSpace);
2845 if(!pszToken) continue;
2846 if(strlen(pszToken) >= 3) {
2848 if((pszTmp = StrStrIA(szMonths, pszToken)))
2849 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2852 pszToken = strtok(NULL, szSpace);
2853 if(!pszToken) continue;
2854 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2855 /* Determine time or year */
2856 pszToken = strtok(NULL, szSpace);
2857 if(!pszToken) continue;
2858 if((pszTmp = strchr(pszToken, ':'))) {
2863 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2864 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2866 apTM = localtime(&aTime);
2867 lpfp->tmLastModified.tm_year = apTM->tm_year;
2870 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2871 lpfp->tmLastModified.tm_hour = 12;
2873 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2874 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2875 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2876 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2878 pszToken = strtok(NULL, szSpace);
2879 if(!pszToken) continue;
2880 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2881 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2883 /* NT way of parsing ... :
2885 07-13-03 08:55PM <DIR> sakpatch
2886 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2888 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2889 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2891 sscanf(pszToken, "%d-%d-%d",
2892 &lpfp->tmLastModified.tm_mon,
2893 &lpfp->tmLastModified.tm_mday,
2894 &lpfp->tmLastModified.tm_year);
2896 /* Hacky and bad Y2K protection :-) */
2897 if (lpfp->tmLastModified.tm_year < 70)
2898 lpfp->tmLastModified.tm_year += 100;
2900 pszToken = strtok(NULL, szSpace);
2901 if(!pszToken) continue;
2902 sscanf(pszToken, "%d:%d",
2903 &lpfp->tmLastModified.tm_hour,
2904 &lpfp->tmLastModified.tm_min);
2905 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2906 lpfp->tmLastModified.tm_hour += 12;
2908 lpfp->tmLastModified.tm_sec = 0;
2910 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2911 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2912 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2913 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2915 pszToken = strtok(NULL, szSpace);
2916 if(!pszToken) continue;
2917 if(!strcasecmp(pszToken, "<DIR>")) {
2918 lpfp->bIsDirectory = TRUE;
2920 TRACE("Is directory\n");
2923 lpfp->bIsDirectory = FALSE;
2924 lpfp->nSize = atol(pszToken);
2925 TRACE("Size: %ld\n", lpfp->nSize);
2928 pszToken = strtok(NULL, szSpace);
2929 if(!pszToken) continue;
2930 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2931 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2933 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2934 else if(pszToken[0] == '+') {
2935 FIXME("EPLF Format not implemented\n");
2938 if(lpfp->lpszName) {
2939 if((lpszSearchFile == NULL) ||
2940 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2942 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2945 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2946 lpfp->lpszName = NULL;
2953 /***********************************************************************
2954 * FTP_ParseDirectory (internal)
2956 * Parse string of directory information
2962 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2963 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2965 BOOL bSuccess = TRUE;
2966 INT sizeFilePropArray = 500;/*20; */
2967 INT indexFilePropArray = -1;
2971 /* Allocate intial file properties array */
2972 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2977 if (indexFilePropArray+1 >= sizeFilePropArray)
2979 LPFILEPROPERTIESW tmpafp;
2981 sizeFilePropArray *= 2;
2982 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2983 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2992 indexFilePropArray++;
2993 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
2995 if (bSuccess && indexFilePropArray)
2997 if (indexFilePropArray < sizeFilePropArray - 1)
2999 LPFILEPROPERTIESW tmpafp;
3001 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3002 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3006 *dwfp = indexFilePropArray;
3010 HeapFree(GetProcessHeap(), 0, *lpafp);
3011 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3019 /***********************************************************************
3020 * FTP_ParsePermission (internal)
3022 * Parse permission string of directory information
3029 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3031 BOOL bSuccess = TRUE;
3032 unsigned short nPermission = 0;
3037 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3043 lpfp->bIsDirectory = (*lpszPermission == 'd');
3049 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3052 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3055 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3058 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3061 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3064 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3067 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3070 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3073 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3077 }while (nPos <= nLast);
3079 lpfp->permissions = nPermission;
3084 /***********************************************************************
3085 * FTP_SetResponseError (internal)
3087 * Set the appropriate error code for a given response from the server
3092 DWORD FTP_SetResponseError(DWORD dwResponse)
3098 case 421: /* Service not available - Server may be shutting down. */
3099 dwCode = ERROR_INTERNET_TIMEOUT;
3102 case 425: /* Cannot open data connection. */
3103 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3106 case 426: /* Connection closed, transer aborted. */
3107 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3110 case 500: /* Syntax error. Command unrecognized. */
3111 case 501: /* Syntax error. Error in parameters or arguments. */
3112 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3115 case 530: /* Not logged in. Login incorrect. */
3116 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3119 case 550: /* File action not taken. File not found or no access. */
3120 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3123 case 450: /* File action not taken. File may be busy. */
3124 case 451: /* Action aborted. Server error. */
3125 case 452: /* Action not taken. Insufficient storage space on server. */
3126 case 502: /* Command not implemented. */
3127 case 503: /* Bad sequence of command. */
3128 case 504: /* Command not implemented for that parameter. */
3129 case 532: /* Need account for storing files */
3130 case 551: /* Requested action aborted. Page type unknown */
3131 case 552: /* Action aborted. Exceeded storage allocation */
3132 case 553: /* Action not taken. File name not allowed. */
3135 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3139 INTERNET_SetLastError(dwCode);