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
67 /* Testing shows that Windows only accepts dwFlags where the last
68 * 3 (yes 3) bits define FTP_TRANSFER_TYPE_UNKNOWN, FTP_TRANSFER_TYPE_ASCII or FTP_TRANSFER_TYPE_BINARY.
70 #define FTP_CONDITION_MASK 0x0007
73 /* FTP commands with arguments. */
89 /* FTP commands without arguments. */
98 static const CHAR
*const szFtpCommands
[] = {
121 static const CHAR szMonths
[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
122 static const WCHAR szNoAccount
[] = {'n','o','a','c','c','o','u','n','t','\0'};
124 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
);
125 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
);
126 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
);
127 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
128 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD_PTR dwContext
);
129 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
);
130 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
);
131 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
);
132 static INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD_PTR dwContext
);
133 static BOOL
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
);
134 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
);
135 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
);
136 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
);
137 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
);
138 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
);
139 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
);
140 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
);
141 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
);
142 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
);
143 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
);
144 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW fileprop
);
145 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
146 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
);
147 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
148 LPWIN32_FIND_DATAW lpFindFileData
, DWORD_PTR dwContext
);
149 static DWORD
FTP_SetResponseError(DWORD dwResponse
);
151 /***********************************************************************
152 * FtpPutFileA (WININET.@)
154 * Uploads a file to the FTP server
161 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
162 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD_PTR dwContext
)
164 LPWSTR lpwzLocalFile
;
165 LPWSTR lpwzNewRemoteFile
;
168 lpwzLocalFile
= lpszLocalFile
?WININET_strdup_AtoW(lpszLocalFile
):NULL
;
169 lpwzNewRemoteFile
= lpszNewRemoteFile
?WININET_strdup_AtoW(lpszNewRemoteFile
):NULL
;
170 ret
= FtpPutFileW(hConnect
, lpwzLocalFile
, lpwzNewRemoteFile
,
172 HeapFree(GetProcessHeap(), 0, lpwzLocalFile
);
173 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile
);
177 static void AsyncFtpPutFileProc(WORKREQUEST
*workRequest
)
179 struct WORKREQ_FTPPUTFILEW
const *req
= &workRequest
->u
.FtpPutFileW
;
180 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
182 TRACE("%p\n", lpwfs
);
184 FTP_FtpPutFileW(lpwfs
, req
->lpszLocalFile
,
185 req
->lpszNewRemoteFile
, req
->dwFlags
, req
->dwContext
);
187 HeapFree(GetProcessHeap(), 0, req
->lpszLocalFile
);
188 HeapFree(GetProcessHeap(), 0, req
->lpszNewRemoteFile
);
191 /***********************************************************************
192 * FtpPutFileW (WININET.@)
194 * Uploads a file to the FTP server
201 BOOL WINAPI
FtpPutFileW(HINTERNET hConnect
, LPCWSTR lpszLocalFile
,
202 LPCWSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD_PTR dwContext
)
204 LPWININETFTPSESSIONW lpwfs
;
205 LPWININETAPPINFOW hIC
= NULL
;
208 if (!lpszLocalFile
|| !lpszNewRemoteFile
)
210 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
214 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
217 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
221 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
223 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
227 if ((dwFlags
& FTP_CONDITION_MASK
) > FTP_TRANSFER_TYPE_BINARY
)
229 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
233 hIC
= lpwfs
->lpAppInfo
;
234 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
236 WORKREQUEST workRequest
;
237 struct WORKREQ_FTPPUTFILEW
*req
= &workRequest
.u
.FtpPutFileW
;
239 workRequest
.asyncproc
= AsyncFtpPutFileProc
;
240 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
241 req
->lpszLocalFile
= WININET_strdupW(lpszLocalFile
);
242 req
->lpszNewRemoteFile
= WININET_strdupW(lpszNewRemoteFile
);
243 req
->dwFlags
= dwFlags
;
244 req
->dwContext
= dwContext
;
246 r
= INTERNET_AsyncCall(&workRequest
);
250 r
= FTP_FtpPutFileW(lpwfs
, lpszLocalFile
,
251 lpszNewRemoteFile
, dwFlags
, dwContext
);
255 WININET_Release( &lpwfs
->hdr
);
260 /***********************************************************************
261 * FTP_FtpPutFileW (Internal)
263 * Uploads a file to the FTP server
270 BOOL WINAPI
FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszLocalFile
,
271 LPCWSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD_PTR dwContext
)
274 BOOL bSuccess
= FALSE
;
275 LPWININETAPPINFOW hIC
= NULL
;
278 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile
), debugstr_w(lpszNewRemoteFile
));
280 /* Clear any error information */
281 INTERNET_SetLastError(0);
283 /* Open file to be uploaded */
284 if (INVALID_HANDLE_VALUE
==
285 (hFile
= CreateFileW(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
286 /* Let CreateFile set the appropriate error */
289 hIC
= lpwfs
->lpAppInfo
;
291 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
293 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
297 /* Get data socket to server */
298 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
300 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
301 closesocket(nDataSocket
);
302 nResCode
= FTP_ReceiveResponse(lpwfs
, dwContext
);
308 FTP_SetResponseError(nResCode
);
313 if (lpwfs
->lstnSocket
!= -1)
314 closesocket(lpwfs
->lstnSocket
);
316 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
318 INTERNET_ASYNC_RESULT iar
;
320 iar
.dwResult
= (DWORD
)bSuccess
;
321 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
322 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
323 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
332 /***********************************************************************
333 * FtpSetCurrentDirectoryA (WININET.@)
335 * Change the working directory on the FTP server
342 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
344 LPWSTR lpwzDirectory
;
347 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
348 ret
= FtpSetCurrentDirectoryW(hConnect
, lpwzDirectory
);
349 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
354 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST
*workRequest
)
356 struct WORKREQ_FTPSETCURRENTDIRECTORYW
const *req
= &workRequest
->u
.FtpSetCurrentDirectoryW
;
357 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
359 TRACE("%p\n", lpwfs
);
361 FTP_FtpSetCurrentDirectoryW(lpwfs
, req
->lpszDirectory
);
362 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
365 /***********************************************************************
366 * FtpSetCurrentDirectoryW (WININET.@)
368 * Change the working directory on the FTP server
375 BOOL WINAPI
FtpSetCurrentDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
377 LPWININETFTPSESSIONW lpwfs
= NULL
;
378 LPWININETAPPINFOW hIC
= NULL
;
383 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
387 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
388 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
390 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
394 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
396 hIC
= lpwfs
->lpAppInfo
;
397 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
399 WORKREQUEST workRequest
;
400 struct WORKREQ_FTPSETCURRENTDIRECTORYW
*req
;
402 workRequest
.asyncproc
= AsyncFtpSetCurrentDirectoryProc
;
403 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
404 req
= &workRequest
.u
.FtpSetCurrentDirectoryW
;
405 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
407 r
= INTERNET_AsyncCall(&workRequest
);
411 r
= FTP_FtpSetCurrentDirectoryW(lpwfs
, lpszDirectory
);
416 WININET_Release( &lpwfs
->hdr
);
422 /***********************************************************************
423 * FTP_FtpSetCurrentDirectoryW (Internal)
425 * Change the working directory on the FTP server
432 BOOL WINAPI
FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
435 LPWININETAPPINFOW hIC
= NULL
;
436 DWORD bSuccess
= FALSE
;
438 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
440 /* Clear any error information */
441 INTERNET_SetLastError(0);
443 hIC
= lpwfs
->lpAppInfo
;
444 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
445 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
448 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
455 FTP_SetResponseError(nResCode
);
459 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
461 INTERNET_ASYNC_RESULT iar
;
463 iar
.dwResult
= (DWORD
)bSuccess
;
464 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
465 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
466 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
472 /***********************************************************************
473 * FtpCreateDirectoryA (WININET.@)
475 * Create new directory on the FTP server
482 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
484 LPWSTR lpwzDirectory
;
487 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
488 ret
= FtpCreateDirectoryW(hConnect
, lpwzDirectory
);
489 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
494 static void AsyncFtpCreateDirectoryProc(WORKREQUEST
*workRequest
)
496 struct WORKREQ_FTPCREATEDIRECTORYW
const *req
= &workRequest
->u
.FtpCreateDirectoryW
;
497 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
499 TRACE(" %p\n", lpwfs
);
501 FTP_FtpCreateDirectoryW(lpwfs
, req
->lpszDirectory
);
502 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
505 /***********************************************************************
506 * FtpCreateDirectoryW (WININET.@)
508 * Create new directory on the FTP server
515 BOOL WINAPI
FtpCreateDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
517 LPWININETFTPSESSIONW lpwfs
;
518 LPWININETAPPINFOW hIC
= NULL
;
521 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
524 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
528 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
530 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
536 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
540 hIC
= lpwfs
->lpAppInfo
;
541 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
543 WORKREQUEST workRequest
;
544 struct WORKREQ_FTPCREATEDIRECTORYW
*req
;
546 workRequest
.asyncproc
= AsyncFtpCreateDirectoryProc
;
547 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
548 req
= &workRequest
.u
.FtpCreateDirectoryW
;
549 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
551 r
= INTERNET_AsyncCall(&workRequest
);
555 r
= FTP_FtpCreateDirectoryW(lpwfs
, lpszDirectory
);
558 WININET_Release( &lpwfs
->hdr
);
564 /***********************************************************************
565 * FTP_FtpCreateDirectoryW (Internal)
567 * Create new directory on the FTP server
574 BOOL WINAPI
FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
577 BOOL bSuccess
= FALSE
;
578 LPWININETAPPINFOW hIC
= NULL
;
580 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
582 /* Clear any error information */
583 INTERNET_SetLastError(0);
585 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
588 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
594 FTP_SetResponseError(nResCode
);
598 hIC
= lpwfs
->lpAppInfo
;
599 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
601 INTERNET_ASYNC_RESULT iar
;
603 iar
.dwResult
= (DWORD
)bSuccess
;
604 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
605 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
606 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
612 /***********************************************************************
613 * FtpFindFirstFileA (WININET.@)
615 * Search the specified directory
618 * HINTERNET on success
622 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
623 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD_PTR dwContext
)
625 LPWSTR lpwzSearchFile
;
626 WIN32_FIND_DATAW wfd
;
627 LPWIN32_FIND_DATAW lpFindFileDataW
;
630 lpwzSearchFile
= lpszSearchFile
?WININET_strdup_AtoW(lpszSearchFile
):NULL
;
631 lpFindFileDataW
= lpFindFileData
?&wfd
:NULL
;
632 ret
= FtpFindFirstFileW(hConnect
, lpwzSearchFile
, lpFindFileDataW
, dwFlags
, dwContext
);
633 HeapFree(GetProcessHeap(), 0, lpwzSearchFile
);
636 WININET_find_data_WtoA(lpFindFileDataW
, lpFindFileData
);
642 static void AsyncFtpFindFirstFileProc(WORKREQUEST
*workRequest
)
644 struct WORKREQ_FTPFINDFIRSTFILEW
const *req
= &workRequest
->u
.FtpFindFirstFileW
;
645 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
647 TRACE("%p\n", lpwfs
);
649 FTP_FtpFindFirstFileW(lpwfs
, req
->lpszSearchFile
,
650 req
->lpFindFileData
, req
->dwFlags
, req
->dwContext
);
651 HeapFree(GetProcessHeap(), 0, req
->lpszSearchFile
);
654 /***********************************************************************
655 * FtpFindFirstFileW (WININET.@)
657 * Search the specified directory
660 * HINTERNET on success
664 HINTERNET WINAPI
FtpFindFirstFileW(HINTERNET hConnect
,
665 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD_PTR dwContext
)
667 LPWININETFTPSESSIONW lpwfs
;
668 LPWININETAPPINFOW hIC
= NULL
;
671 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
672 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
674 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
678 hIC
= lpwfs
->lpAppInfo
;
679 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
681 WORKREQUEST workRequest
;
682 struct WORKREQ_FTPFINDFIRSTFILEW
*req
;
684 workRequest
.asyncproc
= AsyncFtpFindFirstFileProc
;
685 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
686 req
= &workRequest
.u
.FtpFindFirstFileW
;
687 req
->lpszSearchFile
= (lpszSearchFile
== NULL
) ? NULL
: WININET_strdupW(lpszSearchFile
);
688 req
->lpFindFileData
= lpFindFileData
;
689 req
->dwFlags
= dwFlags
;
690 req
->dwContext
= dwContext
;
692 INTERNET_AsyncCall(&workRequest
);
697 r
= FTP_FtpFindFirstFileW(lpwfs
, lpszSearchFile
, lpFindFileData
,
702 WININET_Release( &lpwfs
->hdr
);
708 /***********************************************************************
709 * FTP_FtpFindFirstFileW (Internal)
711 * Search the specified directory
714 * HINTERNET on success
718 HINTERNET WINAPI
FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs
,
719 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD_PTR dwContext
)
722 LPWININETAPPINFOW hIC
= NULL
;
723 HINTERNET hFindNext
= NULL
;
727 /* Clear any error information */
728 INTERNET_SetLastError(0);
730 if (!FTP_InitListenSocket(lpwfs
))
733 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
736 if (!FTP_SendPortOrPasv(lpwfs
))
739 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, NULL
,
740 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
743 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
746 if (nResCode
== 125 || nResCode
== 150)
750 /* Get data socket to server */
751 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
753 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpszSearchFile
, lpFindFileData
, dwContext
);
754 closesocket(nDataSocket
);
755 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
756 if (nResCode
!= 226 && nResCode
!= 250)
757 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
761 FTP_SetResponseError(nResCode
);
765 if (lpwfs
->lstnSocket
!= -1)
766 closesocket(lpwfs
->lstnSocket
);
768 hIC
= lpwfs
->lpAppInfo
;
769 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
771 INTERNET_ASYNC_RESULT iar
;
775 iar
.dwResult
= (DWORD
)hFindNext
;
776 iar
.dwError
= ERROR_SUCCESS
;
777 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
778 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
781 iar
.dwResult
= (DWORD
)hFindNext
;
782 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
783 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
784 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
791 /***********************************************************************
792 * FtpGetCurrentDirectoryA (WININET.@)
794 * Retrieves the current directory
801 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
802 LPDWORD lpdwCurrentDirectory
)
808 if(lpdwCurrentDirectory
) {
809 len
= *lpdwCurrentDirectory
;
810 if(lpszCurrentDirectory
)
812 dir
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
815 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
820 ret
= FtpGetCurrentDirectoryW(hFtpSession
, lpszCurrentDirectory
?dir
:NULL
, lpdwCurrentDirectory
?&len
:NULL
);
821 if(lpdwCurrentDirectory
) {
822 *lpdwCurrentDirectory
= len
;
823 if(lpszCurrentDirectory
) {
824 WideCharToMultiByte(CP_ACP
, 0, dir
, len
, lpszCurrentDirectory
, *lpdwCurrentDirectory
, NULL
, NULL
);
825 HeapFree(GetProcessHeap(), 0, dir
);
832 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST
*workRequest
)
834 struct WORKREQ_FTPGETCURRENTDIRECTORYW
const *req
= &workRequest
->u
.FtpGetCurrentDirectoryW
;
835 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
837 TRACE("%p\n", lpwfs
);
839 FTP_FtpGetCurrentDirectoryW(lpwfs
, req
->lpszDirectory
, req
->lpdwDirectory
);
842 /***********************************************************************
843 * FtpGetCurrentDirectoryW (WININET.@)
845 * Retrieves the current directory
852 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
853 LPDWORD lpdwCurrentDirectory
)
855 LPWININETFTPSESSIONW lpwfs
;
856 LPWININETAPPINFOW hIC
= NULL
;
859 TRACE("len(%d)\n", *lpdwCurrentDirectory
);
861 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
862 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
864 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
868 hIC
= lpwfs
->lpAppInfo
;
869 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
871 WORKREQUEST workRequest
;
872 struct WORKREQ_FTPGETCURRENTDIRECTORYW
*req
;
874 workRequest
.asyncproc
= AsyncFtpGetCurrentDirectoryProc
;
875 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
876 req
= &workRequest
.u
.FtpGetCurrentDirectoryW
;
877 req
->lpszDirectory
= lpszCurrentDirectory
;
878 req
->lpdwDirectory
= lpdwCurrentDirectory
;
880 r
= INTERNET_AsyncCall(&workRequest
);
884 r
= FTP_FtpGetCurrentDirectoryW(lpwfs
, lpszCurrentDirectory
,
885 lpdwCurrentDirectory
);
890 WININET_Release( &lpwfs
->hdr
);
896 /***********************************************************************
897 * FTP_FtpGetCurrentDirectoryW (Internal)
899 * Retrieves the current directory
906 BOOL WINAPI
FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPWSTR lpszCurrentDirectory
,
907 LPDWORD lpdwCurrentDirectory
)
910 LPWININETAPPINFOW hIC
= NULL
;
911 DWORD bSuccess
= FALSE
;
913 TRACE("len(%d)\n", *lpdwCurrentDirectory
);
915 /* Clear any error information */
916 INTERNET_SetLastError(0);
918 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
920 hIC
= lpwfs
->lpAppInfo
;
921 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
922 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
925 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
928 if (nResCode
== 257) /* Extract directory name */
930 DWORD firstpos
, lastpos
, len
;
931 LPWSTR lpszResponseBuffer
= WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
933 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
935 if ('"' == lpszResponseBuffer
[lastpos
])
944 len
= lastpos
- firstpos
- 1;
945 lstrcpynW(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1], *lpdwCurrentDirectory
);
946 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer
);
947 *lpdwCurrentDirectory
= len
;
951 FTP_SetResponseError(nResCode
);
955 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
957 INTERNET_ASYNC_RESULT iar
;
959 iar
.dwResult
= (DWORD
)bSuccess
;
960 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
961 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
962 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
965 return (DWORD
) bSuccess
;
968 /***********************************************************************
969 * FtpOpenFileA (WININET.@)
971 * Open a remote file for writing or reading
974 * HINTERNET handle on success
978 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
979 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
985 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
986 ret
= FtpOpenFileW(hFtpSession
, lpwzFileName
, fdwAccess
, dwFlags
, dwContext
);
987 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
992 static void AsyncFtpOpenFileProc(WORKREQUEST
*workRequest
)
994 struct WORKREQ_FTPOPENFILEW
const *req
= &workRequest
->u
.FtpOpenFileW
;
995 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
997 TRACE("%p\n", lpwfs
);
999 FTP_FtpOpenFileW(lpwfs
, req
->lpszFilename
,
1000 req
->dwAccess
, req
->dwFlags
, req
->dwContext
);
1001 HeapFree(GetProcessHeap(), 0, req
->lpszFilename
);
1004 /***********************************************************************
1005 * FtpOpenFileW (WININET.@)
1007 * Open a remote file for writing or reading
1010 * HINTERNET handle on success
1014 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
1015 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
1016 DWORD_PTR dwContext
)
1018 LPWININETFTPSESSIONW lpwfs
;
1019 LPWININETAPPINFOW hIC
= NULL
;
1022 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession
,
1023 debugstr_w(lpszFileName
), fdwAccess
, dwFlags
, dwContext
);
1025 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1028 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1032 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1034 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1038 if ((!lpszFileName
) ||
1039 ((fdwAccess
!= GENERIC_READ
) && (fdwAccess
!= GENERIC_WRITE
)) ||
1040 ((dwFlags
& FTP_CONDITION_MASK
) > FTP_TRANSFER_TYPE_BINARY
))
1042 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1046 if (lpwfs
->download_in_progress
!= NULL
) {
1047 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1050 hIC
= lpwfs
->lpAppInfo
;
1051 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1053 WORKREQUEST workRequest
;
1054 struct WORKREQ_FTPOPENFILEW
*req
;
1056 workRequest
.asyncproc
= AsyncFtpOpenFileProc
;
1057 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1058 req
= &workRequest
.u
.FtpOpenFileW
;
1059 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
1060 req
->dwAccess
= fdwAccess
;
1061 req
->dwFlags
= dwFlags
;
1062 req
->dwContext
= dwContext
;
1064 INTERNET_AsyncCall(&workRequest
);
1069 r
= FTP_FtpOpenFileW(lpwfs
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
1073 WININET_Release( &lpwfs
->hdr
);
1079 /***********************************************************************
1080 * FTP_FtpOpenFileW (Internal)
1082 * Open a remote file for writing or reading
1085 * HINTERNET handle on success
1089 HINTERNET
FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs
,
1090 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
1091 DWORD_PTR dwContext
)
1094 BOOL bSuccess
= FALSE
;
1095 LPWININETFTPFILE lpwh
= NULL
;
1096 LPWININETAPPINFOW hIC
= NULL
;
1097 HINTERNET handle
= NULL
;
1101 /* Clear any error information */
1102 INTERNET_SetLastError(0);
1104 if (GENERIC_READ
== fdwAccess
)
1106 /* Set up socket to retrieve data */
1107 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
1109 else if (GENERIC_WRITE
== fdwAccess
)
1111 /* Set up socket to send data */
1112 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
1115 /* Get data socket to server */
1116 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1118 lpwh
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE
));
1119 lpwh
->hdr
.htype
= WH_HFILE
;
1120 lpwh
->hdr
.dwFlags
= dwFlags
;
1121 lpwh
->hdr
.dwContext
= dwContext
;
1122 lpwh
->hdr
.dwRefCount
= 1;
1123 lpwh
->hdr
.close_connection
= NULL
;
1124 lpwh
->hdr
.destroy
= FTP_CloseFileTransferHandle
;
1125 lpwh
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
1126 lpwh
->nDataSocket
= nDataSocket
;
1127 lpwh
->session_deleted
= FALSE
;
1129 WININET_AddRef( &lpwfs
->hdr
);
1130 lpwh
->lpFtpSession
= lpwfs
;
1131 list_add_head( &lpwfs
->hdr
.children
, &lpwh
->hdr
.entry
);
1133 handle
= WININET_AllocHandle( &lpwh
->hdr
);
1137 /* Indicate that a download is currently in progress */
1138 lpwfs
->download_in_progress
= lpwh
;
1141 if (lpwfs
->lstnSocket
!= -1)
1142 closesocket(lpwfs
->lstnSocket
);
1144 hIC
= lpwfs
->lpAppInfo
;
1145 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1147 INTERNET_ASYNC_RESULT iar
;
1151 iar
.dwResult
= (DWORD
)handle
;
1152 iar
.dwError
= ERROR_SUCCESS
;
1153 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1154 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1157 iar
.dwResult
= (DWORD
)bSuccess
;
1158 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1159 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1160 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1165 WININET_Release( &lpwh
->hdr
);
1171 /***********************************************************************
1172 * FtpGetFileA (WININET.@)
1174 * Retrieve file from the FTP server
1181 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1182 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1183 DWORD_PTR dwContext
)
1185 LPWSTR lpwzRemoteFile
;
1189 lpwzRemoteFile
= lpszRemoteFile
?WININET_strdup_AtoW(lpszRemoteFile
):NULL
;
1190 lpwzNewFile
= lpszNewFile
?WININET_strdup_AtoW(lpszNewFile
):NULL
;
1191 ret
= FtpGetFileW(hInternet
, lpwzRemoteFile
, lpwzNewFile
, fFailIfExists
,
1192 dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1193 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile
);
1194 HeapFree(GetProcessHeap(), 0, lpwzNewFile
);
1199 static void AsyncFtpGetFileProc(WORKREQUEST
*workRequest
)
1201 struct WORKREQ_FTPGETFILEW
const *req
= &workRequest
->u
.FtpGetFileW
;
1202 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1204 TRACE("%p\n", lpwfs
);
1206 FTP_FtpGetFileW(lpwfs
, req
->lpszRemoteFile
,
1207 req
->lpszNewFile
, req
->fFailIfExists
,
1208 req
->dwLocalFlagsAttribute
, req
->dwFlags
, req
->dwContext
);
1209 HeapFree(GetProcessHeap(), 0, req
->lpszRemoteFile
);
1210 HeapFree(GetProcessHeap(), 0, req
->lpszNewFile
);
1214 /***********************************************************************
1215 * FtpGetFileW (WININET.@)
1217 * Retrieve file from the FTP server
1224 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1225 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1226 DWORD_PTR dwContext
)
1228 LPWININETFTPSESSIONW lpwfs
;
1229 LPWININETAPPINFOW hIC
= NULL
;
1232 if (!lpszRemoteFile
|| !lpszNewFile
)
1234 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1238 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hInternet
);
1241 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1245 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1247 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1251 if ((dwInternetFlags
& FTP_CONDITION_MASK
) > FTP_TRANSFER_TYPE_BINARY
)
1253 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1257 if (lpwfs
->download_in_progress
!= NULL
) {
1258 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1262 hIC
= lpwfs
->lpAppInfo
;
1263 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1265 WORKREQUEST workRequest
;
1266 struct WORKREQ_FTPGETFILEW
*req
;
1268 workRequest
.asyncproc
= AsyncFtpGetFileProc
;
1269 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1270 req
= &workRequest
.u
.FtpGetFileW
;
1271 req
->lpszRemoteFile
= WININET_strdupW(lpszRemoteFile
);
1272 req
->lpszNewFile
= WININET_strdupW(lpszNewFile
);
1273 req
->dwLocalFlagsAttribute
= dwLocalFlagsAttribute
;
1274 req
->fFailIfExists
= fFailIfExists
;
1275 req
->dwFlags
= dwInternetFlags
;
1276 req
->dwContext
= dwContext
;
1278 r
= INTERNET_AsyncCall(&workRequest
);
1282 r
= FTP_FtpGetFileW(lpwfs
, lpszRemoteFile
, lpszNewFile
,
1283 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1287 WININET_Release( &lpwfs
->hdr
);
1293 /***********************************************************************
1294 * FTP_FtpGetFileW (Internal)
1296 * Retrieve file from the FTP server
1303 BOOL WINAPI
FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1304 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1305 DWORD_PTR dwContext
)
1307 BOOL bSuccess
= FALSE
;
1309 LPWININETAPPINFOW hIC
= NULL
;
1311 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile
), debugstr_w(lpszNewFile
));
1313 /* Clear any error information */
1314 INTERNET_SetLastError(0);
1316 /* Ensure we can write to lpszNewfile by opening it */
1317 hFile
= CreateFileW(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1318 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1319 if (INVALID_HANDLE_VALUE
== hFile
)
1322 /* Set up socket to retrieve data */
1323 if (FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
))
1327 /* Get data socket to server */
1328 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1333 FTP_RetrieveFileData(lpwfs
, nDataSocket
, hFile
);
1334 nResCode
= FTP_ReceiveResponse(lpwfs
, dwContext
);
1337 if (nResCode
== 226)
1340 FTP_SetResponseError(nResCode
);
1342 closesocket(nDataSocket
);
1346 if (lpwfs
->lstnSocket
!= -1)
1347 closesocket(lpwfs
->lstnSocket
);
1351 hIC
= lpwfs
->lpAppInfo
;
1352 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1354 INTERNET_ASYNC_RESULT iar
;
1356 iar
.dwResult
= (DWORD
)bSuccess
;
1357 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1358 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1359 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1365 /***********************************************************************
1366 * FtpGetFileSize (WININET.@)
1368 DWORD WINAPI
FtpGetFileSize( HINTERNET hFile
, LPDWORD lpdwFileSizeHigh
)
1370 FIXME("(%p, %p)\n", hFile
, lpdwFileSizeHigh
);
1372 if (lpdwFileSizeHigh
)
1373 *lpdwFileSizeHigh
= 0;
1378 /***********************************************************************
1379 * FtpDeleteFileA (WININET.@)
1381 * Delete a file on the ftp server
1388 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1390 LPWSTR lpwzFileName
;
1393 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
1394 ret
= FtpDeleteFileW(hFtpSession
, lpwzFileName
);
1395 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
1399 static void AsyncFtpDeleteFileProc(WORKREQUEST
*workRequest
)
1401 struct WORKREQ_FTPDELETEFILEW
const *req
= &workRequest
->u
.FtpDeleteFileW
;
1402 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1404 TRACE("%p\n", lpwfs
);
1406 FTP_FtpDeleteFileW(lpwfs
, req
->lpszFilename
);
1407 HeapFree(GetProcessHeap(), 0, req
->lpszFilename
);
1410 /***********************************************************************
1411 * FtpDeleteFileW (WININET.@)
1413 * Delete a file on the ftp server
1420 BOOL WINAPI
FtpDeleteFileW(HINTERNET hFtpSession
, LPCWSTR lpszFileName
)
1422 LPWININETFTPSESSIONW lpwfs
;
1423 LPWININETAPPINFOW hIC
= NULL
;
1426 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1429 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1433 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1435 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1441 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1445 hIC
= lpwfs
->lpAppInfo
;
1446 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1448 WORKREQUEST workRequest
;
1449 struct WORKREQ_FTPDELETEFILEW
*req
;
1451 workRequest
.asyncproc
= AsyncFtpDeleteFileProc
;
1452 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1453 req
= &workRequest
.u
.FtpDeleteFileW
;
1454 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
1456 r
= INTERNET_AsyncCall(&workRequest
);
1460 r
= FTP_FtpDeleteFileW(lpwfs
, lpszFileName
);
1464 WININET_Release( &lpwfs
->hdr
);
1469 /***********************************************************************
1470 * FTP_FtpDeleteFileW (Internal)
1472 * Delete a file on the ftp server
1479 BOOL
FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszFileName
)
1482 BOOL bSuccess
= FALSE
;
1483 LPWININETAPPINFOW hIC
= NULL
;
1485 TRACE("%p\n", lpwfs
);
1487 /* Clear any error information */
1488 INTERNET_SetLastError(0);
1490 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1493 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1496 if (nResCode
== 250)
1499 FTP_SetResponseError(nResCode
);
1502 hIC
= lpwfs
->lpAppInfo
;
1503 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1505 INTERNET_ASYNC_RESULT iar
;
1507 iar
.dwResult
= (DWORD
)bSuccess
;
1508 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1509 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1510 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1517 /***********************************************************************
1518 * FtpRemoveDirectoryA (WININET.@)
1520 * Remove a directory on the ftp server
1527 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1529 LPWSTR lpwzDirectory
;
1532 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
1533 ret
= FtpRemoveDirectoryW(hFtpSession
, lpwzDirectory
);
1534 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
1538 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST
*workRequest
)
1540 struct WORKREQ_FTPREMOVEDIRECTORYW
const *req
= &workRequest
->u
.FtpRemoveDirectoryW
;
1541 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1543 TRACE("%p\n", lpwfs
);
1545 FTP_FtpRemoveDirectoryW(lpwfs
, req
->lpszDirectory
);
1546 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
1549 /***********************************************************************
1550 * FtpRemoveDirectoryW (WININET.@)
1552 * Remove a directory on the ftp server
1559 BOOL WINAPI
FtpRemoveDirectoryW(HINTERNET hFtpSession
, LPCWSTR lpszDirectory
)
1561 LPWININETFTPSESSIONW lpwfs
;
1562 LPWININETAPPINFOW hIC
= NULL
;
1565 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1568 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1572 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1574 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1580 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1584 hIC
= lpwfs
->lpAppInfo
;
1585 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1587 WORKREQUEST workRequest
;
1588 struct WORKREQ_FTPREMOVEDIRECTORYW
*req
;
1590 workRequest
.asyncproc
= AsyncFtpRemoveDirectoryProc
;
1591 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1592 req
= &workRequest
.u
.FtpRemoveDirectoryW
;
1593 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
1595 r
= INTERNET_AsyncCall(&workRequest
);
1599 r
= FTP_FtpRemoveDirectoryW(lpwfs
, lpszDirectory
);
1603 WININET_Release( &lpwfs
->hdr
);
1608 /***********************************************************************
1609 * FTP_FtpRemoveDirectoryW (Internal)
1611 * Remove a directory on the ftp server
1618 BOOL
FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
1621 BOOL bSuccess
= FALSE
;
1622 LPWININETAPPINFOW hIC
= NULL
;
1626 /* Clear any error information */
1627 INTERNET_SetLastError(0);
1629 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1632 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1635 if (nResCode
== 250)
1638 FTP_SetResponseError(nResCode
);
1642 hIC
= lpwfs
->lpAppInfo
;
1643 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1645 INTERNET_ASYNC_RESULT iar
;
1647 iar
.dwResult
= (DWORD
)bSuccess
;
1648 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1649 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1650 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1657 /***********************************************************************
1658 * FtpRenameFileA (WININET.@)
1660 * Rename a file on the ftp server
1667 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1673 lpwzSrc
= lpszSrc
?WININET_strdup_AtoW(lpszSrc
):NULL
;
1674 lpwzDest
= lpszDest
?WININET_strdup_AtoW(lpszDest
):NULL
;
1675 ret
= FtpRenameFileW(hFtpSession
, lpwzSrc
, lpwzDest
);
1676 HeapFree(GetProcessHeap(), 0, lpwzSrc
);
1677 HeapFree(GetProcessHeap(), 0, lpwzDest
);
1681 static void AsyncFtpRenameFileProc(WORKREQUEST
*workRequest
)
1683 struct WORKREQ_FTPRENAMEFILEW
const *req
= &workRequest
->u
.FtpRenameFileW
;
1684 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1686 TRACE("%p\n", lpwfs
);
1688 FTP_FtpRenameFileW(lpwfs
, req
->lpszSrcFile
, req
->lpszDestFile
);
1689 HeapFree(GetProcessHeap(), 0, req
->lpszSrcFile
);
1690 HeapFree(GetProcessHeap(), 0, req
->lpszDestFile
);
1693 /***********************************************************************
1694 * FtpRenameFileW (WININET.@)
1696 * Rename a file on the ftp server
1703 BOOL WINAPI
FtpRenameFileW(HINTERNET hFtpSession
, LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1705 LPWININETFTPSESSIONW lpwfs
;
1706 LPWININETAPPINFOW hIC
= NULL
;
1709 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1712 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1716 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1718 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1722 if (!lpszSrc
|| !lpszDest
)
1724 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1728 hIC
= lpwfs
->lpAppInfo
;
1729 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1731 WORKREQUEST workRequest
;
1732 struct WORKREQ_FTPRENAMEFILEW
*req
;
1734 workRequest
.asyncproc
= AsyncFtpRenameFileProc
;
1735 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1736 req
= &workRequest
.u
.FtpRenameFileW
;
1737 req
->lpszSrcFile
= WININET_strdupW(lpszSrc
);
1738 req
->lpszDestFile
= WININET_strdupW(lpszDest
);
1740 r
= INTERNET_AsyncCall(&workRequest
);
1744 r
= FTP_FtpRenameFileW(lpwfs
, lpszSrc
, lpszDest
);
1748 WININET_Release( &lpwfs
->hdr
);
1753 /***********************************************************************
1754 * FTP_FtpRenameFileW (Internal)
1756 * Rename a file on the ftp server
1763 BOOL
FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs
,
1764 LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1767 BOOL bSuccess
= FALSE
;
1768 LPWININETAPPINFOW hIC
= NULL
;
1772 /* Clear any error information */
1773 INTERNET_SetLastError(0);
1775 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1778 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1779 if (nResCode
== 350)
1781 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1784 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1787 if (nResCode
== 250)
1790 FTP_SetResponseError(nResCode
);
1793 hIC
= lpwfs
->lpAppInfo
;
1794 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1796 INTERNET_ASYNC_RESULT iar
;
1798 iar
.dwResult
= (DWORD
)bSuccess
;
1799 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1800 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1801 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1807 /***********************************************************************
1808 * FtpCommandA (WININET.@)
1810 BOOL WINAPI
FtpCommandA( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1811 LPCSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1813 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1814 debugstr_a(lpszCommand
), dwContext
, phFtpCommand
);
1819 /***********************************************************************
1820 * FtpCommandW (WININET.@)
1822 BOOL WINAPI
FtpCommandW( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1823 LPCWSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1825 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1826 debugstr_w(lpszCommand
), dwContext
, phFtpCommand
);
1831 /***********************************************************************
1832 * FTP_Connect (internal)
1834 * Connect to a ftp server
1837 * HINTERNET a session handle on success
1842 * Windows uses 'anonymous' as the username, when given a NULL username
1843 * and a NULL password. The password is first looked up in:
1845 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1847 * If this entry is not present it uses the current username as the password.
1851 HINTERNET
FTP_Connect(LPWININETAPPINFOW hIC
, LPCWSTR lpszServerName
,
1852 INTERNET_PORT nServerPort
, LPCWSTR lpszUserName
,
1853 LPCWSTR lpszPassword
, DWORD dwFlags
, DWORD_PTR dwContext
,
1854 DWORD dwInternalFlags
)
1856 static const WCHAR szKey
[] = {'S','o','f','t','w','a','r','e','\\',
1857 'M','i','c','r','o','s','o','f','t','\\',
1858 'W','i','n','d','o','w','s','\\',
1859 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1860 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1861 static const WCHAR szValue
[] = {'E','m','a','i','l','N','a','m','e',0};
1862 static const WCHAR szDefaultUsername
[] = {'a','n','o','n','y','m','o','u','s','\0'};
1863 static const WCHAR szEmpty
[] = {'\0'};
1864 struct sockaddr_in socketAddr
;
1867 BOOL bSuccess
= FALSE
;
1868 LPWININETFTPSESSIONW lpwfs
= NULL
;
1869 HINTERNET handle
= NULL
;
1871 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1872 hIC
, debugstr_w(lpszServerName
),
1873 nServerPort
, debugstr_w(lpszUserName
), debugstr_w(lpszPassword
));
1875 assert( hIC
->hdr
.htype
== WH_HINIT
);
1877 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1879 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1883 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW
));
1886 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1890 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1891 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1893 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1894 lpwfs
->hdr
.dwFlags
= dwFlags
;
1895 lpwfs
->hdr
.dwContext
= dwContext
;
1896 lpwfs
->hdr
.dwInternalFlags
= dwInternalFlags
;
1897 lpwfs
->hdr
.dwRefCount
= 1;
1898 /* FIXME: Native sends INTERNET_STATUS_CLOSING_CONNECTION and
1899 * INTERNET_STATUS_CONNECTION_CLOSED, need an equivalent FTP_CloseConnection
1901 lpwfs
->hdr
.close_connection
= NULL
;
1902 lpwfs
->hdr
.destroy
= FTP_CloseSessionHandle
;
1903 lpwfs
->hdr
.lpfnStatusCB
= hIC
->hdr
.lpfnStatusCB
;
1904 lpwfs
->download_in_progress
= NULL
;
1906 WININET_AddRef( &hIC
->hdr
);
1907 lpwfs
->lpAppInfo
= hIC
;
1908 list_add_head( &hIC
->hdr
.children
, &lpwfs
->hdr
.entry
);
1910 handle
= WININET_AllocHandle( &lpwfs
->hdr
);
1913 ERR("Failed to alloc handle\n");
1914 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1918 if(hIC
->lpszProxy
&& hIC
->dwAccessType
== INTERNET_OPEN_TYPE_PROXY
) {
1919 if(strchrW(hIC
->lpszProxy
, ' '))
1920 FIXME("Several proxies not implemented.\n");
1921 if(hIC
->lpszProxyBypass
)
1922 FIXME("Proxy bypass is ignored.\n");
1924 if ( !lpszUserName
) {
1926 WCHAR szPassword
[MAX_PATH
];
1927 DWORD len
= sizeof(szPassword
);
1929 lpwfs
->lpszUserName
= WININET_strdupW(szDefaultUsername
);
1931 RegOpenKeyW(HKEY_CURRENT_USER
, szKey
, &key
);
1932 if (RegQueryValueExW(key
, szValue
, NULL
, NULL
, (LPBYTE
)szPassword
, &len
)) {
1933 /* Nothing in the registry, get the username and use that as the password */
1934 if (!GetUserNameW(szPassword
, &len
)) {
1935 /* Should never get here, but use an empty password as failsafe */
1936 strcpyW(szPassword
, szEmpty
);
1941 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword
));
1942 lpwfs
->lpszPassword
= WININET_strdupW(szPassword
);
1945 lpwfs
->lpszUserName
= WININET_strdupW(lpszUserName
);
1948 lpwfs
->lpszPassword
= WININET_strdupW(lpszPassword
);
1950 lpwfs
->lpszPassword
= WININET_strdupW(szEmpty
);
1953 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1954 if (!(lpwfs
->hdr
.dwInternalFlags
& INET_OPENURL
))
1956 INTERNET_ASYNC_RESULT iar
;
1958 iar
.dwResult
= (DWORD
)handle
;
1959 iar
.dwError
= ERROR_SUCCESS
;
1961 SendAsyncCallback(&hIC
->hdr
, dwContext
,
1962 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
1963 sizeof(INTERNET_ASYNC_RESULT
));
1966 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1967 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1969 if (!GetAddress(lpszServerName
, nServerPort
, &socketAddr
))
1971 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1975 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1976 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1978 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1981 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1985 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1986 &socketAddr
, sizeof(struct sockaddr_in
));
1988 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1990 ERR("Unable to connect (%s)\n", strerror(errno
));
1991 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1995 TRACE("Connected to server\n");
1996 lpwfs
->sndSocket
= nsocket
;
1997 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1998 &socketAddr
, sizeof(struct sockaddr_in
));
2000 sock_namelen
= sizeof(lpwfs
->socketAddress
);
2001 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
2003 if (FTP_ConnectToHost(lpwfs
))
2005 TRACE("Successfully logged into server\n");
2011 if (!bSuccess
&& nsocket
!= -1)
2012 closesocket(nsocket
);
2014 if (!bSuccess
&& lpwfs
)
2016 HeapFree(GetProcessHeap(), 0, lpwfs
);
2017 WININET_FreeHandle( handle
);
2022 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
2024 INTERNET_ASYNC_RESULT iar
;
2026 iar
.dwResult
= (DWORD
)lpwfs
;
2027 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
2028 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
2029 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
2036 /***********************************************************************
2037 * FTP_ConnectToHost (internal)
2039 * Connect to a ftp server
2046 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
)
2049 BOOL bSuccess
= FALSE
;
2052 FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2054 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
2057 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2060 /* Login successful... */
2061 if (nResCode
== 230)
2063 /* User name okay, need password... */
2064 else if (nResCode
== 331)
2065 bSuccess
= FTP_SendPassword(lpwfs
);
2066 /* Need account for login... */
2067 else if (nResCode
== 332)
2068 bSuccess
= FTP_SendAccount(lpwfs
);
2070 FTP_SetResponseError(nResCode
);
2073 TRACE("Returning %d\n", bSuccess
);
2079 /***********************************************************************
2080 * FTP_SendCommandA (internal)
2082 * Send command to server
2089 static BOOL
FTP_SendCommandA(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
2090 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD_PTR dwContext
)
2094 DWORD nBytesSent
= 0;
2098 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
2102 lpfnStatusCB(hdr
->hInternet
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
2105 dwParamLen
= lpszParam
?strlen(lpszParam
)+1:0;
2106 len
= dwParamLen
+ strlen(szFtpCommands
[ftpCmd
]) + strlen(szCRLF
);
2107 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
2109 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2112 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], dwParamLen
? " " : "",
2113 dwParamLen
? lpszParam
: "", szCRLF
);
2115 TRACE("Sending (%s) len(%d)\n", buf
, len
);
2116 while((nBytesSent
< len
) && (nRC
!= -1))
2118 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
2122 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
2126 lpfnStatusCB(hdr
->hInternet
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
2127 &nBytesSent
, sizeof(DWORD
));
2130 TRACE("Sent %d bytes\n", nBytesSent
);
2134 /***********************************************************************
2135 * FTP_SendCommand (internal)
2137 * Send command to server
2144 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
2145 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD_PTR dwContext
)
2148 LPSTR lpszParamA
= lpszParam
?WININET_strdup_WtoA(lpszParam
):NULL
;
2149 ret
= FTP_SendCommandA(nSocket
, ftpCmd
, lpszParamA
, lpfnStatusCB
, hdr
, dwContext
);
2150 HeapFree(GetProcessHeap(), 0, lpszParamA
);
2154 /***********************************************************************
2155 * FTP_ReceiveResponse (internal)
2157 * Receive response from server
2160 * Reply code on success
2164 INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD_PTR dwContext
)
2166 LPSTR lpszResponse
= INTERNET_GetResponseBuffer();
2169 char firstprefix
[5];
2170 BOOL multiline
= FALSE
;
2171 LPWININETAPPINFOW hIC
= NULL
;
2173 TRACE("socket(%d)\n", lpwfs
->sndSocket
);
2175 hIC
= lpwfs
->lpAppInfo
;
2176 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
2180 if (!INTERNET_GetNextLine(lpwfs
->sndSocket
, &nRecv
))
2187 if(lpszResponse
[3] != '-')
2190 { /* Start of multiline repsonse. Loop until we get "nnn " */
2192 memcpy(firstprefix
, lpszResponse
, 3);
2193 firstprefix
[3] = ' ';
2194 firstprefix
[4] = '\0';
2199 if(!memcmp(firstprefix
, lpszResponse
, 4))
2207 rc
= atoi(lpszResponse
);
2209 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
2210 &nRecv
, sizeof(DWORD
));
2214 TRACE("return %d\n", rc
);
2219 /***********************************************************************
2220 * FTP_SendPassword (internal)
2222 * Send password to ftp server
2229 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
)
2232 BOOL bSuccess
= FALSE
;
2235 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
2238 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2241 TRACE("Received reply code %d\n", nResCode
);
2242 /* Login successful... */
2243 if (nResCode
== 230)
2245 /* Command not implemented, superfluous at the server site... */
2246 /* Need account for login... */
2247 else if (nResCode
== 332)
2248 bSuccess
= FTP_SendAccount(lpwfs
);
2250 FTP_SetResponseError(nResCode
);
2254 TRACE("Returning %d\n", bSuccess
);
2259 /***********************************************************************
2260 * FTP_SendAccount (internal)
2269 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
)
2272 BOOL bSuccess
= FALSE
;
2275 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, szNoAccount
, 0, 0, 0))
2278 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2282 FTP_SetResponseError(nResCode
);
2289 /***********************************************************************
2290 * FTP_SendStore (internal)
2292 * Send request to upload file to ftp server
2299 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2302 BOOL bSuccess
= FALSE
;
2305 if (!FTP_InitListenSocket(lpwfs
))
2308 if (!FTP_SendType(lpwfs
, dwType
))
2311 if (!FTP_SendPortOrPasv(lpwfs
))
2314 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
2316 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2319 if (nResCode
== 150 || nResCode
== 125)
2322 FTP_SetResponseError(nResCode
);
2326 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
2328 closesocket(lpwfs
->lstnSocket
);
2329 lpwfs
->lstnSocket
= -1;
2336 /***********************************************************************
2337 * FTP_InitListenSocket (internal)
2339 * Create a socket to listen for server response
2346 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
)
2348 BOOL bSuccess
= FALSE
;
2349 socklen_t namelen
= sizeof(struct sockaddr_in
);
2353 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
2354 if (lpwfs
->lstnSocket
== -1)
2356 TRACE("Unable to create listening socket\n");
2360 /* We obtain our ip addr from the name of the command channel socket */
2361 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
2363 /* and get the system to assign us a port */
2364 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
2366 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
2368 TRACE("Unable to bind socket\n");
2372 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
2374 TRACE("listen failed\n");
2378 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
2382 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
2384 closesocket(lpwfs
->lstnSocket
);
2385 lpwfs
->lstnSocket
= -1;
2392 /***********************************************************************
2393 * FTP_SendType (internal)
2395 * Tell server type of data being transferred
2401 * W98SE doesn't cache the type that's currently set
2402 * (i.e. it sends it always),
2403 * so we probably don't want to do that either.
2405 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
)
2408 WCHAR type
[] = { 'I','\0' };
2409 BOOL bSuccess
= FALSE
;
2412 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
2415 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
2418 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
)/100;
2424 FTP_SetResponseError(nResCode
);
2432 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2433 /***********************************************************************
2434 * FTP_GetFileSize (internal)
2436 * Retrieves from the server the size of the given file
2443 static BOOL
FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD
*dwSize
)
2446 BOOL bSuccess
= FALSE
;
2450 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
2453 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2456 if (nResCode
== 213) {
2457 /* Now parses the output to get the actual file size */
2459 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2461 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
2462 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
2463 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2467 FTP_SetResponseError(nResCode
);
2477 /***********************************************************************
2478 * FTP_SendPort (internal)
2480 * Tell server which port to use
2487 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
)
2489 static const WCHAR szIPFormat
[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2491 WCHAR szIPAddress
[64];
2492 BOOL bSuccess
= FALSE
;
2495 sprintfW(szIPAddress
, szIPFormat
,
2496 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2497 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2498 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2499 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2500 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2501 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2503 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2506 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2509 if (nResCode
== 200)
2512 FTP_SetResponseError(nResCode
);
2520 /***********************************************************************
2521 * FTP_DoPassive (internal)
2523 * Tell server that we want to do passive transfers
2524 * and connect data socket
2531 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
)
2534 BOOL bSuccess
= FALSE
;
2537 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2540 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2543 if (nResCode
== 227)
2545 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2549 char *pAddr
, *pPort
;
2551 struct sockaddr_in dataSocketAddress
;
2553 p
= lpszResponseBuffer
+4; /* skip status code */
2554 while (*p
!= '\0' && (*p
< '0' || *p
> '9')) p
++;
2558 ERR("no address found in response, aborting\n");
2562 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2565 ERR("unknown response address format '%s', aborting\n", p
);
2568 for (i
=0; i
< 6; i
++)
2571 dataSocketAddress
= lpwfs
->socketAddress
;
2572 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2573 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2581 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2585 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2587 ERR("can't connect passive FTP data port.\n");
2588 closesocket(nsocket
);
2591 lpwfs
->pasvSocket
= nsocket
;
2595 FTP_SetResponseError(nResCode
);
2603 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
)
2605 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2607 if (!FTP_DoPassive(lpwfs
))
2612 if (!FTP_SendPort(lpwfs
))
2619 /***********************************************************************
2620 * FTP_GetDataSocket (internal)
2622 * Either accepts an incoming data socket connection from the server
2623 * or just returns the already opened socket after a PASV command
2624 * in case of passive FTP.
2632 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
)
2634 struct sockaddr_in saddr
;
2635 socklen_t addrlen
= sizeof(struct sockaddr
);
2638 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2640 *nDataSocket
= lpwfs
->pasvSocket
;
2644 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2645 closesocket(lpwfs
->lstnSocket
);
2646 lpwfs
->lstnSocket
= -1;
2648 return *nDataSocket
!= -1;
2652 /***********************************************************************
2653 * FTP_SendData (internal)
2655 * Send data to the server
2662 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
)
2664 BY_HANDLE_FILE_INFORMATION fi
;
2665 DWORD nBytesRead
= 0;
2666 DWORD nBytesSent
= 0;
2667 DWORD nTotalSent
= 0;
2668 DWORD nBytesToSend
, nLen
;
2670 time_t s_long_time
, e_long_time
;
2675 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2677 /* Get the size of the file. */
2678 GetFileInformationByHandle(hFile
, &fi
);
2683 nBytesToSend
= nBytesRead
- nBytesSent
;
2685 if (nBytesToSend
<= 0)
2687 /* Read data from file. */
2689 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2690 ERR("Failed reading from file\n");
2693 nBytesToSend
= nBytesRead
;
2698 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2699 DATA_PACKET_SIZE
: nBytesToSend
;
2700 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2708 /* Do some computation to display the status. */
2710 nSeconds
= e_long_time
- s_long_time
;
2711 if( nSeconds
/ 60 > 0 )
2713 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2714 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2715 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2719 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2720 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2721 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2723 } while (nRC
!= -1);
2725 TRACE("file transfer complete!\n");
2727 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2733 /***********************************************************************
2734 * FTP_SendRetrieve (internal)
2736 * Send request to retrieve a file
2739 * Number of bytes to be received on success
2743 static BOOL
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2749 if (!(ret
= FTP_InitListenSocket(lpwfs
)))
2752 if (!(ret
= FTP_SendType(lpwfs
, dwType
)))
2755 if (!(ret
= FTP_SendPortOrPasv(lpwfs
)))
2758 if (!(ret
= FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0)))
2761 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2762 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2763 /* That means that we got an error getting the file. */
2764 FTP_SetResponseError(nResCode
);
2769 if (!ret
&& lpwfs
->lstnSocket
!= -1)
2771 closesocket(lpwfs
->lstnSocket
);
2772 lpwfs
->lstnSocket
= -1;
2779 /***********************************************************************
2780 * FTP_RetrieveData (internal)
2782 * Retrieve data from server
2789 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
)
2791 DWORD nBytesWritten
;
2792 DWORD nBytesReceived
= 0;
2798 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2799 if (NULL
== lpszBuffer
)
2801 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2807 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2810 /* other side closed socket. */
2813 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2814 nBytesReceived
+= nRC
;
2818 TRACE("Data transfer complete\n");
2821 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2827 /***********************************************************************
2828 * FTP_CloseSessionHandle (internal)
2830 * Deallocate session handle
2837 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
)
2839 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) hdr
;
2843 WININET_Release(&lpwfs
->lpAppInfo
->hdr
);
2845 if (lpwfs
->download_in_progress
!= NULL
)
2846 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2848 if (lpwfs
->sndSocket
!= -1)
2849 closesocket(lpwfs
->sndSocket
);
2851 if (lpwfs
->lstnSocket
!= -1)
2852 closesocket(lpwfs
->lstnSocket
);
2854 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2855 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2856 HeapFree(GetProcessHeap(), 0, lpwfs
);
2860 /***********************************************************************
2861 * FTP_FindNextFileW (Internal)
2863 * Continues a file search from a previous call to FindFirstFile
2870 BOOL WINAPI
FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh
, LPVOID lpvFindData
)
2872 BOOL bSuccess
= TRUE
;
2873 LPWIN32_FIND_DATAW lpFindFileData
;
2875 TRACE("index(%d) size(%d)\n", lpwh
->index
, lpwh
->size
);
2877 assert (lpwh
->hdr
.htype
== WH_HFTPFINDNEXT
);
2879 /* Clear any error information */
2880 INTERNET_SetLastError(0);
2882 lpFindFileData
= (LPWIN32_FIND_DATAW
) lpvFindData
;
2883 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2885 if (lpwh
->index
>= lpwh
->size
)
2887 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2892 FTP_ConvertFileProp(&lpwh
->lpafp
[lpwh
->index
], lpFindFileData
);
2895 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData
->cFileName
), lpFindFileData
->nFileSizeLow
);
2899 if (lpwh
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
2901 INTERNET_ASYNC_RESULT iar
;
2903 iar
.dwResult
= (DWORD
)bSuccess
;
2904 iar
.dwError
= iar
.dwError
= bSuccess
? ERROR_SUCCESS
:
2905 INTERNET_GetLastError();
2907 INTERNET_SendCallback(&lpwh
->hdr
, lpwh
->hdr
.dwContext
,
2908 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
2909 sizeof(INTERNET_ASYNC_RESULT
));
2916 /***********************************************************************
2917 * FTP_CloseFindNextHandle (internal)
2919 * Deallocate session handle
2926 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
)
2928 LPWININETFTPFINDNEXTW lpwfn
= (LPWININETFTPFINDNEXTW
) hdr
;
2933 WININET_Release(&lpwfn
->lpFtpSession
->hdr
);
2935 for (i
= 0; i
< lpwfn
->size
; i
++)
2937 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2940 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2941 HeapFree(GetProcessHeap(), 0, lpwfn
);
2944 /***********************************************************************
2945 * FTP_CloseFileTransferHandle (internal)
2947 * Closes the file transfer handle. This also 'cleans' the data queue of
2948 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2951 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
)
2953 LPWININETFTPFILE lpwh
= (LPWININETFTPFILE
) hdr
;
2954 LPWININETFTPSESSIONW lpwfs
= lpwh
->lpFtpSession
;
2959 WININET_Release(&lpwh
->lpFtpSession
->hdr
);
2961 if (!lpwh
->session_deleted
)
2962 lpwfs
->download_in_progress
= NULL
;
2964 /* This just serves to flush the control socket of any spurrious lines written
2965 to it (like '226 Transfer complete.').
2967 Wonder what to do if the server sends us an error code though...
2969 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2971 if (lpwh
->nDataSocket
!= -1)
2972 closesocket(lpwh
->nDataSocket
);
2974 HeapFree(GetProcessHeap(), 0, lpwh
);
2977 /***********************************************************************
2978 * FTP_ReceiveFileList (internal)
2980 * Read file list from server
2983 * Handle to file list on success
2987 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
2988 LPWIN32_FIND_DATAW lpFindFileData
, DWORD_PTR dwContext
)
2991 LPFILEPROPERTIESW lpafp
= NULL
;
2992 LPWININETFTPFINDNEXTW lpwfn
= NULL
;
2993 HINTERNET handle
= 0;
2995 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs
, nSocket
, debugstr_w(lpszSearchFile
), lpFindFileData
, dwContext
);
2997 if (FTP_ParseDirectory(lpwfs
, nSocket
, lpszSearchFile
, &lpafp
, &dwSize
))
3000 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
3002 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFTPFINDNEXTW
));
3005 lpwfn
->hdr
.htype
= WH_HFTPFINDNEXT
;
3006 lpwfn
->hdr
.dwContext
= dwContext
;
3007 lpwfn
->hdr
.dwRefCount
= 1;
3008 lpwfn
->hdr
.close_connection
= NULL
;
3009 lpwfn
->hdr
.destroy
= FTP_CloseFindNextHandle
;
3010 lpwfn
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
3011 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
3012 lpwfn
->size
= dwSize
;
3013 lpwfn
->lpafp
= lpafp
;
3015 WININET_AddRef( &lpwfs
->hdr
);
3016 lpwfn
->lpFtpSession
= lpwfs
;
3017 list_add_head( &lpwfs
->hdr
.children
, &lpwfn
->hdr
.entry
);
3019 handle
= WININET_AllocHandle( &lpwfn
->hdr
);
3024 WININET_Release( &lpwfn
->hdr
);
3026 TRACE("Matched %d files\n", dwSize
);
3031 /***********************************************************************
3032 * FTP_ConvertFileProp (internal)
3034 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3041 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp
, LPWIN32_FIND_DATAW lpFindFileData
)
3043 BOOL bSuccess
= FALSE
;
3045 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAW
));
3049 /* Convert 'Unix' time to Windows time */
3050 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
3051 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
3052 lpFindFileData
->ftLastWriteTime
= lpFindFileData
->ftLastAccessTime
;
3053 lpFindFileData
->ftCreationTime
= lpFindFileData
->ftLastAccessTime
;
3055 /* Not all fields are filled in */
3056 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3057 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
3059 if (lpafp
->bIsDirectory
)
3060 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
3062 if (lpafp
->lpszName
)
3063 lstrcpynW(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
3071 /***********************************************************************
3072 * FTP_ParseNextFile (internal)
3074 * Parse the next line in file listing
3080 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW lpfp
)
3082 static const char szSpace
[] = " \t";
3090 lpfp
->lpszName
= NULL
;
3092 if(!(pszLine
= INTERNET_GetNextLine(nSocket
, &nBufLen
)))
3095 pszToken
= strtok(pszLine
, szSpace
);
3097 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3100 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3102 if(!isdigit(pszToken
[0]) && 10 == strlen(pszToken
)) {
3103 if(!FTP_ParsePermission(pszToken
, lpfp
))
3104 lpfp
->bIsDirectory
= FALSE
;
3105 for(i
=0; i
<=3; i
++) {
3106 if(!(pszToken
= strtok(NULL
, szSpace
)))
3109 if(!pszToken
) continue;
3110 if(lpfp
->bIsDirectory
) {
3111 TRACE("Is directory\n");
3115 TRACE("Size: %s\n", pszToken
);
3116 lpfp
->nSize
= atol(pszToken
);
3119 lpfp
->tmLastModified
.tm_sec
= 0;
3120 lpfp
->tmLastModified
.tm_min
= 0;
3121 lpfp
->tmLastModified
.tm_hour
= 0;
3122 lpfp
->tmLastModified
.tm_mday
= 0;
3123 lpfp
->tmLastModified
.tm_mon
= 0;
3124 lpfp
->tmLastModified
.tm_year
= 0;
3126 /* Determine month */
3127 pszToken
= strtok(NULL
, szSpace
);
3128 if(!pszToken
) continue;
3129 if(strlen(pszToken
) >= 3) {
3131 if((pszTmp
= StrStrIA(szMonths
, pszToken
)))
3132 lpfp
->tmLastModified
.tm_mon
= ((pszTmp
- szMonths
) / 3)+1;
3135 pszToken
= strtok(NULL
, szSpace
);
3136 if(!pszToken
) continue;
3137 lpfp
->tmLastModified
.tm_mday
= atoi(pszToken
);
3138 /* Determine time or year */
3139 pszToken
= strtok(NULL
, szSpace
);
3140 if(!pszToken
) continue;
3141 if((pszTmp
= strchr(pszToken
, ':'))) {
3146 lpfp
->tmLastModified
.tm_min
= atoi(pszTmp
);
3147 lpfp
->tmLastModified
.tm_hour
= atoi(pszToken
);
3149 apTM
= localtime(&aTime
);
3150 lpfp
->tmLastModified
.tm_year
= apTM
->tm_year
;
3153 lpfp
->tmLastModified
.tm_year
= atoi(pszToken
) - 1900;
3154 lpfp
->tmLastModified
.tm_hour
= 12;
3156 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3157 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3158 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3159 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3161 pszToken
= strtok(NULL
, szSpace
);
3162 if(!pszToken
) continue;
3163 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3164 TRACE("File: %s\n", debugstr_w(lpfp
->lpszName
));
3166 /* NT way of parsing ... :
3168 07-13-03 08:55PM <DIR> sakpatch
3169 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3171 else if(isdigit(pszToken
[0]) && 8 == strlen(pszToken
)) {
3172 lpfp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
3174 sscanf(pszToken
, "%d-%d-%d",
3175 &lpfp
->tmLastModified
.tm_mon
,
3176 &lpfp
->tmLastModified
.tm_mday
,
3177 &lpfp
->tmLastModified
.tm_year
);
3179 /* Hacky and bad Y2K protection :-) */
3180 if (lpfp
->tmLastModified
.tm_year
< 70)
3181 lpfp
->tmLastModified
.tm_year
+= 100;
3183 pszToken
= strtok(NULL
, szSpace
);
3184 if(!pszToken
) continue;
3185 sscanf(pszToken
, "%d:%d",
3186 &lpfp
->tmLastModified
.tm_hour
,
3187 &lpfp
->tmLastModified
.tm_min
);
3188 if((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
3189 lpfp
->tmLastModified
.tm_hour
+= 12;
3191 lpfp
->tmLastModified
.tm_sec
= 0;
3193 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3194 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3195 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3196 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3198 pszToken
= strtok(NULL
, szSpace
);
3199 if(!pszToken
) continue;
3200 if(!strcasecmp(pszToken
, "<DIR>")) {
3201 lpfp
->bIsDirectory
= TRUE
;
3203 TRACE("Is directory\n");
3206 lpfp
->bIsDirectory
= FALSE
;
3207 lpfp
->nSize
= atol(pszToken
);
3208 TRACE("Size: %d\n", lpfp
->nSize
);
3211 pszToken
= strtok(NULL
, szSpace
);
3212 if(!pszToken
) continue;
3213 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3214 TRACE("Name: %s\n", debugstr_w(lpfp
->lpszName
));
3216 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3217 else if(pszToken
[0] == '+') {
3218 FIXME("EPLF Format not implemented\n");
3221 if(lpfp
->lpszName
) {
3222 if((lpszSearchFile
== NULL
) ||
3223 (PathMatchSpecW(lpfp
->lpszName
, lpszSearchFile
))) {
3225 TRACE("Matched: %s\n", debugstr_w(lpfp
->lpszName
));
3228 HeapFree(GetProcessHeap(), 0, lpfp
->lpszName
);
3229 lpfp
->lpszName
= NULL
;
3236 /***********************************************************************
3237 * FTP_ParseDirectory (internal)
3239 * Parse string of directory information
3245 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
3246 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
)
3248 BOOL bSuccess
= TRUE
;
3249 INT sizeFilePropArray
= 500;/*20; */
3250 INT indexFilePropArray
= -1;
3254 /* Allocate intial file properties array */
3255 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESW
)*(sizeFilePropArray
));
3260 if (indexFilePropArray
+1 >= sizeFilePropArray
)
3262 LPFILEPROPERTIESW tmpafp
;
3264 sizeFilePropArray
*= 2;
3265 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
3266 sizeof(FILEPROPERTIESW
)*sizeFilePropArray
);
3275 indexFilePropArray
++;
3276 } while (FTP_ParseNextFile(nSocket
, lpszSearchFile
, &(*lpafp
)[indexFilePropArray
]));
3278 if (bSuccess
&& indexFilePropArray
)
3280 if (indexFilePropArray
< sizeFilePropArray
- 1)
3282 LPFILEPROPERTIESW tmpafp
;
3284 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
3285 sizeof(FILEPROPERTIESW
)*indexFilePropArray
);
3289 *dwfp
= indexFilePropArray
;
3293 HeapFree(GetProcessHeap(), 0, *lpafp
);
3294 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
3302 /***********************************************************************
3303 * FTP_ParsePermission (internal)
3305 * Parse permission string of directory information
3312 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
)
3314 BOOL bSuccess
= TRUE
;
3315 unsigned short nPermission
= 0;
3320 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
3326 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
3332 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
3335 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
3338 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
3341 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
3344 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
3347 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
3350 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
3353 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
3356 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
3360 }while (nPos
<= nLast
);
3362 lpfp
->permissions
= nPermission
;
3367 /***********************************************************************
3368 * FTP_SetResponseError (internal)
3370 * Set the appropriate error code for a given response from the server
3375 static DWORD
FTP_SetResponseError(DWORD dwResponse
)
3381 case 421: /* Service not available - Server may be shutting down. */
3382 dwCode
= ERROR_INTERNET_TIMEOUT
;
3385 case 425: /* Cannot open data connection. */
3386 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
3389 case 426: /* Connection closed, transer aborted. */
3390 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
3393 case 500: /* Syntax error. Command unrecognized. */
3394 case 501: /* Syntax error. Error in parameters or arguments. */
3395 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
3398 case 530: /* Not logged in. Login incorrect. */
3399 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
3402 case 550: /* File action not taken. File not found or no access. */
3403 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
3406 case 450: /* File action not taken. File may be busy. */
3407 case 451: /* Action aborted. Server error. */
3408 case 452: /* Action not taken. Insufficient storage space on server. */
3409 case 502: /* Command not implemented. */
3410 case 503: /* Bad sequence of commands. */
3411 case 504: /* Command not implemented for that parameter. */
3412 case 532: /* Need account for storing files */
3413 case 551: /* Requested action aborted. Page type unknown */
3414 case 552: /* Action aborted. Exceeded storage allocation */
3415 case 553: /* Action not taken. File name not allowed. */
3418 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
3422 INTERNET_SetLastError(dwCode
);