2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
11 * Copyright 2000 Andreas Mohr
12 * Copyright 2002 Jaco Greeff
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
58 #include "wine/debug.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
63 #define DATA_PACKET_SIZE 0x2000
68 /* FTP commands with arguments. */
84 /* FTP commands without arguments. */
93 static const CHAR
*szFtpCommands
[] = {
116 static const CHAR szMonths
[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
117 static const WCHAR szNoAccount
[] = {'n','o','a','c','c','o','u','n','t','\0'};
119 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
);
120 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
);
121 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
);
122 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
);
124 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
);
125 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
);
126 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
);
127 static INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD dwContext
);
128 static DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
);
129 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
);
130 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
);
131 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
);
132 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
);
133 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
);
134 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
);
135 static BOOL
FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD
*dwSize
);
136 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
);
137 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
);
138 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
);
139 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
);
140 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW fileprop
);
141 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
142 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
);
143 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
144 LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwContext
);
145 static DWORD
FTP_SetResponseError(DWORD dwResponse
);
147 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
157 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
158 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
160 LPWSTR lpwzLocalFile
;
161 LPWSTR lpwzNewRemoteFile
;
164 lpwzLocalFile
= lpszLocalFile
?WININET_strdup_AtoW(lpszLocalFile
):NULL
;
165 lpwzNewRemoteFile
= lpszNewRemoteFile
?WININET_strdup_AtoW(lpszNewRemoteFile
):NULL
;
166 ret
= FtpPutFileW(hConnect
, lpwzLocalFile
, lpwzNewRemoteFile
,
168 HeapFree(GetProcessHeap(), 0, lpwzLocalFile
);
169 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile
);
173 /***********************************************************************
174 * FtpPutFileW (WININET.@)
176 * Uploads a file to the FTP server
183 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);
255 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
257 /* Open file to be uploaded */
258 if (INVALID_HANDLE_VALUE
==
259 (hFile
= CreateFileW(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
261 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND
);
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
= NULL
;
343 LPWININETAPPINFOW hIC
= NULL
;
348 SetLastError(ERROR_INVALID_PARAMETER
);
352 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
353 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
355 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
359 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
361 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
362 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
364 WORKREQUEST workRequest
;
365 struct WORKREQ_FTPSETCURRENTDIRECTORYW
*req
;
367 workRequest
.asyncall
= FTPSETCURRENTDIRECTORYW
;
368 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
369 req
= &workRequest
.u
.FtpSetCurrentDirectoryW
;
370 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
372 r
= INTERNET_AsyncCall(&workRequest
);
376 r
= FTP_FtpSetCurrentDirectoryW(lpwfs
, lpszDirectory
);
381 WININET_Release( &lpwfs
->hdr
);
387 /***********************************************************************
388 * FTP_FtpSetCurrentDirectoryW (Internal)
390 * Change the working directory on the FTP server
397 BOOL WINAPI
FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
400 LPWININETAPPINFOW hIC
= NULL
;
401 DWORD bSuccess
= FALSE
;
403 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
405 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
407 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
411 /* Clear any error information */
412 INTERNET_SetLastError(0);
414 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
415 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
416 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
419 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
426 FTP_SetResponseError(nResCode
);
430 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
432 INTERNET_ASYNC_RESULT iar
;
434 iar
.dwResult
= (DWORD
)bSuccess
;
435 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
436 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
437 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
443 /***********************************************************************
444 * FtpCreateDirectoryA (WININET.@)
446 * Create new directory on the FTP server
453 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
455 LPWSTR lpwzDirectory
;
458 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
459 ret
= FtpCreateDirectoryW(hConnect
, lpwzDirectory
);
460 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
465 /***********************************************************************
466 * FtpCreateDirectoryW (WININET.@)
468 * Create new directory on the FTP server
475 BOOL WINAPI
FtpCreateDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
477 LPWININETFTPSESSIONW lpwfs
;
478 LPWININETAPPINFOW hIC
= NULL
;
481 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
482 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
484 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
488 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
489 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
491 WORKREQUEST workRequest
;
492 struct WORKREQ_FTPCREATEDIRECTORYW
*req
;
494 workRequest
.asyncall
= FTPCREATEDIRECTORYW
;
495 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
496 req
= &workRequest
.u
.FtpCreateDirectoryW
;
497 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
499 r
= INTERNET_AsyncCall(&workRequest
);
503 r
= FTP_FtpCreateDirectoryW(lpwfs
, lpszDirectory
);
507 WININET_Release( &lpwfs
->hdr
);
513 /***********************************************************************
514 * FTP_FtpCreateDirectoryW (Internal)
516 * Create new directory on the FTP server
523 BOOL WINAPI
FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
526 BOOL bSuccess
= FALSE
;
527 LPWININETAPPINFOW hIC
= NULL
;
529 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
531 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
533 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
537 /* Clear any error information */
538 INTERNET_SetLastError(0);
540 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
543 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
549 FTP_SetResponseError(nResCode
);
553 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
554 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
556 INTERNET_ASYNC_RESULT iar
;
558 iar
.dwResult
= (DWORD
)bSuccess
;
559 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
560 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
561 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
567 /***********************************************************************
568 * FtpFindFirstFileA (WININET.@)
570 * Search the specified directory
573 * HINTERNET on success
577 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
578 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
580 LPWSTR lpwzSearchFile
;
581 WIN32_FIND_DATAW wfd
;
582 LPWIN32_FIND_DATAW lpFindFileDataW
;
585 lpwzSearchFile
= lpszSearchFile
?WININET_strdup_AtoW(lpszSearchFile
):NULL
;
586 lpFindFileDataW
= lpFindFileData
?&wfd
:NULL
;
587 ret
= FtpFindFirstFileW(hConnect
, lpwzSearchFile
, lpFindFileDataW
, dwFlags
, dwContext
);
588 HeapFree(GetProcessHeap(), 0, lpwzSearchFile
);
591 WININET_find_data_WtoA(lpFindFileDataW
, lpFindFileData
);
597 /***********************************************************************
598 * FtpFindFirstFileW (WININET.@)
600 * Search the specified directory
603 * HINTERNET on success
607 HINTERNET WINAPI
FtpFindFirstFileW(HINTERNET hConnect
,
608 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
610 LPWININETFTPSESSIONW lpwfs
;
611 LPWININETAPPINFOW hIC
= NULL
;
614 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
615 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
617 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
621 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
622 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
624 WORKREQUEST workRequest
;
625 struct WORKREQ_FTPFINDFIRSTFILEW
*req
;
627 workRequest
.asyncall
= FTPFINDFIRSTFILEW
;
628 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
629 req
= &workRequest
.u
.FtpFindFirstFileW
;
630 req
->lpszSearchFile
= (lpszSearchFile
== NULL
) ? NULL
: WININET_strdupW(lpszSearchFile
);
631 req
->lpFindFileData
= lpFindFileData
;
632 req
->dwFlags
= dwFlags
;
633 req
->dwContext
= dwContext
;
635 INTERNET_AsyncCall(&workRequest
);
640 r
= FTP_FtpFindFirstFileW(lpwfs
, lpszSearchFile
, lpFindFileData
,
645 WININET_Release( &lpwfs
->hdr
);
651 /***********************************************************************
652 * FTP_FtpFindFirstFileW (Internal)
654 * Search the specified directory
657 * HINTERNET on success
661 HINTERNET WINAPI
FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs
,
662 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
665 LPWININETAPPINFOW hIC
= NULL
;
666 HINTERNET hFindNext
= NULL
;
670 assert(WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
672 /* Clear any error information */
673 INTERNET_SetLastError(0);
675 if (!FTP_InitListenSocket(lpwfs
))
678 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
681 if (!FTP_SendPortOrPasv(lpwfs
))
684 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
685 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, NULL
,
686 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
689 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
692 if (nResCode
== 125 || nResCode
== 150)
696 /* Get data socket to server */
697 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
699 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpszSearchFile
, lpFindFileData
, dwContext
);
700 closesocket(nDataSocket
);
701 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
702 if (nResCode
!= 226 && nResCode
!= 250)
703 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
707 FTP_SetResponseError(nResCode
);
711 if (lpwfs
->lstnSocket
!= -1)
712 closesocket(lpwfs
->lstnSocket
);
714 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
716 INTERNET_ASYNC_RESULT iar
;
720 iar
.dwResult
= (DWORD
)hFindNext
;
721 iar
.dwError
= ERROR_SUCCESS
;
722 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
723 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
726 iar
.dwResult
= (DWORD
)hFindNext
;
727 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
728 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
729 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
736 /***********************************************************************
737 * FtpGetCurrentDirectoryA (WININET.@)
739 * Retrieves the current directory
746 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
747 LPDWORD lpdwCurrentDirectory
)
753 if(lpdwCurrentDirectory
) len
= *lpdwCurrentDirectory
;
754 ret
= FtpGetCurrentDirectoryW(hFtpSession
, lpszCurrentDirectory
?dir
:NULL
, lpdwCurrentDirectory
?&len
:NULL
);
755 if(lpdwCurrentDirectory
) {
756 *lpdwCurrentDirectory
= len
;
757 if(lpszCurrentDirectory
)
758 WideCharToMultiByte(CP_ACP
, 0, dir
, len
, lpszCurrentDirectory
, *lpdwCurrentDirectory
, NULL
, NULL
);
764 /***********************************************************************
765 * FtpGetCurrentDirectoryW (WININET.@)
767 * Retrieves the current directory
774 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
775 LPDWORD lpdwCurrentDirectory
)
777 LPWININETFTPSESSIONW lpwfs
;
778 LPWININETAPPINFOW hIC
= NULL
;
781 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
783 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
784 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
786 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
790 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
791 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
793 WORKREQUEST workRequest
;
794 struct WORKREQ_FTPGETCURRENTDIRECTORYW
*req
;
796 workRequest
.asyncall
= FTPGETCURRENTDIRECTORYW
;
797 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
798 req
= &workRequest
.u
.FtpGetCurrentDirectoryW
;
799 req
->lpszDirectory
= lpszCurrentDirectory
;
800 req
->lpdwDirectory
= lpdwCurrentDirectory
;
802 r
= INTERNET_AsyncCall(&workRequest
);
806 r
= FTP_FtpGetCurrentDirectoryW(lpwfs
, lpszCurrentDirectory
,
807 lpdwCurrentDirectory
);
812 WININET_Release( &lpwfs
->hdr
);
818 /***********************************************************************
819 * FTP_FtpGetCurrentDirectoryA (Internal)
821 * Retrieves the current directory
828 BOOL WINAPI
FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPWSTR lpszCurrentDirectory
,
829 LPDWORD lpdwCurrentDirectory
)
832 LPWININETAPPINFOW hIC
= NULL
;
833 DWORD bSuccess
= FALSE
;
835 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
837 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
839 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
843 /* Clear any error information */
844 INTERNET_SetLastError(0);
846 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
848 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
849 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
850 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
853 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
856 if (nResCode
== 257) /* Extract directory name */
858 DWORD firstpos
, lastpos
, len
;
859 LPWSTR lpszResponseBuffer
= WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
861 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
863 if ('"' == lpszResponseBuffer
[lastpos
])
872 len
= lastpos
- firstpos
- 1;
873 lstrcpynW(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1], *lpdwCurrentDirectory
);
874 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer
);
875 *lpdwCurrentDirectory
= len
;
879 FTP_SetResponseError(nResCode
);
883 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
885 INTERNET_ASYNC_RESULT iar
;
887 iar
.dwResult
= (DWORD
)bSuccess
;
888 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
889 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
890 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
893 return (DWORD
) bSuccess
;
896 /***********************************************************************
897 * FtpOpenFileA (WININET.@)
899 * Open a remote file for writing or reading
902 * HINTERNET handle on success
906 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
907 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
913 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
914 ret
= FtpOpenFileW(hFtpSession
, lpwzFileName
, fdwAccess
, dwFlags
, dwContext
);
915 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
920 /***********************************************************************
921 * FtpOpenFileW (WININET.@)
923 * Open a remote file for writing or reading
926 * HINTERNET handle on success
930 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
931 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
934 LPWININETFTPSESSIONW lpwfs
;
935 LPWININETAPPINFOW hIC
= NULL
;
938 TRACE("(%p,%s,0x%08lx,0x%08lx,0x%08lx)\n", hFtpSession
,
939 debugstr_w(lpszFileName
), fdwAccess
, dwFlags
, dwContext
);
941 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
942 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
944 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
948 if (lpwfs
->download_in_progress
!= NULL
) {
949 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
952 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
953 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
955 WORKREQUEST workRequest
;
956 struct WORKREQ_FTPOPENFILEW
*req
;
958 workRequest
.asyncall
= FTPOPENFILEW
;
959 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
960 req
= &workRequest
.u
.FtpOpenFileW
;
961 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
962 req
->dwAccess
= fdwAccess
;
963 req
->dwFlags
= dwFlags
;
964 req
->dwContext
= dwContext
;
966 INTERNET_AsyncCall(&workRequest
);
971 r
= FTP_FtpOpenFileW(lpwfs
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
976 WININET_Release( &lpwfs
->hdr
);
982 /***********************************************************************
983 * FTP_FtpOpenFileW (Internal)
985 * Open a remote file for writing or reading
988 * HINTERNET handle on success
992 HINTERNET
FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs
,
993 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
997 BOOL bSuccess
= FALSE
;
998 LPWININETFILE lpwh
= NULL
;
999 LPWININETAPPINFOW hIC
= NULL
;
1000 HINTERNET handle
= NULL
;
1004 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1006 /* Clear any error information */
1007 INTERNET_SetLastError(0);
1009 if (GENERIC_READ
== fdwAccess
)
1011 /* Set up socket to retrieve data */
1012 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
1014 else if (GENERIC_WRITE
== fdwAccess
)
1016 /* Set up socket to send data */
1017 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
1020 /* Get data socket to server */
1021 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1023 lpwh
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE
));
1024 lpwh
->hdr
.htype
= WH_HFILE
;
1025 lpwh
->hdr
.dwFlags
= dwFlags
;
1026 lpwh
->hdr
.dwContext
= dwContext
;
1027 lpwh
->hdr
.lpwhparent
= WININET_AddRef( &lpwfs
->hdr
);
1028 lpwh
->hdr
.dwRefCount
= 1;
1029 lpwh
->hdr
.destroy
= FTP_CloseFileTransferHandle
;
1030 lpwh
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
1031 lpwh
->nDataSocket
= nDataSocket
;
1032 lpwh
->session_deleted
= FALSE
;
1034 handle
= WININET_AllocHandle( &lpwh
->hdr
);
1038 /* Indicate that a download is currently in progress */
1039 lpwfs
->download_in_progress
= lpwh
;
1042 if (lpwfs
->lstnSocket
!= -1)
1043 closesocket(lpwfs
->lstnSocket
);
1045 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1046 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1048 INTERNET_ASYNC_RESULT iar
;
1052 iar
.dwResult
= (DWORD
)handle
;
1053 iar
.dwError
= ERROR_SUCCESS
;
1054 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1055 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1058 iar
.dwResult
= (DWORD
)bSuccess
;
1059 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1060 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1061 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1066 WININET_Release( &lpwh
->hdr
);
1072 /***********************************************************************
1073 * FtpGetFileA (WININET.@)
1075 * Retrieve file from the FTP server
1082 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1083 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1086 LPWSTR lpwzRemoteFile
;
1090 lpwzRemoteFile
= lpszRemoteFile
?WININET_strdup_AtoW(lpszRemoteFile
):NULL
;
1091 lpwzNewFile
= lpszNewFile
?WININET_strdup_AtoW(lpszNewFile
):NULL
;
1092 ret
= FtpGetFileW(hInternet
, lpwzRemoteFile
, lpwzNewFile
, fFailIfExists
,
1093 dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1094 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile
);
1095 HeapFree(GetProcessHeap(), 0, lpwzNewFile
);
1100 /***********************************************************************
1101 * FtpGetFileW (WININET.@)
1103 * Retrieve file from the FTP server
1110 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1111 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1114 LPWININETFTPSESSIONW lpwfs
;
1115 LPWININETAPPINFOW hIC
= NULL
;
1118 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hInternet
);
1119 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1121 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1125 if (lpwfs
->download_in_progress
!= NULL
) {
1126 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1130 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1131 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1133 WORKREQUEST workRequest
;
1134 struct WORKREQ_FTPGETFILEW
*req
;
1136 workRequest
.asyncall
= FTPGETFILEW
;
1137 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1138 req
= &workRequest
.u
.FtpGetFileW
;
1139 req
->lpszRemoteFile
= WININET_strdupW(lpszRemoteFile
);
1140 req
->lpszNewFile
= WININET_strdupW(lpszNewFile
);
1141 req
->dwLocalFlagsAttribute
= dwLocalFlagsAttribute
;
1142 req
->fFailIfExists
= fFailIfExists
;
1143 req
->dwFlags
= dwInternetFlags
;
1144 req
->dwContext
= dwContext
;
1146 r
= INTERNET_AsyncCall(&workRequest
);
1150 r
= FTP_FtpGetFileW(lpwfs
, lpszRemoteFile
, lpszNewFile
,
1151 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1156 WININET_Release( &lpwfs
->hdr
);
1162 /***********************************************************************
1163 * FTP_FtpGetFileW (Internal)
1165 * Retrieve file from the FTP server
1172 BOOL WINAPI
FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1173 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1177 BOOL bSuccess
= FALSE
;
1179 LPWININETAPPINFOW hIC
= NULL
;
1181 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile
), debugstr_w(lpszNewFile
));
1183 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1185 /* Clear any error information */
1186 INTERNET_SetLastError(0);
1188 /* Ensure we can write to lpszNewfile by opening it */
1189 hFile
= CreateFileW(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1190 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1191 if (INVALID_HANDLE_VALUE
== hFile
)
1194 /* Set up socket to retrieve data */
1195 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
1201 /* Get data socket to server */
1202 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1207 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
1208 nResCode
= FTP_ReceiveResponse(lpwfs
, dwContext
);
1211 if (nResCode
== 226)
1214 FTP_SetResponseError(nResCode
);
1216 closesocket(nDataSocket
);
1221 if (lpwfs
->lstnSocket
!= -1)
1222 closesocket(lpwfs
->lstnSocket
);
1227 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1228 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1230 INTERNET_ASYNC_RESULT iar
;
1232 iar
.dwResult
= (DWORD
)bSuccess
;
1233 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1234 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1235 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1241 /***********************************************************************
1242 * FtpGetFileSize (WININET.@)
1244 DWORD WINAPI
FtpGetFileSize( HINTERNET hFile
, LPDWORD lpdwFileSizeHigh
)
1246 FIXME("(%p, %p)\n", hFile
, lpdwFileSizeHigh
);
1248 if (lpdwFileSizeHigh
)
1249 *lpdwFileSizeHigh
= 0;
1254 /***********************************************************************
1255 * FtpDeleteFileA (WININET.@)
1257 * Delete a file on the ftp server
1264 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1266 LPWSTR lpwzFileName
;
1269 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
1270 ret
= FtpDeleteFileW(hFtpSession
, lpwzFileName
);
1271 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
1275 /***********************************************************************
1276 * FtpDeleteFileW (WININET.@)
1278 * Delete a file on the ftp server
1285 BOOL WINAPI
FtpDeleteFileW(HINTERNET hFtpSession
, LPCWSTR lpszFileName
)
1287 LPWININETFTPSESSIONW lpwfs
;
1288 LPWININETAPPINFOW hIC
= NULL
;
1291 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1292 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1294 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1298 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1299 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1301 WORKREQUEST workRequest
;
1302 struct WORKREQ_FTPDELETEFILEW
*req
;
1304 workRequest
.asyncall
= FTPDELETEFILEW
;
1305 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1306 req
= &workRequest
.u
.FtpDeleteFileW
;
1307 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
1309 r
= INTERNET_AsyncCall(&workRequest
);
1313 r
= FTP_FtpDeleteFileW(hFtpSession
, lpszFileName
);
1318 WININET_Release( &lpwfs
->hdr
);
1323 /***********************************************************************
1324 * FTP_FtpDeleteFileW (Internal)
1326 * Delete a file on the ftp server
1333 BOOL
FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszFileName
)
1336 BOOL bSuccess
= FALSE
;
1337 LPWININETAPPINFOW hIC
= NULL
;
1339 TRACE("%p\n", lpwfs
);
1341 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1343 /* Clear any error information */
1344 INTERNET_SetLastError(0);
1346 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1349 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1352 if (nResCode
== 250)
1355 FTP_SetResponseError(nResCode
);
1358 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1359 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1361 INTERNET_ASYNC_RESULT iar
;
1363 iar
.dwResult
= (DWORD
)bSuccess
;
1364 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1365 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1366 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1373 /***********************************************************************
1374 * FtpRemoveDirectoryA (WININET.@)
1376 * Remove a directory on the ftp server
1383 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1385 LPWSTR lpwzDirectory
;
1388 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
1389 ret
= FtpRemoveDirectoryW(hFtpSession
, lpwzDirectory
);
1390 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
1394 /***********************************************************************
1395 * FtpRemoveDirectoryW (WININET.@)
1397 * Remove a directory on the ftp server
1404 BOOL WINAPI
FtpRemoveDirectoryW(HINTERNET hFtpSession
, LPCWSTR lpszDirectory
)
1406 LPWININETFTPSESSIONW lpwfs
;
1407 LPWININETAPPINFOW hIC
= NULL
;
1410 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1411 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1413 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1417 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1418 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1420 WORKREQUEST workRequest
;
1421 struct WORKREQ_FTPREMOVEDIRECTORYW
*req
;
1423 workRequest
.asyncall
= FTPREMOVEDIRECTORYW
;
1424 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1425 req
= &workRequest
.u
.FtpRemoveDirectoryW
;
1426 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
1428 r
= INTERNET_AsyncCall(&workRequest
);
1432 r
= FTP_FtpRemoveDirectoryW(lpwfs
, lpszDirectory
);
1437 WININET_Release( &lpwfs
->hdr
);
1442 /***********************************************************************
1443 * FTP_FtpRemoveDirectoryW (Internal)
1445 * Remove a directory on the ftp server
1452 BOOL
FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
1455 BOOL bSuccess
= FALSE
;
1456 LPWININETAPPINFOW hIC
= NULL
;
1460 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1462 /* Clear any error information */
1463 INTERNET_SetLastError(0);
1465 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1468 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1471 if (nResCode
== 250)
1474 FTP_SetResponseError(nResCode
);
1478 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1479 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1481 INTERNET_ASYNC_RESULT iar
;
1483 iar
.dwResult
= (DWORD
)bSuccess
;
1484 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1485 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1486 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1493 /***********************************************************************
1494 * FtpRenameFileA (WININET.@)
1496 * Rename a file on the ftp server
1503 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1509 lpwzSrc
= lpszSrc
?WININET_strdup_AtoW(lpszSrc
):NULL
;
1510 lpwzDest
= lpszDest
?WININET_strdup_AtoW(lpszDest
):NULL
;
1511 ret
= FtpRenameFileW(hFtpSession
, lpwzSrc
, lpwzDest
);
1512 HeapFree(GetProcessHeap(), 0, lpwzSrc
);
1513 HeapFree(GetProcessHeap(), 0, lpwzDest
);
1517 /***********************************************************************
1518 * FtpRenameFileW (WININET.@)
1520 * Rename a file on the ftp server
1527 BOOL WINAPI
FtpRenameFileW(HINTERNET hFtpSession
, LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1529 LPWININETFTPSESSIONW lpwfs
;
1530 LPWININETAPPINFOW hIC
= NULL
;
1533 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1534 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1536 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1540 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1541 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1543 WORKREQUEST workRequest
;
1544 struct WORKREQ_FTPRENAMEFILEW
*req
;
1546 workRequest
.asyncall
= FTPRENAMEFILEW
;
1547 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1548 req
= &workRequest
.u
.FtpRenameFileW
;
1549 req
->lpszSrcFile
= WININET_strdupW(lpszSrc
);
1550 req
->lpszDestFile
= WININET_strdupW(lpszDest
);
1552 r
= INTERNET_AsyncCall(&workRequest
);
1556 r
= FTP_FtpRenameFileW(hFtpSession
, lpszSrc
, lpszDest
);
1561 WININET_Release( &lpwfs
->hdr
);
1566 /***********************************************************************
1567 * FTP_FtpRenameFileA (Internal)
1569 * Rename a file on the ftp server
1576 BOOL
FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs
,
1577 LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1580 BOOL bSuccess
= FALSE
;
1581 LPWININETAPPINFOW hIC
= NULL
;
1585 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1587 /* Clear any error information */
1588 INTERNET_SetLastError(0);
1590 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1593 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1594 if (nResCode
== 350)
1596 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1599 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1602 if (nResCode
== 250)
1605 FTP_SetResponseError(nResCode
);
1608 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1609 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1611 INTERNET_ASYNC_RESULT iar
;
1613 iar
.dwResult
= (DWORD
)bSuccess
;
1614 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1615 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1616 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1622 /***********************************************************************
1623 * FtpCommandA (WININET.@)
1625 BOOL WINAPI
FtpCommandA( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1626 LPCSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1628 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1629 debugstr_a(lpszCommand
), dwContext
, phFtpCommand
);
1634 /***********************************************************************
1635 * FtpCommandW (WININET.@)
1637 BOOL WINAPI
FtpCommandW( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1638 LPCWSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1640 FIXME("%p %d 0x%08lx %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1641 debugstr_w(lpszCommand
), dwContext
, phFtpCommand
);
1646 /***********************************************************************
1647 * FTP_Connect (internal)
1649 * Connect to a ftp server
1652 * HINTERNET a session handle on success
1657 HINTERNET
FTP_Connect(LPWININETAPPINFOW hIC
, LPCWSTR lpszServerName
,
1658 INTERNET_PORT nServerPort
, LPCWSTR lpszUserName
,
1659 LPCWSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
,
1660 DWORD dwInternalFlags
)
1662 static const WCHAR szDefaultUsername
[] = {'a','n','o','n','y','m','o','u','s','\0'};
1663 static const WCHAR szDefaultPassword
[] = {'u','s','e','r','@','s','e','r','v','e','r','\0'};
1664 struct sockaddr_in socketAddr
;
1667 BOOL bSuccess
= FALSE
;
1668 LPWININETFTPSESSIONW lpwfs
= NULL
;
1669 HINTERNET handle
= NULL
;
1671 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1672 hIC
, debugstr_w(lpszServerName
),
1673 nServerPort
, debugstr_w(lpszUserName
), debugstr_w(lpszPassword
));
1675 assert( hIC
->hdr
.htype
== WH_HINIT
);
1677 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1679 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1683 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW
));
1686 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1690 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1691 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1693 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1694 lpwfs
->hdr
.lpwhparent
= WININET_AddRef( &hIC
->hdr
);
1695 lpwfs
->hdr
.dwFlags
= dwFlags
;
1696 lpwfs
->hdr
.dwContext
= dwContext
;
1697 lpwfs
->hdr
.dwInternalFlags
= dwInternalFlags
;
1698 lpwfs
->hdr
.dwRefCount
= 1;
1699 lpwfs
->hdr
.destroy
= FTP_CloseSessionHandle
;
1700 lpwfs
->hdr
.lpfnStatusCB
= hIC
->hdr
.lpfnStatusCB
;
1701 lpwfs
->download_in_progress
= NULL
;
1703 handle
= WININET_AllocHandle( &lpwfs
->hdr
);
1706 ERR("Failed to alloc handle\n");
1707 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1711 if(hIC
->lpszProxy
&& hIC
->dwAccessType
== INTERNET_OPEN_TYPE_PROXY
) {
1712 if(strchrW(hIC
->lpszProxy
, ' '))
1713 FIXME("Several proxies not implemented.\n");
1714 if(hIC
->lpszProxyBypass
)
1715 FIXME("Proxy bypass is ignored.\n");
1717 if ( !lpszUserName
) {
1718 lpwfs
->lpszUserName
= WININET_strdupW(szDefaultUsername
);
1719 lpwfs
->lpszPassword
= WININET_strdupW(szDefaultPassword
);
1722 lpwfs
->lpszUserName
= WININET_strdupW(lpszUserName
);
1723 lpwfs
->lpszPassword
= WININET_strdupW(lpszPassword
);
1726 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1727 if (!(lpwfs
->hdr
.dwInternalFlags
& INET_OPENURL
))
1729 INTERNET_ASYNC_RESULT iar
;
1731 iar
.dwResult
= (DWORD
)handle
;
1732 iar
.dwError
= ERROR_SUCCESS
;
1734 SendAsyncCallback(&hIC
->hdr
, dwContext
,
1735 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
1736 sizeof(INTERNET_ASYNC_RESULT
));
1739 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1740 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1742 if (!GetAddress(lpszServerName
, nServerPort
, &socketAddr
))
1744 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1748 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1749 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1751 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1754 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1758 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1759 &socketAddr
, sizeof(struct sockaddr_in
));
1761 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1763 ERR("Unable to connect (%s)\n", strerror(errno
));
1764 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1768 TRACE("Connected to server\n");
1769 lpwfs
->sndSocket
= nsocket
;
1770 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1771 &socketAddr
, sizeof(struct sockaddr_in
));
1773 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1774 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1776 if (FTP_ConnectToHost(lpwfs
))
1778 TRACE("Successfully logged into server\n");
1784 if (!bSuccess
&& nsocket
== -1)
1785 closesocket(nsocket
);
1787 if (!bSuccess
&& lpwfs
)
1789 HeapFree(GetProcessHeap(), 0, lpwfs
);
1790 WININET_FreeHandle( handle
);
1794 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1796 INTERNET_ASYNC_RESULT iar
;
1798 iar
.dwResult
= (DWORD
)lpwfs
;
1799 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1800 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1801 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1808 /***********************************************************************
1809 * FTP_ConnectToHost (internal)
1811 * Connect to a ftp server
1818 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
)
1821 BOOL bSuccess
= FALSE
;
1824 FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1826 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1829 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1832 /* Login successful... */
1833 if (nResCode
== 230)
1835 /* User name okay, need password... */
1836 else if (nResCode
== 331)
1837 bSuccess
= FTP_SendPassword(lpwfs
);
1838 /* Need account for login... */
1839 else if (nResCode
== 332)
1840 bSuccess
= FTP_SendAccount(lpwfs
);
1842 FTP_SetResponseError(nResCode
);
1845 TRACE("Returning %d\n", bSuccess
);
1851 /***********************************************************************
1852 * FTP_SendCommandA (internal)
1854 * Send command to server
1861 static BOOL
FTP_SendCommandA(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
1862 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
)
1866 DWORD nBytesSent
= 0;
1870 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
1874 HINTERNET hHandle
= WININET_FindHandle( hdr
);
1877 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1878 WININET_Release( hdr
);
1882 dwParamLen
= lpszParam
?strlen(lpszParam
)+1:0;
1883 len
= dwParamLen
+ strlen(szFtpCommands
[ftpCmd
]) + strlen(szCRLF
);
1884 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1886 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1889 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], dwParamLen
? " " : "",
1890 dwParamLen
? lpszParam
: "", szCRLF
);
1892 TRACE("Sending (%s) len(%ld)\n", buf
, len
);
1893 while((nBytesSent
< len
) && (nRC
!= -1))
1895 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1899 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1903 HINTERNET hHandle
= WININET_FindHandle( hdr
);
1906 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1907 &nBytesSent
, sizeof(DWORD
));
1908 WININET_Release( hdr
);
1912 TRACE("Sent %ld bytes\n", nBytesSent
);
1916 /***********************************************************************
1917 * FTP_SendCommand (internal)
1919 * Send command to server
1926 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
1927 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
)
1930 LPSTR lpszParamA
= lpszParam
?WININET_strdup_WtoA(lpszParam
):NULL
;
1931 ret
= FTP_SendCommandA(nSocket
, ftpCmd
, lpszParamA
, lpfnStatusCB
, hdr
, dwContext
);
1932 HeapFree(GetProcessHeap(), 0, lpszParamA
);
1936 /***********************************************************************
1937 * FTP_ReceiveResponse (internal)
1939 * Receive response from server
1942 * Reply code on success
1946 INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD dwContext
)
1948 LPSTR lpszResponse
= INTERNET_GetResponseBuffer();
1951 char firstprefix
[5];
1952 BOOL multiline
= FALSE
;
1953 LPWININETAPPINFOW hIC
= NULL
;
1955 TRACE("socket(%d)\n", lpwfs
->sndSocket
);
1957 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1958 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
1962 if (!INTERNET_GetNextLine(lpwfs
->sndSocket
, &nRecv
))
1969 if(lpszResponse
[3] != '-')
1972 { /* Start of multiline repsonse. Loop until we get "nnn " */
1974 memcpy(firstprefix
, lpszResponse
, 3);
1975 firstprefix
[3] = ' ';
1976 firstprefix
[4] = '\0';
1981 if(!memcmp(firstprefix
, lpszResponse
, 4))
1989 rc
= atoi(lpszResponse
);
1991 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
1992 &nRecv
, sizeof(DWORD
));
1996 TRACE("return %d\n", rc
);
2001 /***********************************************************************
2002 * FTP_SendPassword (internal)
2004 * Send password to ftp server
2011 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
)
2014 BOOL bSuccess
= FALSE
;
2017 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
2020 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2023 TRACE("Received reply code %d\n", nResCode
);
2024 /* Login successful... */
2025 if (nResCode
== 230)
2027 /* Command not implemented, superfluous at the server site... */
2028 /* Need account for login... */
2029 else if (nResCode
== 332)
2030 bSuccess
= FTP_SendAccount(lpwfs
);
2032 FTP_SetResponseError(nResCode
);
2036 TRACE("Returning %d\n", bSuccess
);
2041 /***********************************************************************
2042 * FTP_SendAccount (internal)
2051 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
)
2054 BOOL bSuccess
= FALSE
;
2057 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, szNoAccount
, 0, 0, 0))
2060 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2064 FTP_SetResponseError(nResCode
);
2071 /***********************************************************************
2072 * FTP_SendStore (internal)
2074 * Send request to upload file to ftp server
2081 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2084 BOOL bSuccess
= FALSE
;
2087 if (!FTP_InitListenSocket(lpwfs
))
2090 if (!FTP_SendType(lpwfs
, dwType
))
2093 if (!FTP_SendPortOrPasv(lpwfs
))
2096 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
2098 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2101 if (nResCode
== 150 || nResCode
== 125)
2104 FTP_SetResponseError(nResCode
);
2108 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
2110 closesocket(lpwfs
->lstnSocket
);
2111 lpwfs
->lstnSocket
= -1;
2118 /***********************************************************************
2119 * FTP_InitListenSocket (internal)
2121 * Create a socket to listen for server response
2128 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
)
2130 BOOL bSuccess
= FALSE
;
2131 size_t namelen
= sizeof(struct sockaddr_in
);
2135 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
2136 if (lpwfs
->lstnSocket
== -1)
2138 TRACE("Unable to create listening socket\n");
2142 /* We obtain our ip addr from the name of the command channel socket */
2143 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
2145 /* and get the system to assign us a port */
2146 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
2148 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
2150 TRACE("Unable to bind socket\n");
2154 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
2156 TRACE("listen failed\n");
2160 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
2164 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
2166 closesocket(lpwfs
->lstnSocket
);
2167 lpwfs
->lstnSocket
= -1;
2174 /***********************************************************************
2175 * FTP_SendType (internal)
2177 * Tell server type of data being transferred
2183 * W98SE doesn't cache the type that's currently set
2184 * (i.e. it sends it always),
2185 * so we probably don't want to do that either.
2187 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
)
2190 WCHAR type
[] = { 'I','\0' };
2191 BOOL bSuccess
= FALSE
;
2194 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
2197 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
2200 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
)/100;
2206 FTP_SetResponseError(nResCode
);
2213 /***********************************************************************
2214 * FTP_GetFileSize (internal)
2216 * Retrieves from the server the size of the given file
2223 static BOOL
FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD
*dwSize
)
2226 BOOL bSuccess
= FALSE
;
2230 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
2233 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2236 if (nResCode
== 213) {
2237 /* Now parses the output to get the actual file size */
2239 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2241 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
2242 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
2243 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2247 FTP_SetResponseError(nResCode
);
2256 /***********************************************************************
2257 * FTP_SendPort (internal)
2259 * Tell server which port to use
2266 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
)
2268 static const WCHAR szIPFormat
[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2270 WCHAR szIPAddress
[64];
2271 BOOL bSuccess
= FALSE
;
2274 sprintfW(szIPAddress
, szIPFormat
,
2275 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2276 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2277 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2278 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2279 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2280 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2282 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2285 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2288 if (nResCode
== 200)
2291 FTP_SetResponseError(nResCode
);
2299 /***********************************************************************
2300 * FTP_DoPassive (internal)
2302 * Tell server that we want to do passive transfers
2303 * and connect data socket
2310 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
)
2313 BOOL bSuccess
= FALSE
;
2316 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2319 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2322 if (nResCode
== 227)
2324 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2328 char *pAddr
, *pPort
;
2330 struct sockaddr_in dataSocketAddress
;
2332 p
= lpszResponseBuffer
+4; /* skip status code */
2334 /* do a very strict check; we can improve that later. */
2336 if (strncmp(p
, "Entering Passive Mode", 21))
2338 ERR("unknown response '%.*s', aborting\n", 21, p
);
2341 p
+= 21; /* skip string */
2342 if ((*p
++ != ' ') || (*p
++ != '('))
2344 ERR("unknown response format, aborting\n");
2348 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2351 ERR("unknown response address format '%s', aborting\n", p
);
2354 for (i
=0; i
< 6; i
++)
2357 dataSocketAddress
= lpwfs
->socketAddress
;
2358 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2359 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2367 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2371 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2373 ERR("can't connect passive FTP data port.\n");
2376 lpwfs
->pasvSocket
= nsocket
;
2380 FTP_SetResponseError(nResCode
);
2388 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
)
2390 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2392 if (!FTP_DoPassive(lpwfs
))
2397 if (!FTP_SendPort(lpwfs
))
2404 /***********************************************************************
2405 * FTP_GetDataSocket (internal)
2407 * Either accepts an incoming data socket connection from the server
2408 * or just returns the already opened socket after a PASV command
2409 * in case of passive FTP.
2417 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
)
2419 struct sockaddr_in saddr
;
2420 size_t addrlen
= sizeof(struct sockaddr
);
2423 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2425 *nDataSocket
= lpwfs
->pasvSocket
;
2429 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2430 closesocket(lpwfs
->lstnSocket
);
2431 lpwfs
->lstnSocket
= -1;
2433 return *nDataSocket
!= -1;
2437 /***********************************************************************
2438 * FTP_SendData (internal)
2440 * Send data to the server
2447 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
)
2449 BY_HANDLE_FILE_INFORMATION fi
;
2450 DWORD nBytesRead
= 0;
2451 DWORD nBytesSent
= 0;
2452 DWORD nTotalSent
= 0;
2453 DWORD nBytesToSend
, nLen
;
2455 time_t s_long_time
, e_long_time
;
2460 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2461 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2463 /* Get the size of the file. */
2464 GetFileInformationByHandle(hFile
, &fi
);
2469 nBytesToSend
= nBytesRead
- nBytesSent
;
2471 if (nBytesToSend
<= 0)
2473 /* Read data from file. */
2475 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2476 ERR("Failed reading from file\n");
2479 nBytesToSend
= nBytesRead
;
2484 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2485 DATA_PACKET_SIZE
: nBytesToSend
;
2486 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2494 /* Do some computation to display the status. */
2496 nSeconds
= e_long_time
- s_long_time
;
2497 if( nSeconds
/ 60 > 0 )
2499 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remaining time %ld sec\n",
2500 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2501 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2505 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remaining time %ld sec\n",
2506 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2507 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2509 } while (nRC
!= -1);
2511 TRACE("file transfer complete!\n");
2513 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2519 /***********************************************************************
2520 * FTP_SendRetrieve (internal)
2522 * Send request to retrieve a file
2525 * Number of bytes to be received on success
2529 static DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2535 if (!FTP_InitListenSocket(lpwfs
))
2538 if (!FTP_SendType(lpwfs
, dwType
))
2541 if (!FTP_SendPortOrPasv(lpwfs
))
2544 if (!FTP_GetFileSize(lpwfs
, lpszRemoteFile
, &nResult
))
2547 TRACE("Waiting to receive %ld bytes\n", nResult
);
2549 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2552 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2553 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2554 /* That means that we got an error getting the file. */
2559 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2561 closesocket(lpwfs
->lstnSocket
);
2562 lpwfs
->lstnSocket
= -1;
2569 /***********************************************************************
2570 * FTP_RetrieveData (internal)
2572 * Retrieve data from server
2579 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2581 DWORD nBytesWritten
;
2582 DWORD nBytesReceived
= 0;
2588 if (INVALID_HANDLE_VALUE
== hFile
)
2591 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2592 if (NULL
== lpszBuffer
)
2594 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2598 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2600 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2603 /* other side closed socket. */
2606 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2607 nBytesReceived
+= nRC
;
2610 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived
, nBytes
,
2611 nBytesReceived
* 100 / nBytes
);
2614 TRACE("Data transfer complete\n");
2615 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2622 /***********************************************************************
2623 * FTP_CloseSessionHandle (internal)
2625 * Deallocate session handle
2632 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
)
2634 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) hdr
;
2638 if (lpwfs
->download_in_progress
!= NULL
)
2639 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2641 if (lpwfs
->sndSocket
!= -1)
2642 closesocket(lpwfs
->sndSocket
);
2644 if (lpwfs
->lstnSocket
!= -1)
2645 closesocket(lpwfs
->lstnSocket
);
2647 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2648 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2649 HeapFree(GetProcessHeap(), 0, lpwfs
);
2653 /***********************************************************************
2654 * FTP_CloseFindNextHandle (internal)
2656 * Deallocate session handle
2663 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
)
2665 LPWININETFINDNEXTW lpwfn
= (LPWININETFINDNEXTW
) hdr
;
2670 for (i
= 0; i
< lpwfn
->size
; i
++)
2672 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2675 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2676 HeapFree(GetProcessHeap(), 0, lpwfn
);
2679 /***********************************************************************
2680 * FTP_CloseFileTransferHandle (internal)
2682 * Closes the file transfer handle. This also 'cleans' the data queue of
2683 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2686 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
)
2688 LPWININETFILE lpwh
= (LPWININETFILE
) hdr
;
2689 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) lpwh
->hdr
.lpwhparent
;
2694 if (!lpwh
->session_deleted
)
2695 lpwfs
->download_in_progress
= NULL
;
2697 /* This just serves to flush the control socket of any spurrious lines written
2698 to it (like '226 Transfer complete.').
2700 Wonder what to do if the server sends us an error code though...
2702 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2704 if (lpwh
->nDataSocket
!= -1)
2705 closesocket(lpwh
->nDataSocket
);
2707 HeapFree(GetProcessHeap(), 0, lpwh
);
2710 /***********************************************************************
2711 * FTP_ReceiveFileList (internal)
2713 * Read file list from server
2716 * Handle to file list on success
2720 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
2721 LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwContext
)
2724 LPFILEPROPERTIESW lpafp
= NULL
;
2725 LPWININETFINDNEXTW lpwfn
= NULL
;
2726 HINTERNET handle
= 0;
2728 TRACE("(%p,%d,%s,%p,%ld)\n", lpwfs
, nSocket
, debugstr_w(lpszSearchFile
), lpFindFileData
, dwContext
);
2730 if (FTP_ParseDirectory(lpwfs
, nSocket
, lpszSearchFile
, &lpafp
, &dwSize
))
2733 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2735 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFINDNEXTW
));
2738 lpwfn
->hdr
.htype
= WH_HFINDNEXT
;
2739 lpwfn
->hdr
.lpwhparent
= WININET_AddRef( &lpwfs
->hdr
);
2740 lpwfn
->hdr
.dwContext
= dwContext
;
2741 lpwfn
->hdr
.dwRefCount
= 1;
2742 lpwfn
->hdr
.destroy
= FTP_CloseFindNextHandle
;
2743 lpwfn
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
2744 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2745 lpwfn
->size
= dwSize
;
2746 lpwfn
->lpafp
= lpafp
;
2748 handle
= WININET_AllocHandle( &lpwfn
->hdr
);
2753 WININET_Release( &lpwfn
->hdr
);
2755 TRACE("Matched %ld files\n", dwSize
);
2760 /***********************************************************************
2761 * FTP_ConvertFileProp (internal)
2763 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2770 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp
, LPWIN32_FIND_DATAW lpFindFileData
)
2772 BOOL bSuccess
= FALSE
;
2774 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAW
));
2778 /* Convert 'Unix' time to Windows time */
2779 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
2780 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
2781 lpFindFileData
->ftLastWriteTime
= lpFindFileData
->ftLastAccessTime
;
2782 lpFindFileData
->ftCreationTime
= lpFindFileData
->ftLastAccessTime
;
2784 /* Not all fields are filled in */
2785 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2786 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
2788 if (lpafp
->bIsDirectory
)
2789 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2791 if (lpafp
->lpszName
)
2792 lstrcpynW(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2800 /***********************************************************************
2801 * FTP_ParseNextFile (internal)
2803 * Parse the next line in file listing
2809 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW lpfp
)
2811 static const char szSpace
[] = " \t";
2819 lpfp
->lpszName
= NULL
;
2821 if(!(pszLine
= INTERNET_GetNextLine(nSocket
, &nBufLen
)))
2824 pszToken
= strtok(pszLine
, szSpace
);
2826 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2829 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2831 if(!isdigit(pszToken
[0]) && 10 == strlen(pszToken
)) {
2832 if(!FTP_ParsePermission(pszToken
, lpfp
))
2833 lpfp
->bIsDirectory
= FALSE
;
2834 for(i
=0; i
<=3; i
++) {
2835 if(!(pszToken
= strtok(NULL
, szSpace
)))
2838 if(!pszToken
) continue;
2839 if(lpfp
->bIsDirectory
) {
2840 TRACE("Is directory\n");
2844 TRACE("Size: %s\n", pszToken
);
2845 lpfp
->nSize
= atol(pszToken
);
2848 lpfp
->tmLastModified
.tm_sec
= 0;
2849 lpfp
->tmLastModified
.tm_min
= 0;
2850 lpfp
->tmLastModified
.tm_hour
= 0;
2851 lpfp
->tmLastModified
.tm_mday
= 0;
2852 lpfp
->tmLastModified
.tm_mon
= 0;
2853 lpfp
->tmLastModified
.tm_year
= 0;
2855 /* Determine month */
2856 pszToken
= strtok(NULL
, szSpace
);
2857 if(!pszToken
) continue;
2858 if(strlen(pszToken
) >= 3) {
2860 if((pszTmp
= StrStrIA(szMonths
, pszToken
)))
2861 lpfp
->tmLastModified
.tm_mon
= ((pszTmp
- szMonths
) / 3)+1;
2864 pszToken
= strtok(NULL
, szSpace
);
2865 if(!pszToken
) continue;
2866 lpfp
->tmLastModified
.tm_mday
= atoi(pszToken
);
2867 /* Determine time or year */
2868 pszToken
= strtok(NULL
, szSpace
);
2869 if(!pszToken
) continue;
2870 if((pszTmp
= strchr(pszToken
, ':'))) {
2875 lpfp
->tmLastModified
.tm_min
= atoi(pszTmp
);
2876 lpfp
->tmLastModified
.tm_hour
= atoi(pszToken
);
2878 apTM
= localtime(&aTime
);
2879 lpfp
->tmLastModified
.tm_year
= apTM
->tm_year
;
2882 lpfp
->tmLastModified
.tm_year
= atoi(pszToken
) - 1900;
2883 lpfp
->tmLastModified
.tm_hour
= 12;
2885 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2886 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
2887 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
2888 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
2890 pszToken
= strtok(NULL
, szSpace
);
2891 if(!pszToken
) continue;
2892 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
2893 TRACE("File: %s\n", debugstr_w(lpfp
->lpszName
));
2895 /* NT way of parsing ... :
2897 07-13-03 08:55PM <DIR> sakpatch
2898 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2900 else if(isdigit(pszToken
[0]) && 8 == strlen(pszToken
)) {
2901 lpfp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
2903 sscanf(pszToken
, "%d-%d-%d",
2904 &lpfp
->tmLastModified
.tm_mon
,
2905 &lpfp
->tmLastModified
.tm_mday
,
2906 &lpfp
->tmLastModified
.tm_year
);
2908 /* Hacky and bad Y2K protection :-) */
2909 if (lpfp
->tmLastModified
.tm_year
< 70)
2910 lpfp
->tmLastModified
.tm_year
+= 100;
2912 pszToken
= strtok(NULL
, szSpace
);
2913 if(!pszToken
) continue;
2914 sscanf(pszToken
, "%d:%d",
2915 &lpfp
->tmLastModified
.tm_hour
,
2916 &lpfp
->tmLastModified
.tm_min
);
2917 if((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
2918 lpfp
->tmLastModified
.tm_hour
+= 12;
2920 lpfp
->tmLastModified
.tm_sec
= 0;
2922 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2923 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
2924 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
2925 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
2927 pszToken
= strtok(NULL
, szSpace
);
2928 if(!pszToken
) continue;
2929 if(!strcasecmp(pszToken
, "<DIR>")) {
2930 lpfp
->bIsDirectory
= TRUE
;
2932 TRACE("Is directory\n");
2935 lpfp
->bIsDirectory
= FALSE
;
2936 lpfp
->nSize
= atol(pszToken
);
2937 TRACE("Size: %ld\n", lpfp
->nSize
);
2940 pszToken
= strtok(NULL
, szSpace
);
2941 if(!pszToken
) continue;
2942 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
2943 TRACE("Name: %s\n", debugstr_w(lpfp
->lpszName
));
2945 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
2946 else if(pszToken
[0] == '+') {
2947 FIXME("EPLF Format not implemented\n");
2950 if(lpfp
->lpszName
) {
2951 if((lpszSearchFile
== NULL
) ||
2952 (PathMatchSpecW(lpfp
->lpszName
, lpszSearchFile
))) {
2954 TRACE("Matched: %s\n", debugstr_w(lpfp
->lpszName
));
2957 HeapFree(GetProcessHeap(), 0, lpfp
->lpszName
);
2958 lpfp
->lpszName
= NULL
;
2965 /***********************************************************************
2966 * FTP_ParseDirectory (internal)
2968 * Parse string of directory information
2974 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
2975 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
)
2977 BOOL bSuccess
= TRUE
;
2978 INT sizeFilePropArray
= 500;/*20; */
2979 INT indexFilePropArray
= -1;
2983 /* Allocate intial file properties array */
2984 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESW
)*(sizeFilePropArray
));
2989 if (indexFilePropArray
+1 >= sizeFilePropArray
)
2991 LPFILEPROPERTIESW tmpafp
;
2993 sizeFilePropArray
*= 2;
2994 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
2995 sizeof(FILEPROPERTIESW
)*sizeFilePropArray
);
3004 indexFilePropArray
++;
3005 } while (FTP_ParseNextFile(nSocket
, lpszSearchFile
, &(*lpafp
)[indexFilePropArray
]));
3007 if (bSuccess
&& indexFilePropArray
)
3009 if (indexFilePropArray
< sizeFilePropArray
- 1)
3011 LPFILEPROPERTIESW tmpafp
;
3013 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
3014 sizeof(FILEPROPERTIESW
)*indexFilePropArray
);
3018 *dwfp
= indexFilePropArray
;
3022 HeapFree(GetProcessHeap(), 0, *lpafp
);
3023 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
3031 /***********************************************************************
3032 * FTP_ParsePermission (internal)
3034 * Parse permission string of directory information
3041 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
)
3043 BOOL bSuccess
= TRUE
;
3044 unsigned short nPermission
= 0;
3049 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
3055 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
3061 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
3064 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
3067 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
3070 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
3073 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
3076 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
3079 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
3082 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
3085 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
3089 }while (nPos
<= nLast
);
3091 lpfp
->permissions
= nPermission
;
3096 /***********************************************************************
3097 * FTP_SetResponseError (internal)
3099 * Set the appropriate error code for a given response from the server
3104 static DWORD
FTP_SetResponseError(DWORD dwResponse
)
3110 case 421: /* Service not available - Server may be shutting down. */
3111 dwCode
= ERROR_INTERNET_TIMEOUT
;
3114 case 425: /* Cannot open data connection. */
3115 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
3118 case 426: /* Connection closed, transer aborted. */
3119 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
3122 case 500: /* Syntax error. Command unrecognized. */
3123 case 501: /* Syntax error. Error in parameters or arguments. */
3124 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
3127 case 530: /* Not logged in. Login incorrect. */
3128 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
3131 case 550: /* File action not taken. File not found or no access. */
3132 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
3135 case 450: /* File action not taken. File may be busy. */
3136 case 451: /* Action aborted. Server error. */
3137 case 452: /* Action not taken. Insufficient storage space on server. */
3138 case 502: /* Command not implemented. */
3139 case 503: /* Bad sequence of command. */
3140 case 504: /* Command not implemented for that parameter. */
3141 case 532: /* Need account for storing files */
3142 case 551: /* Requested action aborted. Page type unknown */
3143 case 552: /* Action aborted. Exceeded storage allocation */
3144 case 553: /* Action not taken. File name not allowed. */
3147 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
3151 INTERNET_SetLastError(dwCode
);