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 HINTERNET hHandle
= WININET_FindHandle( hdr
);
1930 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1931 WININET_Release( hdr
);
1935 dwParamLen
= lpszParam
?strlen(lpszParam
)+1:0;
1936 len
= dwParamLen
+ strlen(szFtpCommands
[ftpCmd
]) + strlen(szCRLF
);
1937 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1939 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1942 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], dwParamLen
? " " : "",
1943 dwParamLen
? lpszParam
: "", szCRLF
);
1945 TRACE("Sending (%s) len(%d)\n", buf
, len
);
1946 while((nBytesSent
< len
) && (nRC
!= -1))
1948 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1952 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1956 HINTERNET hHandle
= WININET_FindHandle( hdr
);
1959 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1960 &nBytesSent
, sizeof(DWORD
));
1961 WININET_Release( hdr
);
1965 TRACE("Sent %d bytes\n", nBytesSent
);
1969 /***********************************************************************
1970 * FTP_SendCommand (internal)
1972 * Send command to server
1979 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
1980 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
)
1983 LPSTR lpszParamA
= lpszParam
?WININET_strdup_WtoA(lpszParam
):NULL
;
1984 ret
= FTP_SendCommandA(nSocket
, ftpCmd
, lpszParamA
, lpfnStatusCB
, hdr
, dwContext
);
1985 HeapFree(GetProcessHeap(), 0, lpszParamA
);
1989 /***********************************************************************
1990 * FTP_ReceiveResponse (internal)
1992 * Receive response from server
1995 * Reply code on success
1999 INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD dwContext
)
2001 LPSTR lpszResponse
= INTERNET_GetResponseBuffer();
2004 char firstprefix
[5];
2005 BOOL multiline
= FALSE
;
2006 LPWININETAPPINFOW hIC
= NULL
;
2008 TRACE("socket(%d)\n", lpwfs
->sndSocket
);
2010 hIC
= lpwfs
->lpAppInfo
;
2011 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
2015 if (!INTERNET_GetNextLine(lpwfs
->sndSocket
, &nRecv
))
2022 if(lpszResponse
[3] != '-')
2025 { /* Start of multiline repsonse. Loop until we get "nnn " */
2027 memcpy(firstprefix
, lpszResponse
, 3);
2028 firstprefix
[3] = ' ';
2029 firstprefix
[4] = '\0';
2034 if(!memcmp(firstprefix
, lpszResponse
, 4))
2042 rc
= atoi(lpszResponse
);
2044 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
2045 &nRecv
, sizeof(DWORD
));
2049 TRACE("return %d\n", rc
);
2054 /***********************************************************************
2055 * FTP_SendPassword (internal)
2057 * Send password to ftp server
2064 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
)
2067 BOOL bSuccess
= FALSE
;
2070 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
2073 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2076 TRACE("Received reply code %d\n", nResCode
);
2077 /* Login successful... */
2078 if (nResCode
== 230)
2080 /* Command not implemented, superfluous at the server site... */
2081 /* Need account for login... */
2082 else if (nResCode
== 332)
2083 bSuccess
= FTP_SendAccount(lpwfs
);
2085 FTP_SetResponseError(nResCode
);
2089 TRACE("Returning %d\n", bSuccess
);
2094 /***********************************************************************
2095 * FTP_SendAccount (internal)
2104 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
)
2107 BOOL bSuccess
= FALSE
;
2110 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, szNoAccount
, 0, 0, 0))
2113 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2117 FTP_SetResponseError(nResCode
);
2124 /***********************************************************************
2125 * FTP_SendStore (internal)
2127 * Send request to upload file to ftp server
2134 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2137 BOOL bSuccess
= FALSE
;
2140 if (!FTP_InitListenSocket(lpwfs
))
2143 if (!FTP_SendType(lpwfs
, dwType
))
2146 if (!FTP_SendPortOrPasv(lpwfs
))
2149 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
2151 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2154 if (nResCode
== 150 || nResCode
== 125)
2157 FTP_SetResponseError(nResCode
);
2161 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
2163 closesocket(lpwfs
->lstnSocket
);
2164 lpwfs
->lstnSocket
= -1;
2171 /***********************************************************************
2172 * FTP_InitListenSocket (internal)
2174 * Create a socket to listen for server response
2181 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
)
2183 BOOL bSuccess
= FALSE
;
2184 size_t namelen
= sizeof(struct sockaddr_in
);
2188 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
2189 if (lpwfs
->lstnSocket
== -1)
2191 TRACE("Unable to create listening socket\n");
2195 /* We obtain our ip addr from the name of the command channel socket */
2196 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
2198 /* and get the system to assign us a port */
2199 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
2201 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
2203 TRACE("Unable to bind socket\n");
2207 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
2209 TRACE("listen failed\n");
2213 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
2217 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
2219 closesocket(lpwfs
->lstnSocket
);
2220 lpwfs
->lstnSocket
= -1;
2227 /***********************************************************************
2228 * FTP_SendType (internal)
2230 * Tell server type of data being transferred
2236 * W98SE doesn't cache the type that's currently set
2237 * (i.e. it sends it always),
2238 * so we probably don't want to do that either.
2240 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
)
2243 WCHAR type
[] = { 'I','\0' };
2244 BOOL bSuccess
= FALSE
;
2247 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
2250 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
2253 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
)/100;
2259 FTP_SetResponseError(nResCode
);
2266 /***********************************************************************
2267 * FTP_GetFileSize (internal)
2269 * Retrieves from the server the size of the given file
2276 static BOOL
FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD
*dwSize
)
2279 BOOL bSuccess
= FALSE
;
2283 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
2286 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2289 if (nResCode
== 213) {
2290 /* Now parses the output to get the actual file size */
2292 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2294 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
2295 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
2296 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2300 FTP_SetResponseError(nResCode
);
2309 /***********************************************************************
2310 * FTP_SendPort (internal)
2312 * Tell server which port to use
2319 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
)
2321 static const WCHAR szIPFormat
[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2323 WCHAR szIPAddress
[64];
2324 BOOL bSuccess
= FALSE
;
2327 sprintfW(szIPAddress
, szIPFormat
,
2328 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2329 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2330 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2331 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2332 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2333 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2335 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2338 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2341 if (nResCode
== 200)
2344 FTP_SetResponseError(nResCode
);
2352 /***********************************************************************
2353 * FTP_DoPassive (internal)
2355 * Tell server that we want to do passive transfers
2356 * and connect data socket
2363 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
)
2366 BOOL bSuccess
= FALSE
;
2369 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2372 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2375 if (nResCode
== 227)
2377 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2381 char *pAddr
, *pPort
;
2383 struct sockaddr_in dataSocketAddress
;
2385 p
= lpszResponseBuffer
+4; /* skip status code */
2387 /* do a very strict check; we can improve that later. */
2389 if (strncmp(p
, "Entering Passive Mode", 21))
2391 ERR("unknown response '%.*s', aborting\n", 21, p
);
2394 p
+= 21; /* skip string */
2395 if ((*p
++ != ' ') || (*p
++ != '('))
2397 ERR("unknown response format, aborting\n");
2401 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2404 ERR("unknown response address format '%s', aborting\n", p
);
2407 for (i
=0; i
< 6; i
++)
2410 dataSocketAddress
= lpwfs
->socketAddress
;
2411 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2412 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2420 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2424 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2426 ERR("can't connect passive FTP data port.\n");
2427 closesocket(nsocket
);
2430 lpwfs
->pasvSocket
= nsocket
;
2434 FTP_SetResponseError(nResCode
);
2442 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
)
2444 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2446 if (!FTP_DoPassive(lpwfs
))
2451 if (!FTP_SendPort(lpwfs
))
2458 /***********************************************************************
2459 * FTP_GetDataSocket (internal)
2461 * Either accepts an incoming data socket connection from the server
2462 * or just returns the already opened socket after a PASV command
2463 * in case of passive FTP.
2471 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
)
2473 struct sockaddr_in saddr
;
2474 size_t addrlen
= sizeof(struct sockaddr
);
2477 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2479 *nDataSocket
= lpwfs
->pasvSocket
;
2483 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2484 closesocket(lpwfs
->lstnSocket
);
2485 lpwfs
->lstnSocket
= -1;
2487 return *nDataSocket
!= -1;
2491 /***********************************************************************
2492 * FTP_SendData (internal)
2494 * Send data to the server
2501 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
)
2503 BY_HANDLE_FILE_INFORMATION fi
;
2504 DWORD nBytesRead
= 0;
2505 DWORD nBytesSent
= 0;
2506 DWORD nTotalSent
= 0;
2507 DWORD nBytesToSend
, nLen
;
2509 time_t s_long_time
, e_long_time
;
2514 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2515 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2517 /* Get the size of the file. */
2518 GetFileInformationByHandle(hFile
, &fi
);
2523 nBytesToSend
= nBytesRead
- nBytesSent
;
2525 if (nBytesToSend
<= 0)
2527 /* Read data from file. */
2529 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2530 ERR("Failed reading from file\n");
2533 nBytesToSend
= nBytesRead
;
2538 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2539 DATA_PACKET_SIZE
: nBytesToSend
;
2540 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2548 /* Do some computation to display the status. */
2550 nSeconds
= e_long_time
- s_long_time
;
2551 if( nSeconds
/ 60 > 0 )
2553 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2554 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2555 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2559 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2560 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2561 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2563 } while (nRC
!= -1);
2565 TRACE("file transfer complete!\n");
2567 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2573 /***********************************************************************
2574 * FTP_SendRetrieve (internal)
2576 * Send request to retrieve a file
2579 * Number of bytes to be received on success
2583 static DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2589 if (!FTP_InitListenSocket(lpwfs
))
2592 if (!FTP_SendType(lpwfs
, dwType
))
2595 if (!FTP_SendPortOrPasv(lpwfs
))
2598 if (!FTP_GetFileSize(lpwfs
, lpszRemoteFile
, &nResult
))
2601 TRACE("Waiting to receive %d bytes\n", nResult
);
2603 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2606 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2607 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2608 /* That means that we got an error getting the file. */
2613 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2615 closesocket(lpwfs
->lstnSocket
);
2616 lpwfs
->lstnSocket
= -1;
2623 /***********************************************************************
2624 * FTP_RetrieveData (internal)
2626 * Retrieve data from server
2633 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2635 DWORD nBytesWritten
;
2636 DWORD nBytesReceived
= 0;
2642 if (INVALID_HANDLE_VALUE
== hFile
)
2645 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2646 if (NULL
== lpszBuffer
)
2648 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2652 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2654 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2657 /* other side closed socket. */
2660 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2661 nBytesReceived
+= nRC
;
2664 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived
, nBytes
,
2665 nBytesReceived
* 100 / nBytes
);
2668 TRACE("Data transfer complete\n");
2669 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2676 /***********************************************************************
2677 * FTP_CloseSessionHandle (internal)
2679 * Deallocate session handle
2686 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
)
2688 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) hdr
;
2692 INTERNET_SendCallback(hdr
, hdr
->dwContext
,
2693 INTERNET_STATUS_HANDLE_CLOSING
, &hdr
->hInternet
,
2696 WININET_Release(&lpwfs
->lpAppInfo
->hdr
);
2698 if (lpwfs
->download_in_progress
!= NULL
)
2699 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2701 if (lpwfs
->sndSocket
!= -1)
2702 closesocket(lpwfs
->sndSocket
);
2704 if (lpwfs
->lstnSocket
!= -1)
2705 closesocket(lpwfs
->lstnSocket
);
2707 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2708 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2709 HeapFree(GetProcessHeap(), 0, lpwfs
);
2713 /***********************************************************************
2714 * FTP_FindNextFileW (Internal)
2716 * Continues a file search from a previous call to FindFirstFile
2723 BOOL WINAPI
FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh
, LPVOID lpvFindData
)
2725 BOOL bSuccess
= TRUE
;
2726 LPWIN32_FIND_DATAW lpFindFileData
;
2728 TRACE("index(%d) size(%d)\n", lpwh
->index
, lpwh
->size
);
2730 assert (lpwh
->hdr
.htype
== WH_HFTPFINDNEXT
);
2732 /* Clear any error information */
2733 INTERNET_SetLastError(0);
2735 lpFindFileData
= (LPWIN32_FIND_DATAW
) lpvFindData
;
2736 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2738 if (lpwh
->index
>= lpwh
->size
)
2740 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2745 FTP_ConvertFileProp(&lpwh
->lpafp
[lpwh
->index
], lpFindFileData
);
2748 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData
->cFileName
), lpFindFileData
->nFileSizeLow
);
2752 if (lpwh
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
2754 INTERNET_ASYNC_RESULT iar
;
2756 iar
.dwResult
= (DWORD
)bSuccess
;
2757 iar
.dwError
= iar
.dwError
= bSuccess
? ERROR_SUCCESS
:
2758 INTERNET_GetLastError();
2760 INTERNET_SendCallback(&lpwh
->hdr
, lpwh
->hdr
.dwContext
,
2761 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
2762 sizeof(INTERNET_ASYNC_RESULT
));
2769 /***********************************************************************
2770 * FTP_CloseFindNextHandle (internal)
2772 * Deallocate session handle
2779 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
)
2781 LPWININETFTPFINDNEXTW lpwfn
= (LPWININETFTPFINDNEXTW
) hdr
;
2786 INTERNET_SendCallback(hdr
, hdr
->dwContext
,
2787 INTERNET_STATUS_HANDLE_CLOSING
, &hdr
->hInternet
,
2790 WININET_Release(&lpwfn
->lpFtpSession
->hdr
);
2792 for (i
= 0; i
< lpwfn
->size
; i
++)
2794 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2797 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2798 HeapFree(GetProcessHeap(), 0, lpwfn
);
2801 /***********************************************************************
2802 * FTP_CloseFileTransferHandle (internal)
2804 * Closes the file transfer handle. This also 'cleans' the data queue of
2805 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2808 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
)
2810 LPWININETFTPFILE lpwh
= (LPWININETFTPFILE
) hdr
;
2811 LPWININETFTPSESSIONW lpwfs
= lpwh
->lpFtpSession
;
2816 INTERNET_SendCallback(hdr
, hdr
->dwContext
,
2817 INTERNET_STATUS_HANDLE_CLOSING
, &hdr
->hInternet
,
2820 WININET_Release(&lpwh
->lpFtpSession
->hdr
);
2822 if (!lpwh
->session_deleted
)
2823 lpwfs
->download_in_progress
= NULL
;
2825 /* This just serves to flush the control socket of any spurrious lines written
2826 to it (like '226 Transfer complete.').
2828 Wonder what to do if the server sends us an error code though...
2830 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2832 if (lpwh
->nDataSocket
!= -1)
2833 closesocket(lpwh
->nDataSocket
);
2835 HeapFree(GetProcessHeap(), 0, lpwh
);
2838 /***********************************************************************
2839 * FTP_ReceiveFileList (internal)
2841 * Read file list from server
2844 * Handle to file list on success
2848 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
2849 LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwContext
)
2852 LPFILEPROPERTIESW lpafp
= NULL
;
2853 LPWININETFTPFINDNEXTW lpwfn
= NULL
;
2854 HINTERNET handle
= 0;
2856 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs
, nSocket
, debugstr_w(lpszSearchFile
), lpFindFileData
, dwContext
);
2858 if (FTP_ParseDirectory(lpwfs
, nSocket
, lpszSearchFile
, &lpafp
, &dwSize
))
2861 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2863 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFTPFINDNEXTW
));
2866 lpwfn
->hdr
.htype
= WH_HFTPFINDNEXT
;
2867 lpwfn
->hdr
.dwContext
= dwContext
;
2868 lpwfn
->hdr
.dwRefCount
= 1;
2869 lpwfn
->hdr
.destroy
= FTP_CloseFindNextHandle
;
2870 lpwfn
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
2871 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2872 lpwfn
->size
= dwSize
;
2873 lpwfn
->lpafp
= lpafp
;
2875 WININET_AddRef( &lpwfs
->hdr
);
2876 lpwfn
->lpFtpSession
= lpwfs
;
2878 handle
= WININET_AllocHandle( &lpwfn
->hdr
);
2883 WININET_Release( &lpwfn
->hdr
);
2885 TRACE("Matched %d files\n", dwSize
);
2890 /***********************************************************************
2891 * FTP_ConvertFileProp (internal)
2893 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2900 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp
, LPWIN32_FIND_DATAW lpFindFileData
)
2902 BOOL bSuccess
= FALSE
;
2904 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAW
));
2908 /* Convert 'Unix' time to Windows time */
2909 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
2910 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
2911 lpFindFileData
->ftLastWriteTime
= lpFindFileData
->ftLastAccessTime
;
2912 lpFindFileData
->ftCreationTime
= lpFindFileData
->ftLastAccessTime
;
2914 /* Not all fields are filled in */
2915 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2916 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
2918 if (lpafp
->bIsDirectory
)
2919 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2921 if (lpafp
->lpszName
)
2922 lstrcpynW(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2930 /***********************************************************************
2931 * FTP_ParseNextFile (internal)
2933 * Parse the next line in file listing
2939 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW lpfp
)
2941 static const char szSpace
[] = " \t";
2949 lpfp
->lpszName
= NULL
;
2951 if(!(pszLine
= INTERNET_GetNextLine(nSocket
, &nBufLen
)))
2954 pszToken
= strtok(pszLine
, szSpace
);
2956 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2959 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2961 if(!isdigit(pszToken
[0]) && 10 == strlen(pszToken
)) {
2962 if(!FTP_ParsePermission(pszToken
, lpfp
))
2963 lpfp
->bIsDirectory
= FALSE
;
2964 for(i
=0; i
<=3; i
++) {
2965 if(!(pszToken
= strtok(NULL
, szSpace
)))
2968 if(!pszToken
) continue;
2969 if(lpfp
->bIsDirectory
) {
2970 TRACE("Is directory\n");
2974 TRACE("Size: %s\n", pszToken
);
2975 lpfp
->nSize
= atol(pszToken
);
2978 lpfp
->tmLastModified
.tm_sec
= 0;
2979 lpfp
->tmLastModified
.tm_min
= 0;
2980 lpfp
->tmLastModified
.tm_hour
= 0;
2981 lpfp
->tmLastModified
.tm_mday
= 0;
2982 lpfp
->tmLastModified
.tm_mon
= 0;
2983 lpfp
->tmLastModified
.tm_year
= 0;
2985 /* Determine month */
2986 pszToken
= strtok(NULL
, szSpace
);
2987 if(!pszToken
) continue;
2988 if(strlen(pszToken
) >= 3) {
2990 if((pszTmp
= StrStrIA(szMonths
, pszToken
)))
2991 lpfp
->tmLastModified
.tm_mon
= ((pszTmp
- szMonths
) / 3)+1;
2994 pszToken
= strtok(NULL
, szSpace
);
2995 if(!pszToken
) continue;
2996 lpfp
->tmLastModified
.tm_mday
= atoi(pszToken
);
2997 /* Determine time or year */
2998 pszToken
= strtok(NULL
, szSpace
);
2999 if(!pszToken
) continue;
3000 if((pszTmp
= strchr(pszToken
, ':'))) {
3005 lpfp
->tmLastModified
.tm_min
= atoi(pszTmp
);
3006 lpfp
->tmLastModified
.tm_hour
= atoi(pszToken
);
3008 apTM
= localtime(&aTime
);
3009 lpfp
->tmLastModified
.tm_year
= apTM
->tm_year
;
3012 lpfp
->tmLastModified
.tm_year
= atoi(pszToken
) - 1900;
3013 lpfp
->tmLastModified
.tm_hour
= 12;
3015 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3016 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3017 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3018 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3020 pszToken
= strtok(NULL
, szSpace
);
3021 if(!pszToken
) continue;
3022 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3023 TRACE("File: %s\n", debugstr_w(lpfp
->lpszName
));
3025 /* NT way of parsing ... :
3027 07-13-03 08:55PM <DIR> sakpatch
3028 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3030 else if(isdigit(pszToken
[0]) && 8 == strlen(pszToken
)) {
3031 lpfp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
3033 sscanf(pszToken
, "%d-%d-%d",
3034 &lpfp
->tmLastModified
.tm_mon
,
3035 &lpfp
->tmLastModified
.tm_mday
,
3036 &lpfp
->tmLastModified
.tm_year
);
3038 /* Hacky and bad Y2K protection :-) */
3039 if (lpfp
->tmLastModified
.tm_year
< 70)
3040 lpfp
->tmLastModified
.tm_year
+= 100;
3042 pszToken
= strtok(NULL
, szSpace
);
3043 if(!pszToken
) continue;
3044 sscanf(pszToken
, "%d:%d",
3045 &lpfp
->tmLastModified
.tm_hour
,
3046 &lpfp
->tmLastModified
.tm_min
);
3047 if((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
3048 lpfp
->tmLastModified
.tm_hour
+= 12;
3050 lpfp
->tmLastModified
.tm_sec
= 0;
3052 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3053 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3054 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3055 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3057 pszToken
= strtok(NULL
, szSpace
);
3058 if(!pszToken
) continue;
3059 if(!strcasecmp(pszToken
, "<DIR>")) {
3060 lpfp
->bIsDirectory
= TRUE
;
3062 TRACE("Is directory\n");
3065 lpfp
->bIsDirectory
= FALSE
;
3066 lpfp
->nSize
= atol(pszToken
);
3067 TRACE("Size: %d\n", lpfp
->nSize
);
3070 pszToken
= strtok(NULL
, szSpace
);
3071 if(!pszToken
) continue;
3072 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3073 TRACE("Name: %s\n", debugstr_w(lpfp
->lpszName
));
3075 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3076 else if(pszToken
[0] == '+') {
3077 FIXME("EPLF Format not implemented\n");
3080 if(lpfp
->lpszName
) {
3081 if((lpszSearchFile
== NULL
) ||
3082 (PathMatchSpecW(lpfp
->lpszName
, lpszSearchFile
))) {
3084 TRACE("Matched: %s\n", debugstr_w(lpfp
->lpszName
));
3087 HeapFree(GetProcessHeap(), 0, lpfp
->lpszName
);
3088 lpfp
->lpszName
= NULL
;
3095 /***********************************************************************
3096 * FTP_ParseDirectory (internal)
3098 * Parse string of directory information
3104 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
3105 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
)
3107 BOOL bSuccess
= TRUE
;
3108 INT sizeFilePropArray
= 500;/*20; */
3109 INT indexFilePropArray
= -1;
3113 /* Allocate intial file properties array */
3114 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESW
)*(sizeFilePropArray
));
3119 if (indexFilePropArray
+1 >= sizeFilePropArray
)
3121 LPFILEPROPERTIESW tmpafp
;
3123 sizeFilePropArray
*= 2;
3124 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
3125 sizeof(FILEPROPERTIESW
)*sizeFilePropArray
);
3134 indexFilePropArray
++;
3135 } while (FTP_ParseNextFile(nSocket
, lpszSearchFile
, &(*lpafp
)[indexFilePropArray
]));
3137 if (bSuccess
&& indexFilePropArray
)
3139 if (indexFilePropArray
< sizeFilePropArray
- 1)
3141 LPFILEPROPERTIESW tmpafp
;
3143 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
3144 sizeof(FILEPROPERTIESW
)*indexFilePropArray
);
3148 *dwfp
= indexFilePropArray
;
3152 HeapFree(GetProcessHeap(), 0, *lpafp
);
3153 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
3161 /***********************************************************************
3162 * FTP_ParsePermission (internal)
3164 * Parse permission string of directory information
3171 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
)
3173 BOOL bSuccess
= TRUE
;
3174 unsigned short nPermission
= 0;
3179 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
3185 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
3191 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
3194 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
3197 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
3200 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
3203 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
3206 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
3209 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
3212 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
3215 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
3219 }while (nPos
<= nLast
);
3221 lpfp
->permissions
= nPermission
;
3226 /***********************************************************************
3227 * FTP_SetResponseError (internal)
3229 * Set the appropriate error code for a given response from the server
3234 static DWORD
FTP_SetResponseError(DWORD dwResponse
)
3240 case 421: /* Service not available - Server may be shutting down. */
3241 dwCode
= ERROR_INTERNET_TIMEOUT
;
3244 case 425: /* Cannot open data connection. */
3245 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
3248 case 426: /* Connection closed, transer aborted. */
3249 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
3252 case 500: /* Syntax error. Command unrecognized. */
3253 case 501: /* Syntax error. Error in parameters or arguments. */
3254 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
3257 case 530: /* Not logged in. Login incorrect. */
3258 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
3261 case 550: /* File action not taken. File not found or no access. */
3262 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
3265 case 450: /* File action not taken. File may be busy. */
3266 case 451: /* Action aborted. Server error. */
3267 case 452: /* Action not taken. Insufficient storage space on server. */
3268 case 502: /* Command not implemented. */
3269 case 503: /* Bad sequence of command. */
3270 case 504: /* Command not implemented for that parameter. */
3271 case 532: /* Need account for storing files */
3272 case 551: /* Requested action aborted. Page type unknown */
3273 case 552: /* Action aborted. Exceeded storage allocation */
3274 case 553: /* Action not taken. File name not allowed. */
3277 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
3281 INTERNET_SetLastError(dwCode
);