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
= lpwfs
->lpAppInfo
;
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
= lpwfs
->lpAppInfo
;
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
= lpwfs
->lpAppInfo
;
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
= lpwfs
->lpAppInfo
;
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
= lpwfs
->lpAppInfo
;
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
= lpwfs
->lpAppInfo
;
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
= lpwfs
->lpAppInfo
;
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
= lpwfs
->lpAppInfo
;
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
) {
754 len
= *lpdwCurrentDirectory
;
755 if(lpszCurrentDirectory
)
757 dir
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
760 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
765 ret
= FtpGetCurrentDirectoryW(hFtpSession
, lpszCurrentDirectory
?dir
:NULL
, lpdwCurrentDirectory
?&len
:NULL
);
766 if(lpdwCurrentDirectory
) {
767 *lpdwCurrentDirectory
= len
;
768 if(lpszCurrentDirectory
) {
769 WideCharToMultiByte(CP_ACP
, 0, dir
, len
, lpszCurrentDirectory
, *lpdwCurrentDirectory
, NULL
, NULL
);
770 HeapFree(GetProcessHeap(), 0, dir
);
777 /***********************************************************************
778 * FtpGetCurrentDirectoryW (WININET.@)
780 * Retrieves the current directory
787 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
788 LPDWORD lpdwCurrentDirectory
)
790 LPWININETFTPSESSIONW lpwfs
;
791 LPWININETAPPINFOW hIC
= NULL
;
794 TRACE("len(%d)\n", *lpdwCurrentDirectory
);
796 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
797 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
799 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
803 hIC
= lpwfs
->lpAppInfo
;
804 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
806 WORKREQUEST workRequest
;
807 struct WORKREQ_FTPGETCURRENTDIRECTORYW
*req
;
809 workRequest
.asyncall
= FTPGETCURRENTDIRECTORYW
;
810 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
811 req
= &workRequest
.u
.FtpGetCurrentDirectoryW
;
812 req
->lpszDirectory
= lpszCurrentDirectory
;
813 req
->lpdwDirectory
= lpdwCurrentDirectory
;
815 r
= INTERNET_AsyncCall(&workRequest
);
819 r
= FTP_FtpGetCurrentDirectoryW(lpwfs
, lpszCurrentDirectory
,
820 lpdwCurrentDirectory
);
825 WININET_Release( &lpwfs
->hdr
);
831 /***********************************************************************
832 * FTP_FtpGetCurrentDirectoryA (Internal)
834 * Retrieves the current directory
841 BOOL WINAPI
FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPWSTR lpszCurrentDirectory
,
842 LPDWORD lpdwCurrentDirectory
)
845 LPWININETAPPINFOW hIC
= NULL
;
846 DWORD bSuccess
= FALSE
;
848 TRACE("len(%d)\n", *lpdwCurrentDirectory
);
850 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
852 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
856 /* Clear any error information */
857 INTERNET_SetLastError(0);
859 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
861 hIC
= lpwfs
->lpAppInfo
;
862 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
863 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
866 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
869 if (nResCode
== 257) /* Extract directory name */
871 DWORD firstpos
, lastpos
, len
;
872 LPWSTR lpszResponseBuffer
= WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
874 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
876 if ('"' == lpszResponseBuffer
[lastpos
])
885 len
= lastpos
- firstpos
- 1;
886 lstrcpynW(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1], *lpdwCurrentDirectory
);
887 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer
);
888 *lpdwCurrentDirectory
= len
;
892 FTP_SetResponseError(nResCode
);
896 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
898 INTERNET_ASYNC_RESULT iar
;
900 iar
.dwResult
= (DWORD
)bSuccess
;
901 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
902 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
903 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
906 return (DWORD
) bSuccess
;
909 /***********************************************************************
910 * FtpOpenFileA (WININET.@)
912 * Open a remote file for writing or reading
915 * HINTERNET handle on success
919 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
920 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
926 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
927 ret
= FtpOpenFileW(hFtpSession
, lpwzFileName
, fdwAccess
, dwFlags
, dwContext
);
928 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
933 /***********************************************************************
934 * FtpOpenFileW (WININET.@)
936 * Open a remote file for writing or reading
939 * HINTERNET handle on success
943 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
944 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
947 LPWININETFTPSESSIONW lpwfs
;
948 LPWININETAPPINFOW hIC
= NULL
;
951 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession
,
952 debugstr_w(lpszFileName
), fdwAccess
, dwFlags
, dwContext
);
954 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
955 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
957 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
961 if (lpwfs
->download_in_progress
!= NULL
) {
962 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
965 hIC
= lpwfs
->lpAppInfo
;
966 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
968 WORKREQUEST workRequest
;
969 struct WORKREQ_FTPOPENFILEW
*req
;
971 workRequest
.asyncall
= FTPOPENFILEW
;
972 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
973 req
= &workRequest
.u
.FtpOpenFileW
;
974 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
975 req
->dwAccess
= fdwAccess
;
976 req
->dwFlags
= dwFlags
;
977 req
->dwContext
= dwContext
;
979 INTERNET_AsyncCall(&workRequest
);
984 r
= FTP_FtpOpenFileW(lpwfs
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
989 WININET_Release( &lpwfs
->hdr
);
995 /***********************************************************************
996 * FTP_FtpOpenFileW (Internal)
998 * Open a remote file for writing or reading
1001 * HINTERNET handle on success
1005 HINTERNET
FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs
,
1006 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
1010 BOOL bSuccess
= FALSE
;
1011 LPWININETFTPFILE lpwh
= NULL
;
1012 LPWININETAPPINFOW hIC
= NULL
;
1013 HINTERNET handle
= NULL
;
1017 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1019 /* Clear any error information */
1020 INTERNET_SetLastError(0);
1022 if (GENERIC_READ
== fdwAccess
)
1024 /* Set up socket to retrieve data */
1025 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
1027 else if (GENERIC_WRITE
== fdwAccess
)
1029 /* Set up socket to send data */
1030 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
1033 /* Get data socket to server */
1034 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1036 lpwh
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE
));
1037 lpwh
->hdr
.htype
= WH_HFILE
;
1038 lpwh
->hdr
.dwFlags
= dwFlags
;
1039 lpwh
->hdr
.dwContext
= dwContext
;
1040 lpwh
->hdr
.dwRefCount
= 1;
1041 lpwh
->hdr
.destroy
= FTP_CloseFileTransferHandle
;
1042 lpwh
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
1043 lpwh
->nDataSocket
= nDataSocket
;
1044 lpwh
->session_deleted
= FALSE
;
1046 WININET_AddRef( &lpwfs
->hdr
);
1047 lpwh
->lpFtpSession
= lpwfs
;
1049 handle
= WININET_AllocHandle( &lpwh
->hdr
);
1053 /* Indicate that a download is currently in progress */
1054 lpwfs
->download_in_progress
= lpwh
;
1057 if (lpwfs
->lstnSocket
!= -1)
1058 closesocket(lpwfs
->lstnSocket
);
1060 hIC
= lpwfs
->lpAppInfo
;
1061 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1063 INTERNET_ASYNC_RESULT iar
;
1067 iar
.dwResult
= (DWORD
)handle
;
1068 iar
.dwError
= ERROR_SUCCESS
;
1069 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1070 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1073 iar
.dwResult
= (DWORD
)bSuccess
;
1074 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1075 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1076 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1081 WININET_Release( &lpwh
->hdr
);
1087 /***********************************************************************
1088 * FtpGetFileA (WININET.@)
1090 * Retrieve file from the FTP server
1097 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1098 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1101 LPWSTR lpwzRemoteFile
;
1105 lpwzRemoteFile
= lpszRemoteFile
?WININET_strdup_AtoW(lpszRemoteFile
):NULL
;
1106 lpwzNewFile
= lpszNewFile
?WININET_strdup_AtoW(lpszNewFile
):NULL
;
1107 ret
= FtpGetFileW(hInternet
, lpwzRemoteFile
, lpwzNewFile
, fFailIfExists
,
1108 dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1109 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile
);
1110 HeapFree(GetProcessHeap(), 0, lpwzNewFile
);
1115 /***********************************************************************
1116 * FtpGetFileW (WININET.@)
1118 * Retrieve file from the FTP server
1125 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1126 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1129 LPWININETFTPSESSIONW lpwfs
;
1130 LPWININETAPPINFOW hIC
= NULL
;
1133 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hInternet
);
1134 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1136 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1140 if (lpwfs
->download_in_progress
!= NULL
) {
1141 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1145 hIC
= lpwfs
->lpAppInfo
;
1146 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1148 WORKREQUEST workRequest
;
1149 struct WORKREQ_FTPGETFILEW
*req
;
1151 workRequest
.asyncall
= FTPGETFILEW
;
1152 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1153 req
= &workRequest
.u
.FtpGetFileW
;
1154 req
->lpszRemoteFile
= WININET_strdupW(lpszRemoteFile
);
1155 req
->lpszNewFile
= WININET_strdupW(lpszNewFile
);
1156 req
->dwLocalFlagsAttribute
= dwLocalFlagsAttribute
;
1157 req
->fFailIfExists
= fFailIfExists
;
1158 req
->dwFlags
= dwInternetFlags
;
1159 req
->dwContext
= dwContext
;
1161 r
= INTERNET_AsyncCall(&workRequest
);
1165 r
= FTP_FtpGetFileW(lpwfs
, lpszRemoteFile
, lpszNewFile
,
1166 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1171 WININET_Release( &lpwfs
->hdr
);
1177 /***********************************************************************
1178 * FTP_FtpGetFileW (Internal)
1180 * Retrieve file from the FTP server
1187 BOOL WINAPI
FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1188 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1192 BOOL bSuccess
= FALSE
;
1194 LPWININETAPPINFOW hIC
= NULL
;
1196 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile
), debugstr_w(lpszNewFile
));
1198 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1200 /* Clear any error information */
1201 INTERNET_SetLastError(0);
1203 /* Ensure we can write to lpszNewfile by opening it */
1204 hFile
= CreateFileW(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1205 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1206 if (INVALID_HANDLE_VALUE
== hFile
)
1209 /* Set up socket to retrieve data */
1210 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
1216 /* Get data socket to server */
1217 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1222 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
1223 nResCode
= FTP_ReceiveResponse(lpwfs
, dwContext
);
1226 if (nResCode
== 226)
1229 FTP_SetResponseError(nResCode
);
1231 closesocket(nDataSocket
);
1236 if (lpwfs
->lstnSocket
!= -1)
1237 closesocket(lpwfs
->lstnSocket
);
1242 hIC
= lpwfs
->lpAppInfo
;
1243 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1245 INTERNET_ASYNC_RESULT iar
;
1247 iar
.dwResult
= (DWORD
)bSuccess
;
1248 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1249 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1250 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1256 /***********************************************************************
1257 * FtpGetFileSize (WININET.@)
1259 DWORD WINAPI
FtpGetFileSize( HINTERNET hFile
, LPDWORD lpdwFileSizeHigh
)
1261 FIXME("(%p, %p)\n", hFile
, lpdwFileSizeHigh
);
1263 if (lpdwFileSizeHigh
)
1264 *lpdwFileSizeHigh
= 0;
1269 /***********************************************************************
1270 * FtpDeleteFileA (WININET.@)
1272 * Delete a file on the ftp server
1279 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1281 LPWSTR lpwzFileName
;
1284 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
1285 ret
= FtpDeleteFileW(hFtpSession
, lpwzFileName
);
1286 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
1290 /***********************************************************************
1291 * FtpDeleteFileW (WININET.@)
1293 * Delete a file on the ftp server
1300 BOOL WINAPI
FtpDeleteFileW(HINTERNET hFtpSession
, LPCWSTR lpszFileName
)
1302 LPWININETFTPSESSIONW lpwfs
;
1303 LPWININETAPPINFOW hIC
= NULL
;
1306 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1307 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1309 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1313 hIC
= lpwfs
->lpAppInfo
;
1314 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1316 WORKREQUEST workRequest
;
1317 struct WORKREQ_FTPDELETEFILEW
*req
;
1319 workRequest
.asyncall
= FTPDELETEFILEW
;
1320 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1321 req
= &workRequest
.u
.FtpDeleteFileW
;
1322 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
1324 r
= INTERNET_AsyncCall(&workRequest
);
1328 r
= FTP_FtpDeleteFileW(lpwfs
, lpszFileName
);
1333 WININET_Release( &lpwfs
->hdr
);
1338 /***********************************************************************
1339 * FTP_FtpDeleteFileW (Internal)
1341 * Delete a file on the ftp server
1348 BOOL
FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszFileName
)
1351 BOOL bSuccess
= FALSE
;
1352 LPWININETAPPINFOW hIC
= NULL
;
1354 TRACE("%p\n", lpwfs
);
1356 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1358 /* Clear any error information */
1359 INTERNET_SetLastError(0);
1361 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1364 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1367 if (nResCode
== 250)
1370 FTP_SetResponseError(nResCode
);
1373 hIC
= lpwfs
->lpAppInfo
;
1374 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1376 INTERNET_ASYNC_RESULT iar
;
1378 iar
.dwResult
= (DWORD
)bSuccess
;
1379 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1380 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1381 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1388 /***********************************************************************
1389 * FtpRemoveDirectoryA (WININET.@)
1391 * Remove a directory on the ftp server
1398 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1400 LPWSTR lpwzDirectory
;
1403 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
1404 ret
= FtpRemoveDirectoryW(hFtpSession
, lpwzDirectory
);
1405 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
1409 /***********************************************************************
1410 * FtpRemoveDirectoryW (WININET.@)
1412 * Remove a directory on the ftp server
1419 BOOL WINAPI
FtpRemoveDirectoryW(HINTERNET hFtpSession
, LPCWSTR lpszDirectory
)
1421 LPWININETFTPSESSIONW lpwfs
;
1422 LPWININETAPPINFOW hIC
= NULL
;
1425 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1426 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1428 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1432 hIC
= lpwfs
->lpAppInfo
;
1433 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1435 WORKREQUEST workRequest
;
1436 struct WORKREQ_FTPREMOVEDIRECTORYW
*req
;
1438 workRequest
.asyncall
= FTPREMOVEDIRECTORYW
;
1439 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1440 req
= &workRequest
.u
.FtpRemoveDirectoryW
;
1441 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
1443 r
= INTERNET_AsyncCall(&workRequest
);
1447 r
= FTP_FtpRemoveDirectoryW(lpwfs
, lpszDirectory
);
1452 WININET_Release( &lpwfs
->hdr
);
1457 /***********************************************************************
1458 * FTP_FtpRemoveDirectoryW (Internal)
1460 * Remove a directory on the ftp server
1467 BOOL
FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
1470 BOOL bSuccess
= FALSE
;
1471 LPWININETAPPINFOW hIC
= NULL
;
1475 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1477 /* Clear any error information */
1478 INTERNET_SetLastError(0);
1480 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1483 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1486 if (nResCode
== 250)
1489 FTP_SetResponseError(nResCode
);
1493 hIC
= lpwfs
->lpAppInfo
;
1494 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1496 INTERNET_ASYNC_RESULT iar
;
1498 iar
.dwResult
= (DWORD
)bSuccess
;
1499 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1500 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1501 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1508 /***********************************************************************
1509 * FtpRenameFileA (WININET.@)
1511 * Rename a file on the ftp server
1518 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1524 lpwzSrc
= lpszSrc
?WININET_strdup_AtoW(lpszSrc
):NULL
;
1525 lpwzDest
= lpszDest
?WININET_strdup_AtoW(lpszDest
):NULL
;
1526 ret
= FtpRenameFileW(hFtpSession
, lpwzSrc
, lpwzDest
);
1527 HeapFree(GetProcessHeap(), 0, lpwzSrc
);
1528 HeapFree(GetProcessHeap(), 0, lpwzDest
);
1532 /***********************************************************************
1533 * FtpRenameFileW (WININET.@)
1535 * Rename a file on the ftp server
1542 BOOL WINAPI
FtpRenameFileW(HINTERNET hFtpSession
, LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1544 LPWININETFTPSESSIONW lpwfs
;
1545 LPWININETAPPINFOW hIC
= NULL
;
1548 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1549 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1551 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1555 hIC
= lpwfs
->lpAppInfo
;
1556 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1558 WORKREQUEST workRequest
;
1559 struct WORKREQ_FTPRENAMEFILEW
*req
;
1561 workRequest
.asyncall
= FTPRENAMEFILEW
;
1562 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1563 req
= &workRequest
.u
.FtpRenameFileW
;
1564 req
->lpszSrcFile
= WININET_strdupW(lpszSrc
);
1565 req
->lpszDestFile
= WININET_strdupW(lpszDest
);
1567 r
= INTERNET_AsyncCall(&workRequest
);
1571 r
= FTP_FtpRenameFileW(lpwfs
, lpszSrc
, lpszDest
);
1576 WININET_Release( &lpwfs
->hdr
);
1581 /***********************************************************************
1582 * FTP_FtpRenameFileW (Internal)
1584 * Rename a file on the ftp server
1591 BOOL
FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs
,
1592 LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1595 BOOL bSuccess
= FALSE
;
1596 LPWININETAPPINFOW hIC
= NULL
;
1600 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1602 /* Clear any error information */
1603 INTERNET_SetLastError(0);
1605 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1608 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1609 if (nResCode
== 350)
1611 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1614 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1617 if (nResCode
== 250)
1620 FTP_SetResponseError(nResCode
);
1623 hIC
= lpwfs
->lpAppInfo
;
1624 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1626 INTERNET_ASYNC_RESULT iar
;
1628 iar
.dwResult
= (DWORD
)bSuccess
;
1629 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1630 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1631 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1637 /***********************************************************************
1638 * FtpCommandA (WININET.@)
1640 BOOL WINAPI
FtpCommandA( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1641 LPCSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1643 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1644 debugstr_a(lpszCommand
), dwContext
, phFtpCommand
);
1649 /***********************************************************************
1650 * FtpCommandW (WININET.@)
1652 BOOL WINAPI
FtpCommandW( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1653 LPCWSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1655 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1656 debugstr_w(lpszCommand
), dwContext
, phFtpCommand
);
1661 /***********************************************************************
1662 * FTP_Connect (internal)
1664 * Connect to a ftp server
1667 * HINTERNET a session handle on success
1672 * Windows uses 'anonymous' as the username, when given a NULL username
1673 * and a NULL password. The password is first looked up in:
1675 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1677 * If this entry is not present it uses the current username as the password.
1681 HINTERNET
FTP_Connect(LPWININETAPPINFOW hIC
, LPCWSTR lpszServerName
,
1682 INTERNET_PORT nServerPort
, LPCWSTR lpszUserName
,
1683 LPCWSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
,
1684 DWORD dwInternalFlags
)
1686 static const WCHAR szKey
[] = {'S','o','f','t','w','a','r','e','\\',
1687 'M','i','c','r','o','s','o','f','t','\\',
1688 'W','i','n','d','o','w','s','\\',
1689 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1690 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1691 static const WCHAR szValue
[] = {'E','m','a','i','l','N','a','m','e',0};
1692 static const WCHAR szDefaultUsername
[] = {'a','n','o','n','y','m','o','u','s','\0'};
1693 static const WCHAR szEmpty
[] = {'\0'};
1694 struct sockaddr_in socketAddr
;
1697 BOOL bSuccess
= FALSE
;
1698 LPWININETFTPSESSIONW lpwfs
= NULL
;
1699 HINTERNET handle
= NULL
;
1701 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1702 hIC
, debugstr_w(lpszServerName
),
1703 nServerPort
, debugstr_w(lpszUserName
), debugstr_w(lpszPassword
));
1705 assert( hIC
->hdr
.htype
== WH_HINIT
);
1707 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1709 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1713 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW
));
1716 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1720 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1721 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1723 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1724 lpwfs
->hdr
.dwFlags
= dwFlags
;
1725 lpwfs
->hdr
.dwContext
= dwContext
;
1726 lpwfs
->hdr
.dwInternalFlags
= dwInternalFlags
;
1727 lpwfs
->hdr
.dwRefCount
= 1;
1728 lpwfs
->hdr
.destroy
= FTP_CloseSessionHandle
;
1729 lpwfs
->hdr
.lpfnStatusCB
= hIC
->hdr
.lpfnStatusCB
;
1730 lpwfs
->download_in_progress
= NULL
;
1732 WININET_AddRef( &hIC
->hdr
);
1733 lpwfs
->lpAppInfo
= hIC
;
1735 handle
= WININET_AllocHandle( &lpwfs
->hdr
);
1738 ERR("Failed to alloc handle\n");
1739 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1743 if(hIC
->lpszProxy
&& hIC
->dwAccessType
== INTERNET_OPEN_TYPE_PROXY
) {
1744 if(strchrW(hIC
->lpszProxy
, ' '))
1745 FIXME("Several proxies not implemented.\n");
1746 if(hIC
->lpszProxyBypass
)
1747 FIXME("Proxy bypass is ignored.\n");
1749 if ( !lpszUserName
) {
1751 WCHAR szPassword
[MAX_PATH
];
1752 DWORD len
= sizeof(szPassword
);
1754 lpwfs
->lpszUserName
= WININET_strdupW(szDefaultUsername
);
1756 RegOpenKeyW(HKEY_CURRENT_USER
, szKey
, &key
);
1757 if (RegQueryValueExW(key
, szValue
, NULL
, NULL
, (LPBYTE
)szPassword
, &len
)) {
1758 /* Nothing in the registry, get the username and use that as the password */
1759 if (!GetUserNameW(szPassword
, &len
)) {
1760 /* Should never get here, but use an empty password as failsafe */
1761 strcpyW(szPassword
, szEmpty
);
1766 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword
));
1767 lpwfs
->lpszPassword
= WININET_strdupW(szPassword
);
1770 lpwfs
->lpszUserName
= WININET_strdupW(lpszUserName
);
1773 lpwfs
->lpszPassword
= WININET_strdupW(lpszPassword
);
1775 lpwfs
->lpszPassword
= WININET_strdupW(szEmpty
);
1778 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1779 if (!(lpwfs
->hdr
.dwInternalFlags
& INET_OPENURL
))
1781 INTERNET_ASYNC_RESULT iar
;
1783 iar
.dwResult
= (DWORD
)handle
;
1784 iar
.dwError
= ERROR_SUCCESS
;
1786 SendAsyncCallback(&hIC
->hdr
, dwContext
,
1787 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
1788 sizeof(INTERNET_ASYNC_RESULT
));
1791 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1792 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1794 if (!GetAddress(lpszServerName
, nServerPort
, &socketAddr
))
1796 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1800 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1801 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1803 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1806 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1810 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1811 &socketAddr
, sizeof(struct sockaddr_in
));
1813 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1815 ERR("Unable to connect (%s)\n", strerror(errno
));
1816 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1820 TRACE("Connected to server\n");
1821 lpwfs
->sndSocket
= nsocket
;
1822 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1823 &socketAddr
, sizeof(struct sockaddr_in
));
1825 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1826 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1828 if (FTP_ConnectToHost(lpwfs
))
1830 TRACE("Successfully logged into server\n");
1836 if (!bSuccess
&& nsocket
== -1)
1837 closesocket(nsocket
);
1839 if (!bSuccess
&& lpwfs
)
1841 HeapFree(GetProcessHeap(), 0, lpwfs
);
1842 WININET_FreeHandle( handle
);
1847 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1849 INTERNET_ASYNC_RESULT iar
;
1851 iar
.dwResult
= (DWORD
)lpwfs
;
1852 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1853 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1854 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1861 /***********************************************************************
1862 * FTP_ConnectToHost (internal)
1864 * Connect to a ftp server
1871 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
)
1874 BOOL bSuccess
= FALSE
;
1877 FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1879 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1882 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1885 /* Login successful... */
1886 if (nResCode
== 230)
1888 /* User name okay, need password... */
1889 else if (nResCode
== 331)
1890 bSuccess
= FTP_SendPassword(lpwfs
);
1891 /* Need account for login... */
1892 else if (nResCode
== 332)
1893 bSuccess
= FTP_SendAccount(lpwfs
);
1895 FTP_SetResponseError(nResCode
);
1898 TRACE("Returning %d\n", bSuccess
);
1904 /***********************************************************************
1905 * FTP_SendCommandA (internal)
1907 * Send command to server
1914 static BOOL
FTP_SendCommandA(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
1915 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
)
1919 DWORD nBytesSent
= 0;
1923 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
1927 lpfnStatusCB(hdr
->hInternet
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1930 dwParamLen
= lpszParam
?strlen(lpszParam
)+1:0;
1931 len
= dwParamLen
+ strlen(szFtpCommands
[ftpCmd
]) + strlen(szCRLF
);
1932 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1934 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1937 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], dwParamLen
? " " : "",
1938 dwParamLen
? lpszParam
: "", szCRLF
);
1940 TRACE("Sending (%s) len(%d)\n", buf
, len
);
1941 while((nBytesSent
< len
) && (nRC
!= -1))
1943 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1947 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1951 lpfnStatusCB(hdr
->hInternet
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1952 &nBytesSent
, sizeof(DWORD
));
1955 TRACE("Sent %d bytes\n", nBytesSent
);
1959 /***********************************************************************
1960 * FTP_SendCommand (internal)
1962 * Send command to server
1969 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
1970 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
)
1973 LPSTR lpszParamA
= lpszParam
?WININET_strdup_WtoA(lpszParam
):NULL
;
1974 ret
= FTP_SendCommandA(nSocket
, ftpCmd
, lpszParamA
, lpfnStatusCB
, hdr
, dwContext
);
1975 HeapFree(GetProcessHeap(), 0, lpszParamA
);
1979 /***********************************************************************
1980 * FTP_ReceiveResponse (internal)
1982 * Receive response from server
1985 * Reply code on success
1989 INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD dwContext
)
1991 LPSTR lpszResponse
= INTERNET_GetResponseBuffer();
1994 char firstprefix
[5];
1995 BOOL multiline
= FALSE
;
1996 LPWININETAPPINFOW hIC
= NULL
;
1998 TRACE("socket(%d)\n", lpwfs
->sndSocket
);
2000 hIC
= lpwfs
->lpAppInfo
;
2001 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
2005 if (!INTERNET_GetNextLine(lpwfs
->sndSocket
, &nRecv
))
2012 if(lpszResponse
[3] != '-')
2015 { /* Start of multiline repsonse. Loop until we get "nnn " */
2017 memcpy(firstprefix
, lpszResponse
, 3);
2018 firstprefix
[3] = ' ';
2019 firstprefix
[4] = '\0';
2024 if(!memcmp(firstprefix
, lpszResponse
, 4))
2032 rc
= atoi(lpszResponse
);
2034 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
2035 &nRecv
, sizeof(DWORD
));
2039 TRACE("return %d\n", rc
);
2044 /***********************************************************************
2045 * FTP_SendPassword (internal)
2047 * Send password to ftp server
2054 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
)
2057 BOOL bSuccess
= FALSE
;
2060 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
2063 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2066 TRACE("Received reply code %d\n", nResCode
);
2067 /* Login successful... */
2068 if (nResCode
== 230)
2070 /* Command not implemented, superfluous at the server site... */
2071 /* Need account for login... */
2072 else if (nResCode
== 332)
2073 bSuccess
= FTP_SendAccount(lpwfs
);
2075 FTP_SetResponseError(nResCode
);
2079 TRACE("Returning %d\n", bSuccess
);
2084 /***********************************************************************
2085 * FTP_SendAccount (internal)
2094 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
)
2097 BOOL bSuccess
= FALSE
;
2100 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, szNoAccount
, 0, 0, 0))
2103 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2107 FTP_SetResponseError(nResCode
);
2114 /***********************************************************************
2115 * FTP_SendStore (internal)
2117 * Send request to upload file to ftp server
2124 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2127 BOOL bSuccess
= FALSE
;
2130 if (!FTP_InitListenSocket(lpwfs
))
2133 if (!FTP_SendType(lpwfs
, dwType
))
2136 if (!FTP_SendPortOrPasv(lpwfs
))
2139 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
2141 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2144 if (nResCode
== 150 || nResCode
== 125)
2147 FTP_SetResponseError(nResCode
);
2151 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
2153 closesocket(lpwfs
->lstnSocket
);
2154 lpwfs
->lstnSocket
= -1;
2161 /***********************************************************************
2162 * FTP_InitListenSocket (internal)
2164 * Create a socket to listen for server response
2171 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
)
2173 BOOL bSuccess
= FALSE
;
2174 size_t namelen
= sizeof(struct sockaddr_in
);
2178 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
2179 if (lpwfs
->lstnSocket
== -1)
2181 TRACE("Unable to create listening socket\n");
2185 /* We obtain our ip addr from the name of the command channel socket */
2186 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
2188 /* and get the system to assign us a port */
2189 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
2191 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
2193 TRACE("Unable to bind socket\n");
2197 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
2199 TRACE("listen failed\n");
2203 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
2207 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
2209 closesocket(lpwfs
->lstnSocket
);
2210 lpwfs
->lstnSocket
= -1;
2217 /***********************************************************************
2218 * FTP_SendType (internal)
2220 * Tell server type of data being transferred
2226 * W98SE doesn't cache the type that's currently set
2227 * (i.e. it sends it always),
2228 * so we probably don't want to do that either.
2230 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
)
2233 WCHAR type
[] = { 'I','\0' };
2234 BOOL bSuccess
= FALSE
;
2237 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
2240 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
2243 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
)/100;
2249 FTP_SetResponseError(nResCode
);
2256 /***********************************************************************
2257 * FTP_GetFileSize (internal)
2259 * Retrieves from the server the size of the given file
2266 static BOOL
FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD
*dwSize
)
2269 BOOL bSuccess
= FALSE
;
2273 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
2276 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2279 if (nResCode
== 213) {
2280 /* Now parses the output to get the actual file size */
2282 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2284 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
2285 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
2286 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2290 FTP_SetResponseError(nResCode
);
2299 /***********************************************************************
2300 * FTP_SendPort (internal)
2302 * Tell server which port to use
2309 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
)
2311 static const WCHAR szIPFormat
[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2313 WCHAR szIPAddress
[64];
2314 BOOL bSuccess
= FALSE
;
2317 sprintfW(szIPAddress
, szIPFormat
,
2318 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2319 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2320 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2321 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2322 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2323 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2325 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2328 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2331 if (nResCode
== 200)
2334 FTP_SetResponseError(nResCode
);
2342 /***********************************************************************
2343 * FTP_DoPassive (internal)
2345 * Tell server that we want to do passive transfers
2346 * and connect data socket
2353 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
)
2356 BOOL bSuccess
= FALSE
;
2359 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2362 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2365 if (nResCode
== 227)
2367 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2371 char *pAddr
, *pPort
;
2373 struct sockaddr_in dataSocketAddress
;
2375 p
= lpszResponseBuffer
+4; /* skip status code */
2377 /* do a very strict check; we can improve that later. */
2379 if (strncmp(p
, "Entering Passive Mode", 21))
2381 ERR("unknown response '%.*s', aborting\n", 21, p
);
2384 p
+= 21; /* skip string */
2385 if ((*p
++ != ' ') || (*p
++ != '('))
2387 ERR("unknown response format, aborting\n");
2391 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2394 ERR("unknown response address format '%s', aborting\n", p
);
2397 for (i
=0; i
< 6; i
++)
2400 dataSocketAddress
= lpwfs
->socketAddress
;
2401 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2402 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2410 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2414 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2416 ERR("can't connect passive FTP data port.\n");
2417 closesocket(nsocket
);
2420 lpwfs
->pasvSocket
= nsocket
;
2424 FTP_SetResponseError(nResCode
);
2432 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
)
2434 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2436 if (!FTP_DoPassive(lpwfs
))
2441 if (!FTP_SendPort(lpwfs
))
2448 /***********************************************************************
2449 * FTP_GetDataSocket (internal)
2451 * Either accepts an incoming data socket connection from the server
2452 * or just returns the already opened socket after a PASV command
2453 * in case of passive FTP.
2461 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
)
2463 struct sockaddr_in saddr
;
2464 size_t addrlen
= sizeof(struct sockaddr
);
2467 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2469 *nDataSocket
= lpwfs
->pasvSocket
;
2473 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2474 closesocket(lpwfs
->lstnSocket
);
2475 lpwfs
->lstnSocket
= -1;
2477 return *nDataSocket
!= -1;
2481 /***********************************************************************
2482 * FTP_SendData (internal)
2484 * Send data to the server
2491 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
)
2493 BY_HANDLE_FILE_INFORMATION fi
;
2494 DWORD nBytesRead
= 0;
2495 DWORD nBytesSent
= 0;
2496 DWORD nTotalSent
= 0;
2497 DWORD nBytesToSend
, nLen
;
2499 time_t s_long_time
, e_long_time
;
2504 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2505 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2507 /* Get the size of the file. */
2508 GetFileInformationByHandle(hFile
, &fi
);
2513 nBytesToSend
= nBytesRead
- nBytesSent
;
2515 if (nBytesToSend
<= 0)
2517 /* Read data from file. */
2519 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2520 ERR("Failed reading from file\n");
2523 nBytesToSend
= nBytesRead
;
2528 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2529 DATA_PACKET_SIZE
: nBytesToSend
;
2530 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2538 /* Do some computation to display the status. */
2540 nSeconds
= e_long_time
- s_long_time
;
2541 if( nSeconds
/ 60 > 0 )
2543 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2544 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2545 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2549 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2550 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2551 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2553 } while (nRC
!= -1);
2555 TRACE("file transfer complete!\n");
2557 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2563 /***********************************************************************
2564 * FTP_SendRetrieve (internal)
2566 * Send request to retrieve a file
2569 * Number of bytes to be received on success
2573 static DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2579 if (!FTP_InitListenSocket(lpwfs
))
2582 if (!FTP_SendType(lpwfs
, dwType
))
2585 if (!FTP_SendPortOrPasv(lpwfs
))
2588 if (!FTP_GetFileSize(lpwfs
, lpszRemoteFile
, &nResult
))
2591 TRACE("Waiting to receive %d bytes\n", nResult
);
2593 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2596 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2597 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2598 /* That means that we got an error getting the file. */
2603 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2605 closesocket(lpwfs
->lstnSocket
);
2606 lpwfs
->lstnSocket
= -1;
2613 /***********************************************************************
2614 * FTP_RetrieveData (internal)
2616 * Retrieve data from server
2623 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2625 DWORD nBytesWritten
;
2626 DWORD nBytesReceived
= 0;
2632 if (INVALID_HANDLE_VALUE
== hFile
)
2635 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2636 if (NULL
== lpszBuffer
)
2638 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2642 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2644 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2647 /* other side closed socket. */
2650 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2651 nBytesReceived
+= nRC
;
2654 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived
, nBytes
,
2655 nBytesReceived
* 100 / nBytes
);
2658 TRACE("Data transfer complete\n");
2659 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2666 /***********************************************************************
2667 * FTP_CloseSessionHandle (internal)
2669 * Deallocate session handle
2676 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
)
2678 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) hdr
;
2682 WININET_Release(&lpwfs
->lpAppInfo
->hdr
);
2684 if (lpwfs
->download_in_progress
!= NULL
)
2685 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2687 if (lpwfs
->sndSocket
!= -1)
2688 closesocket(lpwfs
->sndSocket
);
2690 if (lpwfs
->lstnSocket
!= -1)
2691 closesocket(lpwfs
->lstnSocket
);
2693 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2694 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2695 HeapFree(GetProcessHeap(), 0, lpwfs
);
2699 /***********************************************************************
2700 * FTP_FindNextFileW (Internal)
2702 * Continues a file search from a previous call to FindFirstFile
2709 BOOL WINAPI
FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh
, LPVOID lpvFindData
)
2711 BOOL bSuccess
= TRUE
;
2712 LPWIN32_FIND_DATAW lpFindFileData
;
2714 TRACE("index(%d) size(%d)\n", lpwh
->index
, lpwh
->size
);
2716 assert (lpwh
->hdr
.htype
== WH_HFTPFINDNEXT
);
2718 /* Clear any error information */
2719 INTERNET_SetLastError(0);
2721 lpFindFileData
= (LPWIN32_FIND_DATAW
) lpvFindData
;
2722 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2724 if (lpwh
->index
>= lpwh
->size
)
2726 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2731 FTP_ConvertFileProp(&lpwh
->lpafp
[lpwh
->index
], lpFindFileData
);
2734 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData
->cFileName
), lpFindFileData
->nFileSizeLow
);
2738 if (lpwh
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
2740 INTERNET_ASYNC_RESULT iar
;
2742 iar
.dwResult
= (DWORD
)bSuccess
;
2743 iar
.dwError
= iar
.dwError
= bSuccess
? ERROR_SUCCESS
:
2744 INTERNET_GetLastError();
2746 INTERNET_SendCallback(&lpwh
->hdr
, lpwh
->hdr
.dwContext
,
2747 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
2748 sizeof(INTERNET_ASYNC_RESULT
));
2755 /***********************************************************************
2756 * FTP_CloseFindNextHandle (internal)
2758 * Deallocate session handle
2765 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
)
2767 LPWININETFTPFINDNEXTW lpwfn
= (LPWININETFTPFINDNEXTW
) hdr
;
2772 WININET_Release(&lpwfn
->lpFtpSession
->hdr
);
2774 for (i
= 0; i
< lpwfn
->size
; i
++)
2776 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2779 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2780 HeapFree(GetProcessHeap(), 0, lpwfn
);
2783 /***********************************************************************
2784 * FTP_CloseFileTransferHandle (internal)
2786 * Closes the file transfer handle. This also 'cleans' the data queue of
2787 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2790 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
)
2792 LPWININETFTPFILE lpwh
= (LPWININETFTPFILE
) hdr
;
2793 LPWININETFTPSESSIONW lpwfs
= lpwh
->lpFtpSession
;
2798 WININET_Release(&lpwh
->lpFtpSession
->hdr
);
2800 if (!lpwh
->session_deleted
)
2801 lpwfs
->download_in_progress
= NULL
;
2803 /* This just serves to flush the control socket of any spurrious lines written
2804 to it (like '226 Transfer complete.').
2806 Wonder what to do if the server sends us an error code though...
2808 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2810 if (lpwh
->nDataSocket
!= -1)
2811 closesocket(lpwh
->nDataSocket
);
2813 HeapFree(GetProcessHeap(), 0, lpwh
);
2816 /***********************************************************************
2817 * FTP_ReceiveFileList (internal)
2819 * Read file list from server
2822 * Handle to file list on success
2826 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
2827 LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwContext
)
2830 LPFILEPROPERTIESW lpafp
= NULL
;
2831 LPWININETFTPFINDNEXTW lpwfn
= NULL
;
2832 HINTERNET handle
= 0;
2834 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs
, nSocket
, debugstr_w(lpszSearchFile
), lpFindFileData
, dwContext
);
2836 if (FTP_ParseDirectory(lpwfs
, nSocket
, lpszSearchFile
, &lpafp
, &dwSize
))
2839 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2841 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFTPFINDNEXTW
));
2844 lpwfn
->hdr
.htype
= WH_HFTPFINDNEXT
;
2845 lpwfn
->hdr
.dwContext
= dwContext
;
2846 lpwfn
->hdr
.dwRefCount
= 1;
2847 lpwfn
->hdr
.destroy
= FTP_CloseFindNextHandle
;
2848 lpwfn
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
2849 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2850 lpwfn
->size
= dwSize
;
2851 lpwfn
->lpafp
= lpafp
;
2853 WININET_AddRef( &lpwfs
->hdr
);
2854 lpwfn
->lpFtpSession
= lpwfs
;
2856 handle
= WININET_AllocHandle( &lpwfn
->hdr
);
2861 WININET_Release( &lpwfn
->hdr
);
2863 TRACE("Matched %d files\n", dwSize
);
2868 /***********************************************************************
2869 * FTP_ConvertFileProp (internal)
2871 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2878 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp
, LPWIN32_FIND_DATAW lpFindFileData
)
2880 BOOL bSuccess
= FALSE
;
2882 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAW
));
2886 /* Convert 'Unix' time to Windows time */
2887 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
2888 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
2889 lpFindFileData
->ftLastWriteTime
= lpFindFileData
->ftLastAccessTime
;
2890 lpFindFileData
->ftCreationTime
= lpFindFileData
->ftLastAccessTime
;
2892 /* Not all fields are filled in */
2893 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2894 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
2896 if (lpafp
->bIsDirectory
)
2897 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2899 if (lpafp
->lpszName
)
2900 lstrcpynW(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2908 /***********************************************************************
2909 * FTP_ParseNextFile (internal)
2911 * Parse the next line in file listing
2917 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW lpfp
)
2919 static const char szSpace
[] = " \t";
2927 lpfp
->lpszName
= NULL
;
2929 if(!(pszLine
= INTERNET_GetNextLine(nSocket
, &nBufLen
)))
2932 pszToken
= strtok(pszLine
, szSpace
);
2934 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2937 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2939 if(!isdigit(pszToken
[0]) && 10 == strlen(pszToken
)) {
2940 if(!FTP_ParsePermission(pszToken
, lpfp
))
2941 lpfp
->bIsDirectory
= FALSE
;
2942 for(i
=0; i
<=3; i
++) {
2943 if(!(pszToken
= strtok(NULL
, szSpace
)))
2946 if(!pszToken
) continue;
2947 if(lpfp
->bIsDirectory
) {
2948 TRACE("Is directory\n");
2952 TRACE("Size: %s\n", pszToken
);
2953 lpfp
->nSize
= atol(pszToken
);
2956 lpfp
->tmLastModified
.tm_sec
= 0;
2957 lpfp
->tmLastModified
.tm_min
= 0;
2958 lpfp
->tmLastModified
.tm_hour
= 0;
2959 lpfp
->tmLastModified
.tm_mday
= 0;
2960 lpfp
->tmLastModified
.tm_mon
= 0;
2961 lpfp
->tmLastModified
.tm_year
= 0;
2963 /* Determine month */
2964 pszToken
= strtok(NULL
, szSpace
);
2965 if(!pszToken
) continue;
2966 if(strlen(pszToken
) >= 3) {
2968 if((pszTmp
= StrStrIA(szMonths
, pszToken
)))
2969 lpfp
->tmLastModified
.tm_mon
= ((pszTmp
- szMonths
) / 3)+1;
2972 pszToken
= strtok(NULL
, szSpace
);
2973 if(!pszToken
) continue;
2974 lpfp
->tmLastModified
.tm_mday
= atoi(pszToken
);
2975 /* Determine time or year */
2976 pszToken
= strtok(NULL
, szSpace
);
2977 if(!pszToken
) continue;
2978 if((pszTmp
= strchr(pszToken
, ':'))) {
2983 lpfp
->tmLastModified
.tm_min
= atoi(pszTmp
);
2984 lpfp
->tmLastModified
.tm_hour
= atoi(pszToken
);
2986 apTM
= localtime(&aTime
);
2987 lpfp
->tmLastModified
.tm_year
= apTM
->tm_year
;
2990 lpfp
->tmLastModified
.tm_year
= atoi(pszToken
) - 1900;
2991 lpfp
->tmLastModified
.tm_hour
= 12;
2993 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
2994 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
2995 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
2996 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
2998 pszToken
= strtok(NULL
, szSpace
);
2999 if(!pszToken
) continue;
3000 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3001 TRACE("File: %s\n", debugstr_w(lpfp
->lpszName
));
3003 /* NT way of parsing ... :
3005 07-13-03 08:55PM <DIR> sakpatch
3006 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3008 else if(isdigit(pszToken
[0]) && 8 == strlen(pszToken
)) {
3009 lpfp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
3011 sscanf(pszToken
, "%d-%d-%d",
3012 &lpfp
->tmLastModified
.tm_mon
,
3013 &lpfp
->tmLastModified
.tm_mday
,
3014 &lpfp
->tmLastModified
.tm_year
);
3016 /* Hacky and bad Y2K protection :-) */
3017 if (lpfp
->tmLastModified
.tm_year
< 70)
3018 lpfp
->tmLastModified
.tm_year
+= 100;
3020 pszToken
= strtok(NULL
, szSpace
);
3021 if(!pszToken
) continue;
3022 sscanf(pszToken
, "%d:%d",
3023 &lpfp
->tmLastModified
.tm_hour
,
3024 &lpfp
->tmLastModified
.tm_min
);
3025 if((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
3026 lpfp
->tmLastModified
.tm_hour
+= 12;
3028 lpfp
->tmLastModified
.tm_sec
= 0;
3030 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3031 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3032 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3033 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3035 pszToken
= strtok(NULL
, szSpace
);
3036 if(!pszToken
) continue;
3037 if(!strcasecmp(pszToken
, "<DIR>")) {
3038 lpfp
->bIsDirectory
= TRUE
;
3040 TRACE("Is directory\n");
3043 lpfp
->bIsDirectory
= FALSE
;
3044 lpfp
->nSize
= atol(pszToken
);
3045 TRACE("Size: %d\n", lpfp
->nSize
);
3048 pszToken
= strtok(NULL
, szSpace
);
3049 if(!pszToken
) continue;
3050 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3051 TRACE("Name: %s\n", debugstr_w(lpfp
->lpszName
));
3053 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3054 else if(pszToken
[0] == '+') {
3055 FIXME("EPLF Format not implemented\n");
3058 if(lpfp
->lpszName
) {
3059 if((lpszSearchFile
== NULL
) ||
3060 (PathMatchSpecW(lpfp
->lpszName
, lpszSearchFile
))) {
3062 TRACE("Matched: %s\n", debugstr_w(lpfp
->lpszName
));
3065 HeapFree(GetProcessHeap(), 0, lpfp
->lpszName
);
3066 lpfp
->lpszName
= NULL
;
3073 /***********************************************************************
3074 * FTP_ParseDirectory (internal)
3076 * Parse string of directory information
3082 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
3083 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
)
3085 BOOL bSuccess
= TRUE
;
3086 INT sizeFilePropArray
= 500;/*20; */
3087 INT indexFilePropArray
= -1;
3091 /* Allocate intial file properties array */
3092 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESW
)*(sizeFilePropArray
));
3097 if (indexFilePropArray
+1 >= sizeFilePropArray
)
3099 LPFILEPROPERTIESW tmpafp
;
3101 sizeFilePropArray
*= 2;
3102 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
3103 sizeof(FILEPROPERTIESW
)*sizeFilePropArray
);
3112 indexFilePropArray
++;
3113 } while (FTP_ParseNextFile(nSocket
, lpszSearchFile
, &(*lpafp
)[indexFilePropArray
]));
3115 if (bSuccess
&& indexFilePropArray
)
3117 if (indexFilePropArray
< sizeFilePropArray
- 1)
3119 LPFILEPROPERTIESW tmpafp
;
3121 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
3122 sizeof(FILEPROPERTIESW
)*indexFilePropArray
);
3126 *dwfp
= indexFilePropArray
;
3130 HeapFree(GetProcessHeap(), 0, *lpafp
);
3131 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
3139 /***********************************************************************
3140 * FTP_ParsePermission (internal)
3142 * Parse permission string of directory information
3149 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
)
3151 BOOL bSuccess
= TRUE
;
3152 unsigned short nPermission
= 0;
3157 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
3163 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
3169 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
3172 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
3175 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
3178 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
3181 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
3184 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
3187 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
3190 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
3193 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
3197 }while (nPos
<= nLast
);
3199 lpfp
->permissions
= nPermission
;
3204 /***********************************************************************
3205 * FTP_SetResponseError (internal)
3207 * Set the appropriate error code for a given response from the server
3212 static DWORD
FTP_SetResponseError(DWORD dwResponse
)
3218 case 421: /* Service not available - Server may be shutting down. */
3219 dwCode
= ERROR_INTERNET_TIMEOUT
;
3222 case 425: /* Cannot open data connection. */
3223 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
3226 case 426: /* Connection closed, transer aborted. */
3227 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
3230 case 500: /* Syntax error. Command unrecognized. */
3231 case 501: /* Syntax error. Error in parameters or arguments. */
3232 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
3235 case 530: /* Not logged in. Login incorrect. */
3236 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
3239 case 550: /* File action not taken. File not found or no access. */
3240 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
3243 case 450: /* File action not taken. File may be busy. */
3244 case 451: /* Action aborted. Server error. */
3245 case 452: /* Action not taken. Insufficient storage space on server. */
3246 case 502: /* Command not implemented. */
3247 case 503: /* Bad sequence of command. */
3248 case 504: /* Command not implemented for that parameter. */
3249 case 532: /* Need account for storing files */
3250 case 551: /* Requested action aborted. Page type unknown */
3251 case 552: /* Action aborted. Exceeded storage allocation */
3252 case 553: /* Action not taken. File name not allowed. */
3255 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
3259 INTERNET_SetLastError(dwCode
);