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 /***********************************************************************
1237 * FtpGetFileSize (WININET.@)
1239 DWORD WINAPI FtpGetFileSize( HINTERNET hFile, LPDWORD lpdwFileSizeHigh )
1241 FIXME("(%p, %p)\n", hFile, lpdwFileSizeHigh);
1243 if (lpdwFileSizeHigh)
1244 *lpdwFileSizeHigh = 0;
1249 /***********************************************************************
1250 * FtpDeleteFileA (WININET.@)
1252 * Delete a file on the ftp server
1259 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1261 LPWSTR lpwzFileName;
1264 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1265 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1266 HeapFree(GetProcessHeap(), 0, lpwzFileName);
1270 /***********************************************************************
1271 * FtpDeleteFileW (WININET.@)
1273 * Delete a file on the ftp server
1280 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1282 LPWININETFTPSESSIONW lpwfs;
1283 LPWININETAPPINFOW hIC = NULL;
1286 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1287 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1289 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1293 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1294 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1296 WORKREQUEST workRequest;
1297 struct WORKREQ_FTPDELETEFILEW *req;
1299 workRequest.asyncall = FTPDELETEFILEW;
1300 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1301 req = &workRequest.u.FtpDeleteFileW;
1302 req->lpszFilename = WININET_strdupW(lpszFileName);
1304 r = INTERNET_AsyncCall(&workRequest);
1308 r = FTP_FtpDeleteFileW(hFtpSession, lpszFileName);
1313 WININET_Release( &lpwfs->hdr );
1318 /***********************************************************************
1319 * FTP_FtpDeleteFileW (Internal)
1321 * Delete a file on the ftp server
1328 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1331 BOOL bSuccess = FALSE;
1332 LPWININETAPPINFOW hIC = NULL;
1334 TRACE("%p\n", lpwfs);
1336 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1338 /* Clear any error information */
1339 INTERNET_SetLastError(0);
1341 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1344 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1347 if (nResCode == 250)
1350 FTP_SetResponseError(nResCode);
1353 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1354 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1356 INTERNET_ASYNC_RESULT iar;
1358 iar.dwResult = (DWORD)bSuccess;
1359 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1360 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1361 &iar, sizeof(INTERNET_ASYNC_RESULT));
1368 /***********************************************************************
1369 * FtpRemoveDirectoryA (WININET.@)
1371 * Remove a directory on the ftp server
1378 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1380 LPWSTR lpwzDirectory;
1383 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1384 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1385 HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1389 /***********************************************************************
1390 * FtpRemoveDirectoryW (WININET.@)
1392 * Remove a directory on the ftp server
1399 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1401 LPWININETFTPSESSIONW lpwfs;
1402 LPWININETAPPINFOW hIC = NULL;
1405 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1406 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1408 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1412 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1413 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1415 WORKREQUEST workRequest;
1416 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1418 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1419 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1420 req = &workRequest.u.FtpRemoveDirectoryW;
1421 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1423 r = INTERNET_AsyncCall(&workRequest);
1427 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1432 WININET_Release( &lpwfs->hdr );
1437 /***********************************************************************
1438 * FTP_FtpRemoveDirectoryW (Internal)
1440 * Remove a directory on the ftp server
1447 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1450 BOOL bSuccess = FALSE;
1451 LPWININETAPPINFOW hIC = NULL;
1455 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1457 /* Clear any error information */
1458 INTERNET_SetLastError(0);
1460 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1463 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1466 if (nResCode == 250)
1469 FTP_SetResponseError(nResCode);
1473 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1474 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1476 INTERNET_ASYNC_RESULT iar;
1478 iar.dwResult = (DWORD)bSuccess;
1479 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1480 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1481 &iar, sizeof(INTERNET_ASYNC_RESULT));
1488 /***********************************************************************
1489 * FtpRenameFileA (WININET.@)
1491 * Rename a file on the ftp server
1498 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1504 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1505 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1506 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1507 HeapFree(GetProcessHeap(), 0, lpwzSrc);
1508 HeapFree(GetProcessHeap(), 0, lpwzDest);
1512 /***********************************************************************
1513 * FtpRenameFileW (WININET.@)
1515 * Rename a file on the ftp server
1522 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1524 LPWININETFTPSESSIONW lpwfs;
1525 LPWININETAPPINFOW hIC = NULL;
1528 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1529 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1531 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1535 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1536 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1538 WORKREQUEST workRequest;
1539 struct WORKREQ_FTPRENAMEFILEW *req;
1541 workRequest.asyncall = FTPRENAMEFILEW;
1542 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1543 req = &workRequest.u.FtpRenameFileW;
1544 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1545 req->lpszDestFile = WININET_strdupW(lpszDest);
1547 r = INTERNET_AsyncCall(&workRequest);
1551 r = FTP_FtpRenameFileW(hFtpSession, lpszSrc, lpszDest);
1556 WININET_Release( &lpwfs->hdr );
1561 /***********************************************************************
1562 * FTP_FtpRenameFileA (Internal)
1564 * Rename a file on the ftp server
1571 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1572 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1575 BOOL bSuccess = FALSE;
1576 LPWININETAPPINFOW hIC = NULL;
1580 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1582 /* Clear any error information */
1583 INTERNET_SetLastError(0);
1585 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1588 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1589 if (nResCode == 350)
1591 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1594 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1597 if (nResCode == 250)
1600 FTP_SetResponseError(nResCode);
1603 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1604 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1606 INTERNET_ASYNC_RESULT iar;
1608 iar.dwResult = (DWORD)bSuccess;
1609 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1610 SendAsyncCallback(&lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1611 &iar, sizeof(INTERNET_ASYNC_RESULT));
1617 /***********************************************************************
1618 * FtpCommandA (WININET.@)
1620 BOOL WINAPI FtpCommandA( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1621 LPCSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1623 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1624 debugstr_a(lpszCommand), dwContext, phFtpCommand);
1629 /***********************************************************************
1630 * FtpCommandW (WININET.@)
1632 BOOL WINAPI FtpCommandW( HINTERNET hConnect, BOOL fExpectResponse, DWORD dwFlags,
1633 LPCWSTR lpszCommand, DWORD_PTR dwContext, HINTERNET* phFtpCommand )
1635 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect, fExpectResponse, dwFlags,
1636 debugstr_w(lpszCommand), dwContext, phFtpCommand);
1641 /***********************************************************************
1642 * FTP_Connect (internal)
1644 * Connect to a ftp server
1647 * HINTERNET a session handle on success
1652 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1653 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1654 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1655 DWORD dwInternalFlags)
1657 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1658 static const WCHAR szDefaultPassword[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1659 struct sockaddr_in socketAddr;
1660 struct hostent *phe = NULL;
1663 BOOL bSuccess = FALSE;
1664 LPWININETFTPSESSIONW lpwfs = NULL;
1665 HINTERNET handle = NULL;
1667 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1668 hIC, debugstr_w(lpszServerName),
1669 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1671 assert( hIC->hdr.htype == WH_HINIT );
1673 if (NULL == lpszUserName && NULL != lpszPassword)
1675 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1679 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1682 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1686 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1687 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1689 lpwfs->hdr.htype = WH_HFTPSESSION;
1690 lpwfs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1691 lpwfs->hdr.dwFlags = dwFlags;
1692 lpwfs->hdr.dwContext = dwContext;
1693 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1694 lpwfs->hdr.dwRefCount = 1;
1695 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1696 lpwfs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
1697 lpwfs->download_in_progress = NULL;
1699 handle = WININET_AllocHandle( &lpwfs->hdr );
1702 ERR("Failed to alloc handle\n");
1703 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1707 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1708 if(strchrW(hIC->lpszProxy, ' '))
1709 FIXME("Several proxies not implemented.\n");
1710 if(hIC->lpszProxyBypass)
1711 FIXME("Proxy bypass is ignored.\n");
1713 if ( !lpszUserName) {
1714 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1715 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1718 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1719 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1722 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1723 if (!(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1725 INTERNET_ASYNC_RESULT iar;
1727 iar.dwResult = (DWORD)handle;
1728 iar.dwError = ERROR_SUCCESS;
1730 SendAsyncCallback(&hIC->hdr, dwContext,
1731 INTERNET_STATUS_HANDLE_CREATED, &iar,
1732 sizeof(INTERNET_ASYNC_RESULT));
1735 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1736 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1738 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1740 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1744 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1745 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1747 nsocket = socket(AF_INET,SOCK_STREAM,0);
1750 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1754 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1755 &socketAddr, sizeof(struct sockaddr_in));
1757 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1759 ERR("Unable to connect (%s)\n", strerror(errno));
1760 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1764 TRACE("Connected to server\n");
1765 lpwfs->sndSocket = nsocket;
1766 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1767 &socketAddr, sizeof(struct sockaddr_in));
1769 sock_namelen = sizeof(lpwfs->socketAddress);
1770 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1771 lpwfs->phostent = phe;
1773 if (FTP_ConnectToHost(lpwfs))
1775 TRACE("Successfully logged into server\n");
1781 if (!bSuccess && nsocket == -1)
1782 closesocket(nsocket);
1784 if (!bSuccess && lpwfs)
1786 HeapFree(GetProcessHeap(), 0, lpwfs);
1787 WININET_FreeHandle( handle );
1791 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1793 INTERNET_ASYNC_RESULT iar;
1795 iar.dwResult = (DWORD)lpwfs;
1796 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1797 SendAsyncCallback(&hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1798 &iar, sizeof(INTERNET_ASYNC_RESULT));
1805 /***********************************************************************
1806 * FTP_ConnectToHost (internal)
1808 * Connect to a ftp server
1815 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1818 BOOL bSuccess = FALSE;
1821 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1823 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1826 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1829 /* Login successful... */
1830 if (nResCode == 230)
1832 /* User name okay, need password... */
1833 else if (nResCode == 331)
1834 bSuccess = FTP_SendPassword(lpwfs);
1835 /* Need account for login... */
1836 else if (nResCode == 332)
1837 bSuccess = FTP_SendAccount(lpwfs);
1839 FTP_SetResponseError(nResCode);
1842 TRACE("Returning %d\n", bSuccess);
1848 /***********************************************************************
1849 * FTP_SendCommandA (internal)
1851 * Send command to server
1858 BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1859 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1863 DWORD nBytesSent = 0;
1867 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1871 HINTERNET hHandle = WININET_FindHandle( hdr );
1874 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1875 WININET_Release( hdr );
1879 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1880 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1881 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1883 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1886 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1887 dwParamLen ? lpszParam : "", szCRLF);
1889 TRACE("Sending (%s) len(%ld)\n", buf, len);
1890 while((nBytesSent < len) && (nRC != -1))
1892 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1896 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1900 HINTERNET hHandle = WININET_FindHandle( hdr );
1903 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1904 &nBytesSent, sizeof(DWORD));
1905 WININET_Release( hdr );
1909 TRACE("Sent %ld bytes\n", nBytesSent);
1913 /***********************************************************************
1914 * FTP_SendCommand (internal)
1916 * Send command to server
1923 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1924 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1927 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1928 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
1929 HeapFree(GetProcessHeap(), 0, lpszParamA);
1933 /***********************************************************************
1934 * FTP_ReceiveResponse (internal)
1936 * Receive response from server
1939 * Reply code on success
1943 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1945 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1948 char firstprefix[5];
1949 BOOL multiline = FALSE;
1950 LPWININETAPPINFOW hIC = NULL;
1952 TRACE("socket(%d) \n", lpwfs->sndSocket);
1954 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1955 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1959 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1966 if(lpszResponse[3] != '-')
1969 { /* Start of multiline repsonse. Loop until we get "nnn " */
1971 memcpy(firstprefix, lpszResponse, 3);
1972 firstprefix[3] = ' ';
1973 firstprefix[4] = '\0';
1978 if(!memcmp(firstprefix, lpszResponse, 4))
1986 rc = atoi(lpszResponse);
1988 SendAsyncCallback(&lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1989 &nRecv, sizeof(DWORD));
1993 TRACE("return %d\n", rc);
1998 /***********************************************************************
1999 * FTP_SendPassword (internal)
2001 * Send password to ftp server
2008 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
2011 BOOL bSuccess = FALSE;
2014 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
2017 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2020 TRACE("Received reply code %d\n", nResCode);
2021 /* Login successful... */
2022 if (nResCode == 230)
2024 /* Command not implemented, superfluous at the server site... */
2025 /* Need account for login... */
2026 else if (nResCode == 332)
2027 bSuccess = FTP_SendAccount(lpwfs);
2029 FTP_SetResponseError(nResCode);
2033 TRACE("Returning %d\n", bSuccess);
2038 /***********************************************************************
2039 * FTP_SendAccount (internal)
2048 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2051 BOOL bSuccess = FALSE;
2054 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2057 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2061 FTP_SetResponseError(nResCode);
2068 /***********************************************************************
2069 * FTP_SendStore (internal)
2071 * Send request to upload file to ftp server
2078 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2081 BOOL bSuccess = FALSE;
2084 if (!FTP_InitListenSocket(lpwfs))
2087 if (!FTP_SendType(lpwfs, dwType))
2090 if (!FTP_SendPortOrPasv(lpwfs))
2093 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2095 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2098 if (nResCode == 150)
2101 FTP_SetResponseError(nResCode);
2105 if (!bSuccess && lpwfs->lstnSocket != -1)
2107 closesocket(lpwfs->lstnSocket);
2108 lpwfs->lstnSocket = -1;
2115 /***********************************************************************
2116 * FTP_InitListenSocket (internal)
2118 * Create a socket to listen for server response
2125 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2127 BOOL bSuccess = FALSE;
2128 size_t namelen = sizeof(struct sockaddr_in);
2132 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2133 if (lpwfs->lstnSocket == -1)
2135 TRACE("Unable to create listening socket\n");
2139 /* We obtain our ip addr from the name of the command channel socket */
2140 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2142 /* and get the system to assign us a port */
2143 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2145 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2147 TRACE("Unable to bind socket\n");
2151 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2153 TRACE("listen failed\n");
2157 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2161 if (!bSuccess && lpwfs->lstnSocket == -1)
2163 closesocket(lpwfs->lstnSocket);
2164 lpwfs->lstnSocket = -1;
2171 /***********************************************************************
2172 * FTP_SendType (internal)
2174 * Tell server type of data being transferred
2180 * W98SE doesn't cache the type that's currently set
2181 * (i.e. it sends it always),
2182 * so we probably don't want to do that either.
2184 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2187 WCHAR type[] = { 'I','\0' };
2188 BOOL bSuccess = FALSE;
2191 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2194 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2197 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2203 FTP_SetResponseError(nResCode);
2210 /***********************************************************************
2211 * FTP_GetFileSize (internal)
2213 * Retrieves from the server the size of the given file
2220 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2223 BOOL bSuccess = FALSE;
2227 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2230 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2233 if (nResCode == 213) {
2234 /* Now parses the output to get the actual file size */
2236 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2238 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2239 if (lpszResponseBuffer[i] == '\0') return FALSE;
2240 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2244 FTP_SetResponseError(nResCode);
2253 /***********************************************************************
2254 * FTP_SendPort (internal)
2256 * Tell server which port to use
2263 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2265 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2267 WCHAR szIPAddress[64];
2268 BOOL bSuccess = FALSE;
2271 sprintfW(szIPAddress, szIPFormat,
2272 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2273 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2274 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2275 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2276 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2277 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2279 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2282 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2285 if (nResCode == 200)
2288 FTP_SetResponseError(nResCode);
2296 /***********************************************************************
2297 * FTP_DoPassive (internal)
2299 * Tell server that we want to do passive transfers
2300 * and connect data socket
2307 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2310 BOOL bSuccess = FALSE;
2313 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2316 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2319 if (nResCode == 227)
2321 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2325 char *pAddr, *pPort;
2327 struct sockaddr_in dataSocketAddress;
2329 p = lpszResponseBuffer+4; /* skip status code */
2331 /* do a very strict check; we can improve that later. */
2333 if (strncmp(p, "Entering Passive Mode", 21))
2335 ERR("unknown response '%.*s', aborting\n", 21, p);
2338 p += 21; /* skip string */
2339 if ((*p++ != ' ') || (*p++ != '('))
2341 ERR("unknown response format, aborting\n");
2345 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2348 ERR("unknown response address format '%s', aborting\n", p);
2351 for (i=0; i < 6; i++)
2354 dataSocketAddress = lpwfs->socketAddress;
2355 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2356 pPort = (char *)&(dataSocketAddress.sin_port);
2364 nsocket = socket(AF_INET,SOCK_STREAM,0);
2368 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2370 ERR("can't connect passive FTP data port.\n");
2373 lpwfs->pasvSocket = nsocket;
2377 FTP_SetResponseError(nResCode);
2385 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2387 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2389 if (!FTP_DoPassive(lpwfs))
2394 if (!FTP_SendPort(lpwfs))
2401 /***********************************************************************
2402 * FTP_GetDataSocket (internal)
2404 * Either accepts an incoming data socket connection from the server
2405 * or just returns the already opened socket after a PASV command
2406 * in case of passive FTP.
2414 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2416 struct sockaddr_in saddr;
2417 size_t addrlen = sizeof(struct sockaddr);
2420 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2422 *nDataSocket = lpwfs->pasvSocket;
2426 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2427 closesocket(lpwfs->lstnSocket);
2428 lpwfs->lstnSocket = -1;
2430 return *nDataSocket != -1;
2434 /***********************************************************************
2435 * FTP_SendData (internal)
2437 * Send data to the server
2444 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2446 BY_HANDLE_FILE_INFORMATION fi;
2447 DWORD nBytesRead = 0;
2448 DWORD nBytesSent = 0;
2449 DWORD nTotalSent = 0;
2450 DWORD nBytesToSend, nLen;
2452 time_t s_long_time, e_long_time;
2457 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2458 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2460 /* Get the size of the file. */
2461 GetFileInformationByHandle(hFile, &fi);
2466 nBytesToSend = nBytesRead - nBytesSent;
2468 if (nBytesToSend <= 0)
2470 /* Read data from file. */
2472 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2473 ERR("Failed reading from file\n");
2476 nBytesToSend = nBytesRead;
2481 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2482 DATA_PACKET_SIZE : nBytesToSend;
2483 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2491 /* Do some computation to display the status. */
2493 nSeconds = e_long_time - s_long_time;
2494 if( nSeconds / 60 > 0 )
2496 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2497 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2498 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2502 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2503 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2504 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2506 } while (nRC != -1);
2508 TRACE("file transfer complete!\n");
2510 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2516 /***********************************************************************
2517 * FTP_SendRetrieve (internal)
2519 * Send request to retrieve a file
2522 * Number of bytes to be received on success
2526 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2532 if (!FTP_InitListenSocket(lpwfs))
2535 if (!FTP_SendType(lpwfs, dwType))
2538 if (!FTP_SendPortOrPasv(lpwfs))
2541 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2544 TRACE("Waiting to receive %ld bytes\n", nResult);
2546 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2549 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2550 if ((nResCode != 125) && (nResCode != 150)) {
2551 /* That means that we got an error getting the file. */
2556 if (0 == nResult && lpwfs->lstnSocket != -1)
2558 closesocket(lpwfs->lstnSocket);
2559 lpwfs->lstnSocket = -1;
2566 /***********************************************************************
2567 * FTP_RetrieveData (internal)
2569 * Retrieve data from server
2576 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2578 DWORD nBytesWritten;
2579 DWORD nBytesReceived = 0;
2585 if (INVALID_HANDLE_VALUE == hFile)
2588 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2589 if (NULL == lpszBuffer)
2591 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2595 while (nBytesReceived < nBytes && nRC != -1)
2597 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2600 /* other side closed socket. */
2603 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2604 nBytesReceived += nRC;
2607 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2608 nBytesReceived * 100 / nBytes);
2611 TRACE("Data transfer complete\n");
2612 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2619 /***********************************************************************
2620 * FTP_CloseSessionHandle (internal)
2622 * Deallocate session handle
2629 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2631 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2635 if (lpwfs->download_in_progress != NULL)
2636 lpwfs->download_in_progress->session_deleted = TRUE;
2638 if (lpwfs->sndSocket != -1)
2639 closesocket(lpwfs->sndSocket);
2641 if (lpwfs->lstnSocket != -1)
2642 closesocket(lpwfs->lstnSocket);
2644 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2645 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2646 HeapFree(GetProcessHeap(), 0, lpwfs);
2650 /***********************************************************************
2651 * FTP_CloseFindNextHandle (internal)
2653 * Deallocate session handle
2660 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2662 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2667 for (i = 0; i < lpwfn->size; i++)
2669 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2672 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2673 HeapFree(GetProcessHeap(), 0, lpwfn);
2676 /***********************************************************************
2677 * FTP_CloseFileTransferHandle (internal)
2679 * Closes the file transfer handle. This also 'cleans' the data queue of
2680 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2683 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2685 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2686 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2691 if (!lpwh->session_deleted)
2692 lpwfs->download_in_progress = NULL;
2694 /* This just serves to flush the control socket of any spurrious lines written
2695 to it (like '226 Transfer complete.').
2697 Wonder what to do if the server sends us an error code though...
2699 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2701 if (lpwh->nDataSocket != -1)
2702 closesocket(lpwh->nDataSocket);
2704 HeapFree(GetProcessHeap(), 0, lpwh);
2707 /***********************************************************************
2708 * FTP_ReceiveFileList (internal)
2710 * Read file list from server
2713 * Handle to file list on success
2717 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2718 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2721 LPFILEPROPERTIESW lpafp = NULL;
2722 LPWININETFINDNEXTW lpwfn = NULL;
2723 HINTERNET handle = 0;
2725 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2727 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2730 FTP_ConvertFileProp(lpafp, lpFindFileData);
2732 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2735 lpwfn->hdr.htype = WH_HFINDNEXT;
2736 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2737 lpwfn->hdr.dwContext = dwContext;
2738 lpwfn->hdr.dwRefCount = 1;
2739 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2740 lpwfn->hdr.lpfnStatusCB = lpwfs->hdr.lpfnStatusCB;
2741 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2742 lpwfn->size = dwSize;
2743 lpwfn->lpafp = lpafp;
2745 handle = WININET_AllocHandle( &lpwfn->hdr );
2750 WININET_Release( &lpwfn->hdr );
2752 TRACE("Matched %ld files\n", dwSize);
2757 /***********************************************************************
2758 * FTP_ConvertFileProp (internal)
2760 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2767 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2769 BOOL bSuccess = FALSE;
2771 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2775 /* Convert 'Unix' time to Windows time */
2776 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2777 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2778 lpFindFileData->ftLastWriteTime = lpFindFileData->ftLastAccessTime;
2779 lpFindFileData->ftCreationTime = lpFindFileData->ftLastAccessTime;
2781 /* Not all fields are filled in */
2782 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2783 lpFindFileData->nFileSizeLow = lpafp->nSize;
2785 if (lpafp->bIsDirectory)
2786 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2788 if (lpafp->lpszName)
2789 lstrcpynW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2797 /***********************************************************************
2798 * FTP_ParseNextFile (internal)
2800 * Parse the next line in file listing
2806 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2808 static const char szSpace[] = " \t";
2816 lpfp->lpszName = NULL;
2818 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2821 pszToken = strtok(pszLine, szSpace);
2823 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2826 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2828 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2829 if(!FTP_ParsePermission(pszToken, lpfp))
2830 lpfp->bIsDirectory = FALSE;
2831 for(i=0; i<=3; i++) {
2832 if(!(pszToken = strtok(NULL, szSpace)))
2835 if(!pszToken) continue;
2836 if(lpfp->bIsDirectory) {
2837 TRACE("Is directory\n");
2841 TRACE("Size: %s\n", pszToken);
2842 lpfp->nSize = atol(pszToken);
2845 lpfp->tmLastModified.tm_sec = 0;
2846 lpfp->tmLastModified.tm_min = 0;
2847 lpfp->tmLastModified.tm_hour = 0;
2848 lpfp->tmLastModified.tm_mday = 0;
2849 lpfp->tmLastModified.tm_mon = 0;
2850 lpfp->tmLastModified.tm_year = 0;
2852 /* Determine month */
2853 pszToken = strtok(NULL, szSpace);
2854 if(!pszToken) continue;
2855 if(strlen(pszToken) >= 3) {
2857 if((pszTmp = StrStrIA(szMonths, pszToken)))
2858 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2861 pszToken = strtok(NULL, szSpace);
2862 if(!pszToken) continue;
2863 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2864 /* Determine time or year */
2865 pszToken = strtok(NULL, szSpace);
2866 if(!pszToken) continue;
2867 if((pszTmp = strchr(pszToken, ':'))) {
2872 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2873 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2875 apTM = localtime(&aTime);
2876 lpfp->tmLastModified.tm_year = apTM->tm_year;
2879 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2880 lpfp->tmLastModified.tm_hour = 12;
2882 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2883 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2884 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2885 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2887 pszToken = strtok(NULL, szSpace);
2888 if(!pszToken) continue;
2889 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2890 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2892 /* NT way of parsing ... :
2894 07-13-03 08:55PM <DIR> sakpatch
2895 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2897 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2898 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2900 sscanf(pszToken, "%d-%d-%d",
2901 &lpfp->tmLastModified.tm_mon,
2902 &lpfp->tmLastModified.tm_mday,
2903 &lpfp->tmLastModified.tm_year);
2905 /* Hacky and bad Y2K protection :-) */
2906 if (lpfp->tmLastModified.tm_year < 70)
2907 lpfp->tmLastModified.tm_year += 100;
2909 pszToken = strtok(NULL, szSpace);
2910 if(!pszToken) continue;
2911 sscanf(pszToken, "%d:%d",
2912 &lpfp->tmLastModified.tm_hour,
2913 &lpfp->tmLastModified.tm_min);
2914 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2915 lpfp->tmLastModified.tm_hour += 12;
2917 lpfp->tmLastModified.tm_sec = 0;
2919 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2920 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2921 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2922 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2924 pszToken = strtok(NULL, szSpace);
2925 if(!pszToken) continue;
2926 if(!strcasecmp(pszToken, "<DIR>")) {
2927 lpfp->bIsDirectory = TRUE;
2929 TRACE("Is directory\n");
2932 lpfp->bIsDirectory = FALSE;
2933 lpfp->nSize = atol(pszToken);
2934 TRACE("Size: %ld\n", lpfp->nSize);
2937 pszToken = strtok(NULL, szSpace);
2938 if(!pszToken) continue;
2939 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2940 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2942 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2943 else if(pszToken[0] == '+') {
2944 FIXME("EPLF Format not implemented\n");
2947 if(lpfp->lpszName) {
2948 if((lpszSearchFile == NULL) ||
2949 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2951 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2954 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2955 lpfp->lpszName = NULL;
2962 /***********************************************************************
2963 * FTP_ParseDirectory (internal)
2965 * Parse string of directory information
2971 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2972 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2974 BOOL bSuccess = TRUE;
2975 INT sizeFilePropArray = 500;/*20; */
2976 INT indexFilePropArray = -1;
2980 /* Allocate intial file properties array */
2981 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2986 if (indexFilePropArray+1 >= sizeFilePropArray)
2988 LPFILEPROPERTIESW tmpafp;
2990 sizeFilePropArray *= 2;
2991 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2992 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
3001 indexFilePropArray++;
3002 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
3004 if (bSuccess && indexFilePropArray)
3006 if (indexFilePropArray < sizeFilePropArray - 1)
3008 LPFILEPROPERTIESW tmpafp;
3010 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
3011 sizeof(FILEPROPERTIESW)*indexFilePropArray);
3015 *dwfp = indexFilePropArray;
3019 HeapFree(GetProcessHeap(), 0, *lpafp);
3020 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
3028 /***********************************************************************
3029 * FTP_ParsePermission (internal)
3031 * Parse permission string of directory information
3038 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3040 BOOL bSuccess = TRUE;
3041 unsigned short nPermission = 0;
3046 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3052 lpfp->bIsDirectory = (*lpszPermission == 'd');
3058 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3061 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3064 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3067 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3070 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3073 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3076 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3079 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3082 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3086 }while (nPos <= nLast);
3088 lpfp->permissions = nPermission;
3093 /***********************************************************************
3094 * FTP_SetResponseError (internal)
3096 * Set the appropriate error code for a given response from the server
3101 DWORD FTP_SetResponseError(DWORD dwResponse)
3107 case 421: /* Service not available - Server may be shutting down. */
3108 dwCode = ERROR_INTERNET_TIMEOUT;
3111 case 425: /* Cannot open data connection. */
3112 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3115 case 426: /* Connection closed, transer aborted. */
3116 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3119 case 500: /* Syntax error. Command unrecognized. */
3120 case 501: /* Syntax error. Error in parameters or arguments. */
3121 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3124 case 530: /* Not logged in. Login incorrect. */
3125 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3128 case 550: /* File action not taken. File not found or no access. */
3129 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3132 case 450: /* File action not taken. File may be busy. */
3133 case 451: /* Action aborted. Server error. */
3134 case 452: /* Action not taken. Insufficient storage space on server. */
3135 case 502: /* Command not implemented. */
3136 case 503: /* Bad sequence of command. */
3137 case 504: /* Command not implemented for that parameter. */
3138 case 532: /* Need account for storing files */
3139 case 551: /* Requested action aborted. Page type unknown */
3140 case 552: /* Action aborted. Exceeded storage allocation */
3141 case 553: /* Action not taken. File name not allowed. */
3144 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3148 INTERNET_SetLastError(dwCode);