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 if(lpwzLocalFile) HeapFree(GetProcessHeap(), 0, lpwzLocalFile);
169 if(lpwzNewRemoteFile) 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(hIC, &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);
276 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
282 FTP_SetResponseError(nResCode);
288 if (lpwfs->lstnSocket != -1)
289 close(lpwfs->lstnSocket);
291 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
293 INTERNET_ASYNC_RESULT iar;
295 iar.dwResult = (DWORD)bSuccess;
296 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
297 SendAsyncCallback(hIC, &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 if(lpwzDirectory) 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 hIC->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 && hIC->lpfnStatusCB)
426 INTERNET_ASYNC_RESULT iar;
428 iar.dwResult = (DWORD)bSuccess;
429 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
430 SendAsyncCallback(hIC, &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 if(lpwzDirectory) 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 && hIC->lpfnStatusCB)
550 INTERNET_ASYNC_RESULT iar;
552 iar.dwResult = (DWORD)bSuccess;
553 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
554 SendAsyncCallback(hIC, &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 if(lpwzSearchFile) 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 hIC->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);
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 close(lpwfs->lstnSocket);
708 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
710 INTERNET_ASYNC_RESULT iar;
714 iar.dwResult = (DWORD)hFindNext;
715 iar.dwError = ERROR_SUCCESS;
716 SendAsyncCallback(hIC, &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(hIC, &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 hIC->lpfnStatusCB, &lpwfs->hdr, lpwfs->hdr.dwContext))
847 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
850 if (nResCode == 257) /* Extract directory name */
852 INT 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 && hIC->lpfnStatusCB)
880 INTERNET_ASYNC_RESULT iar;
882 iar.dwResult = (DWORD)bSuccess;
883 iar.dwError = bSuccess ? ERROR_SUCCESS : ERROR_INTERNET_EXTENDED_ERROR;
884 SendAsyncCallback(hIC, &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 if(lpwzFileName) 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->nDataSocket = nDataSocket;
1026 lpwh->session_deleted = FALSE;
1028 handle = WININET_AllocHandle( &lpwh->hdr );
1032 /* Indicate that a download is currently in progress */
1033 lpwfs->download_in_progress = lpwh;
1036 if (lpwfs->lstnSocket != -1)
1037 close(lpwfs->lstnSocket);
1039 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1040 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1042 INTERNET_ASYNC_RESULT iar;
1046 iar.dwResult = (DWORD)handle;
1047 iar.dwError = ERROR_SUCCESS;
1048 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_HANDLE_CREATED,
1049 &iar, sizeof(INTERNET_ASYNC_RESULT));
1052 iar.dwResult = (DWORD)bSuccess;
1053 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1054 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1055 &iar, sizeof(INTERNET_ASYNC_RESULT));
1060 WININET_Release( &lpwh->hdr );
1066 /***********************************************************************
1067 * FtpGetFileA (WININET.@)
1069 * Retrieve file from the FTP server
1076 BOOL WINAPI FtpGetFileA(HINTERNET hInternet, LPCSTR lpszRemoteFile, LPCSTR lpszNewFile,
1077 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1080 LPWSTR lpwzRemoteFile;
1084 lpwzRemoteFile = lpszRemoteFile?WININET_strdup_AtoW(lpszRemoteFile):NULL;
1085 lpwzNewFile = lpszNewFile?WININET_strdup_AtoW(lpszNewFile):NULL;
1086 ret = FtpGetFileW(hInternet, lpwzRemoteFile, lpwzNewFile, fFailIfExists,
1087 dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1088 if(lpwzRemoteFile) HeapFree(GetProcessHeap(), 0, lpwzRemoteFile);
1089 if(lpwzNewFile) HeapFree(GetProcessHeap(), 0, lpwzNewFile);
1094 /***********************************************************************
1095 * FtpGetFileW (WININET.@)
1097 * Retrieve file from the FTP server
1104 BOOL WINAPI FtpGetFileW(HINTERNET hInternet, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1105 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1108 LPWININETFTPSESSIONW lpwfs;
1109 LPWININETAPPINFOW hIC = NULL;
1112 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hInternet );
1113 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1115 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1119 if (lpwfs->download_in_progress != NULL) {
1120 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
1124 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1125 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1127 WORKREQUEST workRequest;
1128 struct WORKREQ_FTPGETFILEW *req;
1130 workRequest.asyncall = FTPGETFILEW;
1131 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1132 req = &workRequest.u.FtpGetFileW;
1133 req->lpszRemoteFile = WININET_strdupW(lpszRemoteFile);
1134 req->lpszNewFile = WININET_strdupW(lpszNewFile);
1135 req->dwLocalFlagsAttribute = dwLocalFlagsAttribute;
1136 req->fFailIfExists = fFailIfExists;
1137 req->dwFlags = dwInternetFlags;
1138 req->dwContext = dwContext;
1140 r = INTERNET_AsyncCall(&workRequest);
1144 r = FTP_FtpGetFileW(lpwfs, lpszRemoteFile, lpszNewFile,
1145 fFailIfExists, dwLocalFlagsAttribute, dwInternetFlags, dwContext);
1150 WININET_Release( &lpwfs->hdr );
1156 /***********************************************************************
1157 * FTP_FtpGetFileW (Internal)
1159 * Retrieve file from the FTP server
1166 BOOL WINAPI FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, LPCWSTR lpszNewFile,
1167 BOOL fFailIfExists, DWORD dwLocalFlagsAttribute, DWORD dwInternetFlags,
1171 BOOL bSuccess = FALSE;
1173 LPWININETAPPINFOW hIC = NULL;
1175 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile), debugstr_w(lpszNewFile));
1177 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1179 /* Clear any error information */
1180 INTERNET_SetLastError(0);
1182 /* Ensure we can write to lpszNewfile by opening it */
1183 hFile = CreateFileW(lpszNewFile, GENERIC_WRITE, 0, 0, fFailIfExists ?
1184 CREATE_NEW : CREATE_ALWAYS, dwLocalFlagsAttribute, 0);
1185 if (INVALID_HANDLE_VALUE == hFile)
1188 /* Set up socket to retrieve data */
1189 nBytes = FTP_SendRetrieve(lpwfs, lpszRemoteFile, dwInternetFlags);
1195 /* Get data socket to server */
1196 if (FTP_GetDataSocket(lpwfs, &nDataSocket))
1201 FTP_RetrieveFileData(lpwfs, nDataSocket, nBytes, hFile);
1202 nResCode = FTP_ReceiveResponse(lpwfs, dwContext);
1205 if (nResCode == 226)
1208 FTP_SetResponseError(nResCode);
1215 if (lpwfs->lstnSocket != -1)
1216 close(lpwfs->lstnSocket);
1221 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1222 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1224 INTERNET_ASYNC_RESULT iar;
1226 iar.dwResult = (DWORD)bSuccess;
1227 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1228 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1229 &iar, sizeof(INTERNET_ASYNC_RESULT));
1236 /***********************************************************************
1237 * FtpDeleteFileA (WININET.@)
1239 * Delete a file on the ftp server
1246 BOOL WINAPI FtpDeleteFileA(HINTERNET hFtpSession, LPCSTR lpszFileName)
1248 LPWSTR lpwzFileName;
1251 lpwzFileName = lpszFileName?WININET_strdup_AtoW(lpszFileName):NULL;
1252 ret = FtpDeleteFileW(hFtpSession, lpwzFileName);
1253 if(lpwzFileName) HeapFree(GetProcessHeap(), 0, lpwzFileName);
1257 /***********************************************************************
1258 * FtpDeleteFileW (WININET.@)
1260 * Delete a file on the ftp server
1267 BOOL WINAPI FtpDeleteFileW(HINTERNET hFtpSession, LPCWSTR lpszFileName)
1269 LPWININETFTPSESSIONW lpwfs;
1270 LPWININETAPPINFOW hIC = NULL;
1273 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1274 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1276 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1280 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1281 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1283 WORKREQUEST workRequest;
1284 struct WORKREQ_FTPDELETEFILEW *req;
1286 workRequest.asyncall = FTPDELETEFILEW;
1287 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1288 req = &workRequest.u.FtpDeleteFileW;
1289 req->lpszFilename = WININET_strdupW(lpszFileName);
1291 r = INTERNET_AsyncCall(&workRequest);
1295 r = FTP_FtpDeleteFileW(hFtpSession, lpszFileName);
1300 WININET_Release( &lpwfs->hdr );
1305 /***********************************************************************
1306 * FTP_FtpDeleteFileW (Internal)
1308 * Delete a file on the ftp server
1315 BOOL FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszFileName)
1318 BOOL bSuccess = FALSE;
1319 LPWININETAPPINFOW hIC = NULL;
1321 TRACE("%p\n", lpwfs);
1323 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1325 /* Clear any error information */
1326 INTERNET_SetLastError(0);
1328 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_DELE, lpszFileName, 0, 0, 0))
1331 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1334 if (nResCode == 250)
1337 FTP_SetResponseError(nResCode);
1340 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1341 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1343 INTERNET_ASYNC_RESULT iar;
1345 iar.dwResult = (DWORD)bSuccess;
1346 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1347 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1348 &iar, sizeof(INTERNET_ASYNC_RESULT));
1355 /***********************************************************************
1356 * FtpRemoveDirectoryA (WININET.@)
1358 * Remove a directory on the ftp server
1365 BOOL WINAPI FtpRemoveDirectoryA(HINTERNET hFtpSession, LPCSTR lpszDirectory)
1367 LPWSTR lpwzDirectory;
1370 lpwzDirectory = lpszDirectory?WININET_strdup_AtoW(lpszDirectory):NULL;
1371 ret = FtpRemoveDirectoryW(hFtpSession, lpwzDirectory);
1372 if(lpwzDirectory) HeapFree(GetProcessHeap(), 0, lpwzDirectory);
1376 /***********************************************************************
1377 * FtpRemoveDirectoryW (WININET.@)
1379 * Remove a directory on the ftp server
1386 BOOL WINAPI FtpRemoveDirectoryW(HINTERNET hFtpSession, LPCWSTR lpszDirectory)
1388 LPWININETFTPSESSIONW lpwfs;
1389 LPWININETAPPINFOW hIC = NULL;
1392 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1393 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1395 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1399 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1400 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1402 WORKREQUEST workRequest;
1403 struct WORKREQ_FTPREMOVEDIRECTORYW *req;
1405 workRequest.asyncall = FTPREMOVEDIRECTORYW;
1406 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1407 req = &workRequest.u.FtpRemoveDirectoryW;
1408 req->lpszDirectory = WININET_strdupW(lpszDirectory);
1410 r = INTERNET_AsyncCall(&workRequest);
1414 r = FTP_FtpRemoveDirectoryW(lpwfs, lpszDirectory);
1419 WININET_Release( &lpwfs->hdr );
1424 /***********************************************************************
1425 * FTP_FtpRemoveDirectoryW (Internal)
1427 * Remove a directory on the ftp server
1434 BOOL FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszDirectory)
1437 BOOL bSuccess = FALSE;
1438 LPWININETAPPINFOW hIC = NULL;
1442 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1444 /* Clear any error information */
1445 INTERNET_SetLastError(0);
1447 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RMD, lpszDirectory, 0, 0, 0))
1450 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1453 if (nResCode == 250)
1456 FTP_SetResponseError(nResCode);
1460 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1461 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1463 INTERNET_ASYNC_RESULT iar;
1465 iar.dwResult = (DWORD)bSuccess;
1466 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1467 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1468 &iar, sizeof(INTERNET_ASYNC_RESULT));
1475 /***********************************************************************
1476 * FtpRenameFileA (WININET.@)
1478 * Rename a file on the ftp server
1485 BOOL WINAPI FtpRenameFileA(HINTERNET hFtpSession, LPCSTR lpszSrc, LPCSTR lpszDest)
1491 lpwzSrc = lpszSrc?WININET_strdup_AtoW(lpszSrc):NULL;
1492 lpwzDest = lpszDest?WININET_strdup_AtoW(lpszDest):NULL;
1493 ret = FtpRenameFileW(hFtpSession, lpwzSrc, lpwzDest);
1494 if(lpwzSrc) HeapFree(GetProcessHeap(), 0, lpwzSrc);
1495 if(lpwzDest) HeapFree(GetProcessHeap(), 0, lpwzDest);
1499 /***********************************************************************
1500 * FtpRenameFileW (WININET.@)
1502 * Rename a file on the ftp server
1509 BOOL WINAPI FtpRenameFileW(HINTERNET hFtpSession, LPCWSTR lpszSrc, LPCWSTR lpszDest)
1511 LPWININETFTPSESSIONW lpwfs;
1512 LPWININETAPPINFOW hIC = NULL;
1515 lpwfs = (LPWININETFTPSESSIONW) WININET_GetObject( hFtpSession );
1516 if (NULL == lpwfs || WH_HFTPSESSION != lpwfs->hdr.htype)
1518 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1522 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1523 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1525 WORKREQUEST workRequest;
1526 struct WORKREQ_FTPRENAMEFILEW *req;
1528 workRequest.asyncall = FTPRENAMEFILEW;
1529 workRequest.hdr = WININET_AddRef( &lpwfs->hdr );
1530 req = &workRequest.u.FtpRenameFileW;
1531 req->lpszSrcFile = WININET_strdupW(lpszSrc);
1532 req->lpszDestFile = WININET_strdupW(lpszDest);
1534 r = INTERNET_AsyncCall(&workRequest);
1538 r = FTP_FtpRenameFileW(hFtpSession, lpszSrc, lpszDest);
1543 WININET_Release( &lpwfs->hdr );
1548 /***********************************************************************
1549 * FTP_FtpRenameFileA (Internal)
1551 * Rename a file on the ftp server
1558 BOOL FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs,
1559 LPCWSTR lpszSrc, LPCWSTR lpszDest)
1562 BOOL bSuccess = FALSE;
1563 LPWININETAPPINFOW hIC = NULL;
1567 assert (WH_HFTPSESSION == lpwfs->hdr.htype);
1569 /* Clear any error information */
1570 INTERNET_SetLastError(0);
1572 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNFR, lpszSrc, 0, 0, 0))
1575 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1576 if (nResCode == 350)
1578 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RNTO, lpszDest, 0, 0, 0))
1581 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1584 if (nResCode == 250)
1587 FTP_SetResponseError(nResCode);
1590 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1591 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1593 INTERNET_ASYNC_RESULT iar;
1595 iar.dwResult = (DWORD)bSuccess;
1596 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1597 SendAsyncCallback(hIC, &lpwfs->hdr, lpwfs->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1598 &iar, sizeof(INTERNET_ASYNC_RESULT));
1605 /***********************************************************************
1606 * FTP_Connect (internal)
1608 * Connect to a ftp server
1611 * HINTERNET a session handle on success
1616 HINTERNET FTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1617 INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1618 LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1619 DWORD dwInternalFlags)
1621 static const WCHAR szDefaultUsername[] = {'a','n','o','n','y','m','o','u','s','\0'};
1622 static const WCHAR szDefaultPassword[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1623 struct sockaddr_in socketAddr;
1624 struct hostent *phe = NULL;
1625 INT nsocket = -1, sock_namelen;
1626 BOOL bSuccess = FALSE;
1627 LPWININETFTPSESSIONW lpwfs = NULL;
1628 HINTERNET handle = NULL;
1630 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1631 hIC, debugstr_w(lpszServerName),
1632 nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword));
1634 assert( hIC->hdr.htype != WH_HINIT );
1636 if (NULL == lpszUserName && NULL != lpszPassword)
1638 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1642 lpwfs = HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW));
1645 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1649 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1650 nServerPort = INTERNET_DEFAULT_FTP_PORT;
1652 lpwfs->hdr.htype = WH_HFTPSESSION;
1653 lpwfs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1654 lpwfs->hdr.dwFlags = dwFlags;
1655 lpwfs->hdr.dwContext = dwContext;
1656 lpwfs->hdr.dwInternalFlags = dwInternalFlags;
1657 lpwfs->hdr.dwRefCount = 1;
1658 lpwfs->hdr.destroy = FTP_CloseSessionHandle;
1659 lpwfs->download_in_progress = NULL;
1661 handle = WININET_AllocHandle( &lpwfs->hdr );
1664 ERR("Failed to alloc handle\n");
1665 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1669 if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1670 if(strchrW(hIC->lpszProxy, ' '))
1671 FIXME("Several proxies not implemented.\n");
1672 if(hIC->lpszProxyBypass)
1673 FIXME("Proxy bypass is ignored.\n");
1675 if ( !lpszUserName) {
1676 lpwfs->lpszUserName = WININET_strdupW(szDefaultUsername);
1677 lpwfs->lpszPassword = WININET_strdupW(szDefaultPassword);
1680 lpwfs->lpszUserName = WININET_strdupW(lpszUserName);
1681 lpwfs->lpszPassword = WININET_strdupW(lpszPassword);
1684 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1685 if (hIC->lpfnStatusCB && !(lpwfs->hdr.dwInternalFlags & INET_OPENURL))
1687 INTERNET_ASYNC_RESULT iar;
1689 iar.dwResult = (DWORD)handle;
1690 iar.dwError = ERROR_SUCCESS;
1692 SendAsyncCallback(hIC, &hIC->hdr, dwContext,
1693 INTERNET_STATUS_HANDLE_CREATED, &iar,
1694 sizeof(INTERNET_ASYNC_RESULT));
1697 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_RESOLVING_NAME,
1698 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1700 if (!GetAddress(lpszServerName, nServerPort, &phe, &socketAddr))
1702 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1706 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_NAME_RESOLVED,
1707 (LPWSTR) lpszServerName, strlenW(lpszServerName));
1709 nsocket = socket(AF_INET,SOCK_STREAM,0);
1712 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1716 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_CONNECTING_TO_SERVER,
1717 &socketAddr, sizeof(struct sockaddr_in));
1719 if (connect(nsocket, (struct sockaddr *)&socketAddr, sizeof(socketAddr)) < 0)
1721 ERR("Unable to connect (%s)\n", strerror(errno));
1722 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT);
1726 TRACE("Connected to server\n");
1727 lpwfs->sndSocket = nsocket;
1728 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_CONNECTED_TO_SERVER,
1729 &socketAddr, sizeof(struct sockaddr_in));
1731 sock_namelen = sizeof(lpwfs->socketAddress);
1732 getsockname(nsocket, (struct sockaddr *) &lpwfs->socketAddress, &sock_namelen);
1733 lpwfs->phostent = phe;
1735 if (FTP_ConnectToHost(lpwfs))
1737 TRACE("Successfully logged into server\n");
1743 if (!bSuccess && nsocket == -1)
1746 if (!bSuccess && lpwfs)
1748 HeapFree(GetProcessHeap(), 0, lpwfs);
1749 WININET_FreeHandle( handle );
1753 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
1755 INTERNET_ASYNC_RESULT iar;
1757 iar.dwResult = (DWORD)lpwfs;
1758 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1759 SendAsyncCallback(hIC, &hIC->hdr, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
1760 &iar, sizeof(INTERNET_ASYNC_RESULT));
1767 /***********************************************************************
1768 * FTP_ConnectToHost (internal)
1770 * Connect to a ftp server
1777 BOOL FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs)
1780 BOOL bSuccess = FALSE;
1783 FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1785 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_USER, lpwfs->lpszUserName, 0, 0, 0))
1788 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1791 /* Login successful... */
1792 if (nResCode == 230)
1794 /* User name okay, need password... */
1795 else if (nResCode == 331)
1796 bSuccess = FTP_SendPassword(lpwfs);
1797 /* Need account for login... */
1798 else if (nResCode == 332)
1799 bSuccess = FTP_SendAccount(lpwfs);
1801 FTP_SetResponseError(nResCode);
1804 TRACE("Returning %d\n", bSuccess);
1810 /***********************************************************************
1811 * FTP_SendCommandA (internal)
1813 * Send command to server
1820 BOOL FTP_SendCommandA(INT nSocket, FTP_COMMAND ftpCmd, LPCSTR lpszParam,
1821 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1825 DWORD nBytesSent = 0;
1829 TRACE("%d: (%s) %d\n", ftpCmd, lpszParam, nSocket);
1833 HINTERNET hHandle = WININET_FindHandle( hdr );
1836 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1837 WININET_Release( hdr );
1841 dwParamLen = lpszParam?strlen(lpszParam)+1:0;
1842 len = dwParamLen + strlen(szFtpCommands[ftpCmd]) + strlen(szCRLF);
1843 if (NULL == (buf = HeapAlloc(GetProcessHeap(), 0, len+1)))
1845 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1848 sprintf(buf, "%s%s%s%s", szFtpCommands[ftpCmd], dwParamLen ? " " : "",
1849 dwParamLen ? lpszParam : "", szCRLF);
1851 TRACE("Sending (%s) len(%ld)\n", buf, len);
1852 while((nBytesSent < len) && (nRC != -1))
1854 nRC = send(nSocket, buf+nBytesSent, len - nBytesSent, 0);
1858 HeapFree(GetProcessHeap(), 0, (LPVOID)buf);
1862 HINTERNET hHandle = WININET_FindHandle( hdr );
1865 lpfnStatusCB(hHandle, dwContext, INTERNET_STATUS_REQUEST_SENT,
1866 &nBytesSent, sizeof(DWORD));
1867 WININET_Release( hdr );
1871 TRACE("Sent %ld bytes\n", nBytesSent);
1875 /***********************************************************************
1876 * FTP_SendCommand (internal)
1878 * Send command to server
1885 BOOL FTP_SendCommand(INT nSocket, FTP_COMMAND ftpCmd, LPCWSTR lpszParam,
1886 INTERNET_STATUS_CALLBACK lpfnStatusCB, LPWININETHANDLEHEADER hdr, DWORD dwContext)
1889 LPSTR lpszParamA = lpszParam?WININET_strdup_WtoA(lpszParam):NULL;
1890 ret = FTP_SendCommandA(nSocket, ftpCmd, lpszParamA, lpfnStatusCB, hdr, dwContext);
1891 HeapFree(GetProcessHeap(), 0, lpszParamA);
1895 /***********************************************************************
1896 * FTP_ReceiveResponse (internal)
1898 * Receive response from server
1901 * Reply code on success
1905 INT FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs, DWORD dwContext)
1907 LPSTR lpszResponse = INTERNET_GetResponseBuffer();
1910 char firstprefix[5];
1911 BOOL multiline = FALSE;
1912 LPWININETAPPINFOW hIC = NULL;
1914 TRACE("socket(%d) \n", lpwfs->sndSocket);
1916 hIC = (LPWININETAPPINFOW) lpwfs->hdr.lpwhparent;
1917 SendAsyncCallback(hIC, &lpwfs->hdr, dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1921 if (!INTERNET_GetNextLine(lpwfs->sndSocket, &nRecv))
1928 if(lpszResponse[3] != '-')
1931 { /* Start of multiline repsonse. Loop until we get "nnn " */
1933 memcpy(firstprefix, lpszResponse, 3);
1934 firstprefix[3] = ' ';
1935 firstprefix[4] = '\0';
1940 if(!memcmp(firstprefix, lpszResponse, 4))
1948 rc = atoi(lpszResponse);
1950 SendAsyncCallback(hIC, &lpwfs->hdr, dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
1951 &nRecv, sizeof(DWORD));
1955 TRACE("return %d\n", rc);
1960 /***********************************************************************
1961 * FTP_SendPassword (internal)
1963 * Send password to ftp server
1970 BOOL FTP_SendPassword(LPWININETFTPSESSIONW lpwfs)
1973 BOOL bSuccess = FALSE;
1976 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASS, lpwfs->lpszPassword, 0, 0, 0))
1979 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
1982 TRACE("Received reply code %d\n", nResCode);
1983 /* Login successful... */
1984 if (nResCode == 230)
1986 /* Command not implemented, superfluous at the server site... */
1987 /* Need account for login... */
1988 else if (nResCode == 332)
1989 bSuccess = FTP_SendAccount(lpwfs);
1991 FTP_SetResponseError(nResCode);
1995 TRACE("Returning %d\n", bSuccess);
2000 /***********************************************************************
2001 * FTP_SendAccount (internal)
2010 BOOL FTP_SendAccount(LPWININETFTPSESSIONW lpwfs)
2013 BOOL bSuccess = FALSE;
2016 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_ACCT, szNoAccount, 0, 0, 0))
2019 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2023 FTP_SetResponseError(nResCode);
2030 /***********************************************************************
2031 * FTP_SendStore (internal)
2033 * Send request to upload file to ftp server
2040 BOOL FTP_SendStore(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2043 BOOL bSuccess = FALSE;
2046 if (!FTP_InitListenSocket(lpwfs))
2049 if (!FTP_SendType(lpwfs, dwType))
2052 if (!FTP_SendPortOrPasv(lpwfs))
2055 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_STOR, lpszRemoteFile, 0, 0, 0))
2057 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2060 if (nResCode == 150)
2063 FTP_SetResponseError(nResCode);
2067 if (!bSuccess && lpwfs->lstnSocket != -1)
2069 close(lpwfs->lstnSocket);
2070 lpwfs->lstnSocket = -1;
2077 /***********************************************************************
2078 * FTP_InitListenSocket (internal)
2080 * Create a socket to listen for server response
2087 BOOL FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs)
2089 BOOL bSuccess = FALSE;
2090 size_t namelen = sizeof(struct sockaddr_in);
2094 lpwfs->lstnSocket = socket(PF_INET, SOCK_STREAM, 0);
2095 if (lpwfs->lstnSocket == -1)
2097 TRACE("Unable to create listening socket\n");
2101 /* We obtain our ip addr from the name of the command channel socket */
2102 lpwfs->lstnSocketAddress = lpwfs->socketAddress;
2104 /* and get the system to assign us a port */
2105 lpwfs->lstnSocketAddress.sin_port = htons((u_short) 0);
2107 if (bind(lpwfs->lstnSocket,(struct sockaddr *) &lpwfs->lstnSocketAddress, sizeof(struct sockaddr_in)) == -1)
2109 TRACE("Unable to bind socket\n");
2113 if (listen(lpwfs->lstnSocket, MAX_BACKLOG) == -1)
2115 TRACE("listen failed\n");
2119 if (getsockname(lpwfs->lstnSocket, (struct sockaddr *) &lpwfs->lstnSocketAddress, &namelen) != -1)
2123 if (!bSuccess && lpwfs->lstnSocket == -1)
2125 close(lpwfs->lstnSocket);
2126 lpwfs->lstnSocket = -1;
2133 /***********************************************************************
2134 * FTP_SendType (internal)
2136 * Tell server type of data being transferred
2142 * W98SE doesn't cache the type that's currently set
2143 * (i.e. it sends it always),
2144 * so we probably don't want to do that either.
2146 BOOL FTP_SendType(LPWININETFTPSESSIONW lpwfs, DWORD dwType)
2149 WCHAR type[] = { 'I','\0' };
2150 BOOL bSuccess = FALSE;
2153 if (dwType & INTERNET_FLAG_TRANSFER_ASCII)
2156 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_TYPE, type, 0, 0, 0))
2159 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext)/100;
2165 FTP_SetResponseError(nResCode);
2172 /***********************************************************************
2173 * FTP_GetFileSize (internal)
2175 * Retrieves from the server the size of the given file
2182 BOOL FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD *dwSize)
2185 BOOL bSuccess = FALSE;
2189 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_SIZE, lpszRemoteFile, 0, 0, 0))
2192 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2195 if (nResCode == 213) {
2196 /* Now parses the output to get the actual file size */
2198 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2200 for (i = 0; (lpszResponseBuffer[i] != ' ') && (lpszResponseBuffer[i] != '\0'); i++) ;
2201 if (lpszResponseBuffer[i] == '\0') return FALSE;
2202 *dwSize = atol(&(lpszResponseBuffer[i + 1]));
2206 FTP_SetResponseError(nResCode);
2215 /***********************************************************************
2216 * FTP_SendPort (internal)
2218 * Tell server which port to use
2225 BOOL FTP_SendPort(LPWININETFTPSESSIONW lpwfs)
2227 static const WCHAR szIPFormat[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2229 WCHAR szIPAddress[64];
2230 BOOL bSuccess = FALSE;
2233 sprintfW(szIPAddress, szIPFormat,
2234 lpwfs->lstnSocketAddress.sin_addr.s_addr&0x000000FF,
2235 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x0000FF00)>>8,
2236 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0x00FF0000)>>16,
2237 (lpwfs->lstnSocketAddress.sin_addr.s_addr&0xFF000000)>>24,
2238 lpwfs->lstnSocketAddress.sin_port & 0xFF,
2239 (lpwfs->lstnSocketAddress.sin_port & 0xFF00)>>8);
2241 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PORT, szIPAddress, 0, 0, 0))
2244 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2247 if (nResCode == 200)
2250 FTP_SetResponseError(nResCode);
2258 /***********************************************************************
2259 * FTP_DoPassive (internal)
2261 * Tell server that we want to do passive transfers
2262 * and connect data socket
2269 BOOL FTP_DoPassive(LPWININETFTPSESSIONW lpwfs)
2272 BOOL bSuccess = FALSE;
2275 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_PASV, NULL, 0, 0, 0))
2278 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2281 if (nResCode == 227)
2283 LPSTR lpszResponseBuffer = INTERNET_GetResponseBuffer();
2287 char *pAddr, *pPort;
2289 struct sockaddr_in dataSocketAddress;
2291 p = lpszResponseBuffer+4; /* skip status code */
2293 /* do a very strict check; we can improve that later. */
2295 if (strncmp(p, "Entering Passive Mode", 21))
2297 ERR("unknown response '%.*s', aborting\n", 21, p);
2300 p += 21; /* skip string */
2301 if ((*p++ != ' ') || (*p++ != '('))
2303 ERR("unknown response format, aborting\n");
2307 if (sscanf(p, "%d,%d,%d,%d,%d,%d", &f[0], &f[1], &f[2], &f[3],
2310 ERR("unknown response address format '%s', aborting\n", p);
2313 for (i=0; i < 6; i++)
2316 dataSocketAddress = lpwfs->socketAddress;
2317 pAddr = (char *)&(dataSocketAddress.sin_addr.s_addr);
2318 pPort = (char *)&(dataSocketAddress.sin_port);
2326 nsocket = socket(AF_INET,SOCK_STREAM,0);
2330 if (connect(nsocket, (struct sockaddr *)&dataSocketAddress, sizeof(dataSocketAddress)))
2332 ERR("can't connect passive FTP data port.\n");
2335 lpwfs->pasvSocket = nsocket;
2339 FTP_SetResponseError(nResCode);
2347 BOOL FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs)
2349 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2351 if (!FTP_DoPassive(lpwfs))
2356 if (!FTP_SendPort(lpwfs))
2363 /***********************************************************************
2364 * FTP_GetDataSocket (internal)
2366 * Either accepts an incoming data socket connection from the server
2367 * or just returns the already opened socket after a PASV command
2368 * in case of passive FTP.
2376 BOOL FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs, LPINT nDataSocket)
2378 struct sockaddr_in saddr;
2379 size_t addrlen = sizeof(struct sockaddr);
2382 if (lpwfs->hdr.dwFlags & INTERNET_FLAG_PASSIVE)
2384 *nDataSocket = lpwfs->pasvSocket;
2388 *nDataSocket = accept(lpwfs->lstnSocket, (struct sockaddr *) &saddr, &addrlen);
2389 close(lpwfs->lstnSocket);
2390 lpwfs->lstnSocket = -1;
2392 return *nDataSocket != -1;
2396 /***********************************************************************
2397 * FTP_SendData (internal)
2399 * Send data to the server
2406 BOOL FTP_SendData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, HANDLE hFile)
2408 BY_HANDLE_FILE_INFORMATION fi;
2409 DWORD nBytesRead = 0;
2410 DWORD nBytesSent = 0;
2411 DWORD nTotalSent = 0;
2412 DWORD nBytesToSend, nLen, nRC = 1;
2413 time_t s_long_time, e_long_time;
2418 lpszBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2419 memset(lpszBuffer, 0, sizeof(CHAR)*DATA_PACKET_SIZE);
2421 /* Get the size of the file. */
2422 GetFileInformationByHandle(hFile, &fi);
2427 nBytesToSend = nBytesRead - nBytesSent;
2429 if (nBytesToSend <= 0)
2431 /* Read data from file. */
2433 if (!ReadFile(hFile, lpszBuffer, DATA_PACKET_SIZE, &nBytesRead, 0))
2434 ERR("Failed reading from file\n");
2437 nBytesToSend = nBytesRead;
2442 nLen = DATA_PACKET_SIZE < nBytesToSend ?
2443 DATA_PACKET_SIZE : nBytesToSend;
2444 nRC = send(nDataSocket, lpszBuffer, nLen, 0);
2452 /* Do some computation to display the status. */
2454 nSeconds = e_long_time - s_long_time;
2455 if( nSeconds / 60 > 0 )
2457 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2458 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds / 60,
2459 nSeconds % 60, (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent );
2463 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2464 nTotalSent, fi.nFileSizeLow, nTotalSent*100/fi.nFileSizeLow, nSeconds,
2465 (fi.nFileSizeLow - nTotalSent) * nSeconds / nTotalSent);
2467 } while (nRC != -1);
2469 TRACE("file transfer complete!\n");
2471 if(lpszBuffer != NULL)
2472 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2478 /***********************************************************************
2479 * FTP_SendRetrieve (internal)
2481 * Send request to retrieve a file
2484 * Number of bytes to be received on success
2488 DWORD FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs, LPCWSTR lpszRemoteFile, DWORD dwType)
2494 if (!FTP_InitListenSocket(lpwfs))
2497 if (!FTP_SendType(lpwfs, dwType))
2500 if (!FTP_SendPortOrPasv(lpwfs))
2503 if (!FTP_GetFileSize(lpwfs, lpszRemoteFile, &nResult))
2506 TRACE("Waiting to receive %ld bytes\n", nResult);
2508 if (!FTP_SendCommand(lpwfs->sndSocket, FTP_CMD_RETR, lpszRemoteFile, 0, 0, 0))
2511 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2512 if ((nResCode != 125) && (nResCode != 150)) {
2513 /* That means that we got an error getting the file. */
2518 if (0 == nResult && lpwfs->lstnSocket != -1)
2520 close(lpwfs->lstnSocket);
2521 lpwfs->lstnSocket = -1;
2528 /***********************************************************************
2529 * FTP_RetrieveData (internal)
2531 * Retrieve data from server
2538 BOOL FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs, INT nDataSocket, DWORD nBytes, HANDLE hFile)
2540 DWORD nBytesWritten;
2541 DWORD nBytesReceived = 0;
2547 if (INVALID_HANDLE_VALUE == hFile)
2550 lpszBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CHAR)*DATA_PACKET_SIZE);
2551 if (NULL == lpszBuffer)
2553 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2557 while (nBytesReceived < nBytes && nRC != -1)
2559 nRC = recv(nDataSocket, lpszBuffer, DATA_PACKET_SIZE, 0);
2562 /* other side closed socket. */
2565 WriteFile(hFile, lpszBuffer, nRC, &nBytesWritten, NULL);
2566 nBytesReceived += nRC;
2569 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived, nBytes,
2570 nBytesReceived * 100 / nBytes);
2573 TRACE("Data transfer complete\n");
2574 if (NULL != lpszBuffer)
2575 HeapFree(GetProcessHeap(), 0, lpszBuffer);
2582 /***********************************************************************
2583 * FTP_CloseSessionHandle (internal)
2585 * Deallocate session handle
2592 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr)
2594 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) hdr;
2598 if (lpwfs->download_in_progress != NULL)
2599 lpwfs->download_in_progress->session_deleted = TRUE;
2601 if (lpwfs->sndSocket != -1)
2602 close(lpwfs->sndSocket);
2604 if (lpwfs->lstnSocket != -1)
2605 close(lpwfs->lstnSocket);
2607 if (lpwfs->lpszPassword)
2608 HeapFree(GetProcessHeap(), 0, lpwfs->lpszPassword);
2610 if (lpwfs->lpszUserName)
2611 HeapFree(GetProcessHeap(), 0, lpwfs->lpszUserName);
2613 HeapFree(GetProcessHeap(), 0, lpwfs);
2617 /***********************************************************************
2618 * FTP_CloseFindNextHandle (internal)
2620 * Deallocate session handle
2627 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr)
2629 LPWININETFINDNEXTW lpwfn = (LPWININETFINDNEXTW) hdr;
2634 for (i = 0; i < lpwfn->size; i++)
2636 if (NULL != lpwfn->lpafp[i].lpszName)
2637 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp[i].lpszName);
2640 HeapFree(GetProcessHeap(), 0, lpwfn->lpafp);
2641 HeapFree(GetProcessHeap(), 0, lpwfn);
2644 /***********************************************************************
2645 * FTP_CloseFileTransferHandle (internal)
2647 * Closes the file transfer handle. This also 'cleans' the data queue of
2648 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2651 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr)
2653 LPWININETFILE lpwh = (LPWININETFILE) hdr;
2654 LPWININETFTPSESSIONW lpwfs = (LPWININETFTPSESSIONW) lpwh->hdr.lpwhparent;
2659 if (!lpwh->session_deleted)
2660 lpwfs->download_in_progress = NULL;
2662 /* This just serves to flush the control socket of any spurrious lines written
2663 to it (like '226 Transfer complete.').
2665 Wonder what to do if the server sends us an error code though...
2667 nResCode = FTP_ReceiveResponse(lpwfs, lpwfs->hdr.dwContext);
2669 if (lpwh->nDataSocket != -1)
2670 close(lpwh->nDataSocket);
2672 HeapFree(GetProcessHeap(), 0, lpwh);
2675 /***********************************************************************
2676 * FTP_ReceiveFileList (internal)
2678 * Read file list from server
2681 * Handle to file list on success
2685 HINTERNET FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2686 LPWIN32_FIND_DATAW lpFindFileData, DWORD dwContext)
2689 LPFILEPROPERTIESW lpafp = NULL;
2690 LPWININETFINDNEXTW lpwfn = NULL;
2691 HINTERNET handle = 0;
2693 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs, nSocket, debugstr_w(lpszSearchFile), lpFindFileData, dwContext);
2695 if (FTP_ParseDirectory(lpwfs, nSocket, lpszSearchFile, &lpafp, &dwSize))
2698 FTP_ConvertFileProp(lpafp, lpFindFileData);
2700 lpwfn = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETFINDNEXTW));
2703 lpwfn->hdr.htype = WH_HFINDNEXT;
2704 lpwfn->hdr.lpwhparent = WININET_AddRef( &lpwfs->hdr );
2705 lpwfn->hdr.dwContext = dwContext;
2706 lpwfn->hdr.dwRefCount = 1;
2707 lpwfn->hdr.destroy = FTP_CloseFindNextHandle;
2708 lpwfn->index = 1; /* Next index is 1 since we return index 0 */
2709 lpwfn->size = dwSize;
2710 lpwfn->lpafp = lpafp;
2712 handle = WININET_AllocHandle( &lpwfn->hdr );
2717 WININET_Release( &lpwfn->hdr );
2719 TRACE("Matched %ld files\n", dwSize);
2724 /***********************************************************************
2725 * FTP_ConvertFileProp (internal)
2727 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2734 BOOL FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp, LPWIN32_FIND_DATAW lpFindFileData)
2736 BOOL bSuccess = FALSE;
2738 ZeroMemory(lpFindFileData, sizeof(WIN32_FIND_DATAW));
2742 /* Convert 'Unix' time to Windows time */
2743 RtlSecondsSince1970ToTime(mktime(&lpafp->tmLastModified),
2744 (LARGE_INTEGER *) &(lpFindFileData->ftLastAccessTime));
2746 /* Not all fields are filled in */
2747 lpFindFileData->nFileSizeHigh = 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2748 lpFindFileData->nFileSizeLow = lpafp->nSize;
2750 if (lpafp->bIsDirectory)
2751 lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
2753 if (lpafp->lpszName)
2754 strncpyW(lpFindFileData->cFileName, lpafp->lpszName, MAX_PATH);
2762 /***********************************************************************
2763 * FTP_ParseNextFile (internal)
2765 * Parse the next line in file listing
2771 BOOL FTP_ParseNextFile(INT nSocket, LPCWSTR lpszSearchFile, LPFILEPROPERTIESW lpfp)
2773 static const char szSpace[] = " \t";
2781 lpfp->lpszName = NULL;
2783 if(!(pszLine = INTERNET_GetNextLine(nSocket, &nBufLen)))
2786 pszToken = strtok(pszLine, szSpace);
2788 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2791 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2793 if(!isdigit(pszToken[0]) && 10 == strlen(pszToken)) {
2794 if(!FTP_ParsePermission(pszToken, lpfp))
2795 lpfp->bIsDirectory = FALSE;
2796 for(i=0; i<=3; i++) {
2797 if(!(pszToken = strtok(NULL, szSpace)))
2800 if(!pszToken) continue;
2801 if(lpfp->bIsDirectory) {
2802 TRACE("Is directory\n");
2806 TRACE("Size: %s\n", pszToken);
2807 lpfp->nSize = atol(pszToken);
2810 lpfp->tmLastModified.tm_sec = 0;
2811 lpfp->tmLastModified.tm_min = 0;
2812 lpfp->tmLastModified.tm_hour = 0;
2813 lpfp->tmLastModified.tm_mday = 0;
2814 lpfp->tmLastModified.tm_mon = 0;
2815 lpfp->tmLastModified.tm_year = 0;
2817 /* Determine month */
2818 pszToken = strtok(NULL, szSpace);
2819 if(!pszToken) continue;
2820 if(strlen(pszToken) >= 3) {
2822 if((pszTmp = StrStrIA(szMonths, pszToken)))
2823 lpfp->tmLastModified.tm_mon = ((pszTmp - szMonths) / 3)+1;
2826 pszToken = strtok(NULL, szSpace);
2827 if(!pszToken) continue;
2828 lpfp->tmLastModified.tm_mday = atoi(pszToken);
2829 /* Determine time or year */
2830 pszToken = strtok(NULL, szSpace);
2831 if(!pszToken) continue;
2832 if((pszTmp = strchr(pszToken, ':'))) {
2837 lpfp->tmLastModified.tm_min = atoi(pszTmp);
2838 lpfp->tmLastModified.tm_hour = atoi(pszToken);
2840 apTM = localtime(&aTime);
2841 lpfp->tmLastModified.tm_year = apTM->tm_year;
2844 lpfp->tmLastModified.tm_year = atoi(pszToken) - 1900;
2845 lpfp->tmLastModified.tm_hour = 12;
2847 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2848 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2849 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2850 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2852 pszToken = strtok(NULL, szSpace);
2853 if(!pszToken) continue;
2854 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2855 TRACE("File: %s\n", debugstr_w(lpfp->lpszName));
2857 /* NT way of parsing ... :
2859 07-13-03 08:55PM <DIR> sakpatch
2860 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2862 else if(isdigit(pszToken[0]) && 8 == strlen(pszToken)) {
2863 lpfp->permissions = 0xFFFF; /* No idea, put full permission :-) */
2865 sscanf(pszToken, "%d-%d-%d",
2866 &lpfp->tmLastModified.tm_mon,
2867 &lpfp->tmLastModified.tm_mday,
2868 &lpfp->tmLastModified.tm_year);
2870 /* Hacky and bad Y2K protection :-) */
2871 if (lpfp->tmLastModified.tm_year < 70)
2872 lpfp->tmLastModified.tm_year += 100;
2874 pszToken = strtok(NULL, szSpace);
2875 if(!pszToken) continue;
2876 sscanf(pszToken, "%d:%d",
2877 &lpfp->tmLastModified.tm_hour,
2878 &lpfp->tmLastModified.tm_min);
2879 if((pszToken[5] == 'P') && (pszToken[6] == 'M')) {
2880 lpfp->tmLastModified.tm_hour += 12;
2882 lpfp->tmLastModified.tm_sec = 0;
2884 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2885 lpfp->tmLastModified.tm_hour, lpfp->tmLastModified.tm_min, lpfp->tmLastModified.tm_sec,
2886 (lpfp->tmLastModified.tm_year >= 100) ? lpfp->tmLastModified.tm_year - 100 : lpfp->tmLastModified.tm_year,
2887 lpfp->tmLastModified.tm_mon, lpfp->tmLastModified.tm_mday);
2889 pszToken = strtok(NULL, szSpace);
2890 if(!pszToken) continue;
2891 if(!strcasecmp(pszToken, "<DIR>")) {
2892 lpfp->bIsDirectory = TRUE;
2894 TRACE("Is directory\n");
2897 lpfp->bIsDirectory = FALSE;
2898 lpfp->nSize = atol(pszToken);
2899 TRACE("Size: %ld\n", lpfp->nSize);
2902 pszToken = strtok(NULL, szSpace);
2903 if(!pszToken) continue;
2904 lpfp->lpszName = WININET_strdup_AtoW(pszToken);
2905 TRACE("Name: %s\n", debugstr_w(lpfp->lpszName));
2907 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2908 else if(pszToken[0] == '+') {
2909 FIXME("EPLF Format not implemented\n");
2912 if(lpfp->lpszName) {
2913 if((lpszSearchFile == NULL) ||
2914 (PathMatchSpecW(lpfp->lpszName, lpszSearchFile))) {
2916 TRACE("Matched: %s\n", debugstr_w(lpfp->lpszName));
2919 HeapFree(GetProcessHeap(), 0, lpfp->lpszName);
2920 lpfp->lpszName = NULL;
2927 /***********************************************************************
2928 * FTP_ParseDirectory (internal)
2930 * Parse string of directory information
2936 BOOL FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs, INT nSocket, LPCWSTR lpszSearchFile,
2937 LPFILEPROPERTIESW *lpafp, LPDWORD dwfp)
2939 BOOL bSuccess = TRUE;
2940 INT sizeFilePropArray = 500;/*20; */
2941 INT indexFilePropArray = -1;
2945 /* Allocate intial file properties array */
2946 *lpafp = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FILEPROPERTIESW)*(sizeFilePropArray));
2951 if (indexFilePropArray+1 >= sizeFilePropArray)
2953 LPFILEPROPERTIESW tmpafp;
2955 sizeFilePropArray *= 2;
2956 tmpafp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *lpafp,
2957 sizeof(FILEPROPERTIESW)*sizeFilePropArray);
2966 indexFilePropArray++;
2967 } while (FTP_ParseNextFile(nSocket, lpszSearchFile, &(*lpafp)[indexFilePropArray]));
2969 if (bSuccess && indexFilePropArray)
2971 if (indexFilePropArray < sizeFilePropArray - 1)
2973 LPFILEPROPERTIESW tmpafp;
2975 tmpafp = HeapReAlloc(GetProcessHeap(), 0, *lpafp,
2976 sizeof(FILEPROPERTIESW)*indexFilePropArray);
2980 *dwfp = indexFilePropArray;
2984 HeapFree(GetProcessHeap(), 0, *lpafp);
2985 INTERNET_SetLastError(ERROR_NO_MORE_FILES);
2993 /***********************************************************************
2994 * FTP_ParsePermission (internal)
2996 * Parse permission string of directory information
3003 BOOL FTP_ParsePermission(LPCSTR lpszPermission, LPFILEPROPERTIESW lpfp)
3005 BOOL bSuccess = TRUE;
3006 unsigned short nPermission = 0;
3011 if ((*lpszPermission != 'd') && (*lpszPermission != '-') && (*lpszPermission != 'l'))
3017 lpfp->bIsDirectory = (*lpszPermission == 'd');
3023 nPermission |= (*(lpszPermission+1) == 'r' ? 1 : 0) << 8;
3026 nPermission |= (*(lpszPermission+2) == 'w' ? 1 : 0) << 7;
3029 nPermission |= (*(lpszPermission+3) == 'x' ? 1 : 0) << 6;
3032 nPermission |= (*(lpszPermission+4) == 'r' ? 1 : 0) << 5;
3035 nPermission |= (*(lpszPermission+5) == 'w' ? 1 : 0) << 4;
3038 nPermission |= (*(lpszPermission+6) == 'x' ? 1 : 0) << 3;
3041 nPermission |= (*(lpszPermission+7) == 'r' ? 1 : 0) << 2;
3044 nPermission |= (*(lpszPermission+8) == 'w' ? 1 : 0) << 1;
3047 nPermission |= (*(lpszPermission+9) == 'x' ? 1 : 0);
3051 }while (nPos <= nLast);
3053 lpfp->permissions = nPermission;
3058 /***********************************************************************
3059 * FTP_SetResponseError (internal)
3061 * Set the appropriate error code for a given response from the server
3066 DWORD FTP_SetResponseError(DWORD dwResponse)
3072 case 421: /* Service not available - Server may be shutting down. */
3073 dwCode = ERROR_INTERNET_TIMEOUT;
3076 case 425: /* Cannot open data connection. */
3077 dwCode = ERROR_INTERNET_CANNOT_CONNECT;
3080 case 426: /* Connection closed, transer aborted. */
3081 dwCode = ERROR_INTERNET_CONNECTION_ABORTED;
3084 case 500: /* Syntax error. Command unrecognized. */
3085 case 501: /* Syntax error. Error in parameters or arguments. */
3086 dwCode = ERROR_INTERNET_INCORRECT_FORMAT;
3089 case 530: /* Not logged in. Login incorrect. */
3090 dwCode = ERROR_INTERNET_LOGIN_FAILURE;
3093 case 550: /* File action not taken. File not found or no access. */
3094 dwCode = ERROR_INTERNET_ITEM_NOT_FOUND;
3097 case 450: /* File action not taken. File may be busy. */
3098 case 451: /* Action aborted. Server error. */
3099 case 452: /* Action not taken. Insufficient storage space on server. */
3100 case 502: /* Command not implemented. */
3101 case 503: /* Bad sequence of command. */
3102 case 504: /* Command not implemented for that parameter. */
3103 case 532: /* Need account for storing files */
3104 case 551: /* Requested action aborted. Page type unknown */
3105 case 552: /* Action aborted. Exceeded storage allocation */
3106 case 553: /* Action not taken. File name not allowed. */
3109 dwCode = ERROR_INTERNET_INTERNAL_ERROR;
3113 INTERNET_SetLastError(dwCode);