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_CloseConnection(LPWININETHANDLEHEADER hdr
);
127 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
);
128 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
129 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD_PTR dwContext
);
130 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
);
131 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
);
132 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
);
133 static INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD_PTR dwContext
);
134 static BOOL
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
);
135 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
);
136 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
);
137 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
);
138 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
);
139 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
);
140 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
);
141 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
);
142 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
);
143 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
);
144 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
);
145 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW fileprop
);
146 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
147 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
);
148 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
149 LPWIN32_FIND_DATAW lpFindFileData
, DWORD_PTR dwContext
);
150 static DWORD
FTP_SetResponseError(DWORD dwResponse
);
152 /***********************************************************************
153 * FtpPutFileA (WININET.@)
155 * Uploads a file to the FTP server
162 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
163 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD_PTR dwContext
)
165 LPWSTR lpwzLocalFile
;
166 LPWSTR lpwzNewRemoteFile
;
169 lpwzLocalFile
= lpszLocalFile
?WININET_strdup_AtoW(lpszLocalFile
):NULL
;
170 lpwzNewRemoteFile
= lpszNewRemoteFile
?WININET_strdup_AtoW(lpszNewRemoteFile
):NULL
;
171 ret
= FtpPutFileW(hConnect
, lpwzLocalFile
, lpwzNewRemoteFile
,
173 HeapFree(GetProcessHeap(), 0, lpwzLocalFile
);
174 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile
);
178 static void AsyncFtpPutFileProc(WORKREQUEST
*workRequest
)
180 struct WORKREQ_FTPPUTFILEW
const *req
= &workRequest
->u
.FtpPutFileW
;
181 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
183 TRACE("%p\n", lpwfs
);
185 FTP_FtpPutFileW(lpwfs
, req
->lpszLocalFile
,
186 req
->lpszNewRemoteFile
, req
->dwFlags
, req
->dwContext
);
188 HeapFree(GetProcessHeap(), 0, req
->lpszLocalFile
);
189 HeapFree(GetProcessHeap(), 0, req
->lpszNewRemoteFile
);
192 /***********************************************************************
193 * FtpPutFileW (WININET.@)
195 * Uploads a file to the FTP server
202 BOOL WINAPI
FtpPutFileW(HINTERNET hConnect
, LPCWSTR lpszLocalFile
,
203 LPCWSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD_PTR dwContext
)
205 LPWININETFTPSESSIONW lpwfs
;
206 LPWININETAPPINFOW hIC
= NULL
;
209 if (!lpszLocalFile
|| !lpszNewRemoteFile
)
211 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
215 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
218 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
222 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
224 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
228 if ((dwFlags
& FTP_CONDITION_MASK
) > FTP_TRANSFER_TYPE_BINARY
)
230 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
234 hIC
= lpwfs
->lpAppInfo
;
235 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
237 WORKREQUEST workRequest
;
238 struct WORKREQ_FTPPUTFILEW
*req
= &workRequest
.u
.FtpPutFileW
;
240 workRequest
.asyncproc
= AsyncFtpPutFileProc
;
241 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
242 req
->lpszLocalFile
= WININET_strdupW(lpszLocalFile
);
243 req
->lpszNewRemoteFile
= WININET_strdupW(lpszNewRemoteFile
);
244 req
->dwFlags
= dwFlags
;
245 req
->dwContext
= dwContext
;
247 r
= INTERNET_AsyncCall(&workRequest
);
251 r
= FTP_FtpPutFileW(lpwfs
, lpszLocalFile
,
252 lpszNewRemoteFile
, dwFlags
, dwContext
);
256 WININET_Release( &lpwfs
->hdr
);
261 /***********************************************************************
262 * FTP_FtpPutFileW (Internal)
264 * Uploads a file to the FTP server
271 BOOL WINAPI
FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszLocalFile
,
272 LPCWSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD_PTR dwContext
)
275 BOOL bSuccess
= FALSE
;
276 LPWININETAPPINFOW hIC
= NULL
;
279 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile
), debugstr_w(lpszNewRemoteFile
));
281 /* Clear any error information */
282 INTERNET_SetLastError(0);
284 /* Open file to be uploaded */
285 if (INVALID_HANDLE_VALUE
==
286 (hFile
= CreateFileW(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
287 /* Let CreateFile set the appropriate error */
290 hIC
= lpwfs
->lpAppInfo
;
292 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
294 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
298 /* Get data socket to server */
299 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
301 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
302 closesocket(nDataSocket
);
303 nResCode
= FTP_ReceiveResponse(lpwfs
, dwContext
);
309 FTP_SetResponseError(nResCode
);
314 if (lpwfs
->lstnSocket
!= -1)
315 closesocket(lpwfs
->lstnSocket
);
317 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
319 INTERNET_ASYNC_RESULT iar
;
321 iar
.dwResult
= (DWORD
)bSuccess
;
322 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
323 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
324 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
333 /***********************************************************************
334 * FtpSetCurrentDirectoryA (WININET.@)
336 * Change the working directory on the FTP server
343 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
345 LPWSTR lpwzDirectory
;
348 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
349 ret
= FtpSetCurrentDirectoryW(hConnect
, lpwzDirectory
);
350 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
355 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST
*workRequest
)
357 struct WORKREQ_FTPSETCURRENTDIRECTORYW
const *req
= &workRequest
->u
.FtpSetCurrentDirectoryW
;
358 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
360 TRACE("%p\n", lpwfs
);
362 FTP_FtpSetCurrentDirectoryW(lpwfs
, req
->lpszDirectory
);
363 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
366 /***********************************************************************
367 * FtpSetCurrentDirectoryW (WININET.@)
369 * Change the working directory on the FTP server
376 BOOL WINAPI
FtpSetCurrentDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
378 LPWININETFTPSESSIONW lpwfs
= NULL
;
379 LPWININETAPPINFOW hIC
= NULL
;
384 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
388 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
389 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
391 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
395 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
397 hIC
= lpwfs
->lpAppInfo
;
398 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
400 WORKREQUEST workRequest
;
401 struct WORKREQ_FTPSETCURRENTDIRECTORYW
*req
;
403 workRequest
.asyncproc
= AsyncFtpSetCurrentDirectoryProc
;
404 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
405 req
= &workRequest
.u
.FtpSetCurrentDirectoryW
;
406 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
408 r
= INTERNET_AsyncCall(&workRequest
);
412 r
= FTP_FtpSetCurrentDirectoryW(lpwfs
, lpszDirectory
);
417 WININET_Release( &lpwfs
->hdr
);
423 /***********************************************************************
424 * FTP_FtpSetCurrentDirectoryW (Internal)
426 * Change the working directory on the FTP server
433 BOOL WINAPI
FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
436 LPWININETAPPINFOW hIC
= NULL
;
437 DWORD bSuccess
= FALSE
;
439 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
441 /* Clear any error information */
442 INTERNET_SetLastError(0);
444 hIC
= lpwfs
->lpAppInfo
;
445 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
446 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
449 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
456 FTP_SetResponseError(nResCode
);
460 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
462 INTERNET_ASYNC_RESULT iar
;
464 iar
.dwResult
= (DWORD
)bSuccess
;
465 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
466 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
467 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
473 /***********************************************************************
474 * FtpCreateDirectoryA (WININET.@)
476 * Create new directory on the FTP server
483 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
485 LPWSTR lpwzDirectory
;
488 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
489 ret
= FtpCreateDirectoryW(hConnect
, lpwzDirectory
);
490 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
495 static void AsyncFtpCreateDirectoryProc(WORKREQUEST
*workRequest
)
497 struct WORKREQ_FTPCREATEDIRECTORYW
const *req
= &workRequest
->u
.FtpCreateDirectoryW
;
498 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
500 TRACE(" %p\n", lpwfs
);
502 FTP_FtpCreateDirectoryW(lpwfs
, req
->lpszDirectory
);
503 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
506 /***********************************************************************
507 * FtpCreateDirectoryW (WININET.@)
509 * Create new directory on the FTP server
516 BOOL WINAPI
FtpCreateDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
518 LPWININETFTPSESSIONW lpwfs
;
519 LPWININETAPPINFOW hIC
= NULL
;
522 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
525 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
529 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
531 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
537 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
541 hIC
= lpwfs
->lpAppInfo
;
542 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
544 WORKREQUEST workRequest
;
545 struct WORKREQ_FTPCREATEDIRECTORYW
*req
;
547 workRequest
.asyncproc
= AsyncFtpCreateDirectoryProc
;
548 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
549 req
= &workRequest
.u
.FtpCreateDirectoryW
;
550 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
552 r
= INTERNET_AsyncCall(&workRequest
);
556 r
= FTP_FtpCreateDirectoryW(lpwfs
, lpszDirectory
);
559 WININET_Release( &lpwfs
->hdr
);
565 /***********************************************************************
566 * FTP_FtpCreateDirectoryW (Internal)
568 * Create new directory on the FTP server
575 BOOL WINAPI
FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
578 BOOL bSuccess
= FALSE
;
579 LPWININETAPPINFOW hIC
= NULL
;
581 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
583 /* Clear any error information */
584 INTERNET_SetLastError(0);
586 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
589 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
595 FTP_SetResponseError(nResCode
);
599 hIC
= lpwfs
->lpAppInfo
;
600 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
602 INTERNET_ASYNC_RESULT iar
;
604 iar
.dwResult
= (DWORD
)bSuccess
;
605 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
606 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
607 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
613 /***********************************************************************
614 * FtpFindFirstFileA (WININET.@)
616 * Search the specified directory
619 * HINTERNET on success
623 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
624 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD_PTR dwContext
)
626 LPWSTR lpwzSearchFile
;
627 WIN32_FIND_DATAW wfd
;
628 LPWIN32_FIND_DATAW lpFindFileDataW
;
631 lpwzSearchFile
= lpszSearchFile
?WININET_strdup_AtoW(lpszSearchFile
):NULL
;
632 lpFindFileDataW
= lpFindFileData
?&wfd
:NULL
;
633 ret
= FtpFindFirstFileW(hConnect
, lpwzSearchFile
, lpFindFileDataW
, dwFlags
, dwContext
);
634 HeapFree(GetProcessHeap(), 0, lpwzSearchFile
);
637 WININET_find_data_WtoA(lpFindFileDataW
, lpFindFileData
);
643 static void AsyncFtpFindFirstFileProc(WORKREQUEST
*workRequest
)
645 struct WORKREQ_FTPFINDFIRSTFILEW
const *req
= &workRequest
->u
.FtpFindFirstFileW
;
646 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
648 TRACE("%p\n", lpwfs
);
650 FTP_FtpFindFirstFileW(lpwfs
, req
->lpszSearchFile
,
651 req
->lpFindFileData
, req
->dwFlags
, req
->dwContext
);
652 HeapFree(GetProcessHeap(), 0, req
->lpszSearchFile
);
655 /***********************************************************************
656 * FtpFindFirstFileW (WININET.@)
658 * Search the specified directory
661 * HINTERNET on success
665 HINTERNET WINAPI
FtpFindFirstFileW(HINTERNET hConnect
,
666 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD_PTR dwContext
)
668 LPWININETFTPSESSIONW lpwfs
;
669 LPWININETAPPINFOW hIC
= NULL
;
672 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
673 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
675 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
679 hIC
= lpwfs
->lpAppInfo
;
680 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
682 WORKREQUEST workRequest
;
683 struct WORKREQ_FTPFINDFIRSTFILEW
*req
;
685 workRequest
.asyncproc
= AsyncFtpFindFirstFileProc
;
686 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
687 req
= &workRequest
.u
.FtpFindFirstFileW
;
688 req
->lpszSearchFile
= (lpszSearchFile
== NULL
) ? NULL
: WININET_strdupW(lpszSearchFile
);
689 req
->lpFindFileData
= lpFindFileData
;
690 req
->dwFlags
= dwFlags
;
691 req
->dwContext
= dwContext
;
693 INTERNET_AsyncCall(&workRequest
);
698 r
= FTP_FtpFindFirstFileW(lpwfs
, lpszSearchFile
, lpFindFileData
,
703 WININET_Release( &lpwfs
->hdr
);
709 /***********************************************************************
710 * FTP_FtpFindFirstFileW (Internal)
712 * Search the specified directory
715 * HINTERNET on success
719 HINTERNET WINAPI
FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs
,
720 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD_PTR dwContext
)
723 LPWININETAPPINFOW hIC
= NULL
;
724 HINTERNET hFindNext
= NULL
;
728 /* Clear any error information */
729 INTERNET_SetLastError(0);
731 if (!FTP_InitListenSocket(lpwfs
))
734 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
737 if (!FTP_SendPortOrPasv(lpwfs
))
740 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, NULL
,
741 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
744 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
747 if (nResCode
== 125 || nResCode
== 150)
751 /* Get data socket to server */
752 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
754 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpszSearchFile
, lpFindFileData
, dwContext
);
755 closesocket(nDataSocket
);
756 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
757 if (nResCode
!= 226 && nResCode
!= 250)
758 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
762 FTP_SetResponseError(nResCode
);
766 if (lpwfs
->lstnSocket
!= -1)
767 closesocket(lpwfs
->lstnSocket
);
769 hIC
= lpwfs
->lpAppInfo
;
770 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
772 INTERNET_ASYNC_RESULT iar
;
776 iar
.dwResult
= (DWORD
)hFindNext
;
777 iar
.dwError
= ERROR_SUCCESS
;
778 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
779 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
782 iar
.dwResult
= (DWORD
)hFindNext
;
783 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
784 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
785 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
792 /***********************************************************************
793 * FtpGetCurrentDirectoryA (WININET.@)
795 * Retrieves the current directory
802 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
803 LPDWORD lpdwCurrentDirectory
)
809 if(lpdwCurrentDirectory
) {
810 len
= *lpdwCurrentDirectory
;
811 if(lpszCurrentDirectory
)
813 dir
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
816 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
821 ret
= FtpGetCurrentDirectoryW(hFtpSession
, lpszCurrentDirectory
?dir
:NULL
, lpdwCurrentDirectory
?&len
:NULL
);
822 if(lpdwCurrentDirectory
) {
823 *lpdwCurrentDirectory
= len
;
824 if(lpszCurrentDirectory
) {
825 WideCharToMultiByte(CP_ACP
, 0, dir
, len
, lpszCurrentDirectory
, *lpdwCurrentDirectory
, NULL
, NULL
);
826 HeapFree(GetProcessHeap(), 0, dir
);
833 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST
*workRequest
)
835 struct WORKREQ_FTPGETCURRENTDIRECTORYW
const *req
= &workRequest
->u
.FtpGetCurrentDirectoryW
;
836 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
838 TRACE("%p\n", lpwfs
);
840 FTP_FtpGetCurrentDirectoryW(lpwfs
, req
->lpszDirectory
, req
->lpdwDirectory
);
843 /***********************************************************************
844 * FtpGetCurrentDirectoryW (WININET.@)
846 * Retrieves the current directory
853 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
854 LPDWORD lpdwCurrentDirectory
)
856 LPWININETFTPSESSIONW lpwfs
;
857 LPWININETAPPINFOW hIC
= NULL
;
860 TRACE("len(%d)\n", *lpdwCurrentDirectory
);
862 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
863 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
865 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
869 hIC
= lpwfs
->lpAppInfo
;
870 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
872 WORKREQUEST workRequest
;
873 struct WORKREQ_FTPGETCURRENTDIRECTORYW
*req
;
875 workRequest
.asyncproc
= AsyncFtpGetCurrentDirectoryProc
;
876 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
877 req
= &workRequest
.u
.FtpGetCurrentDirectoryW
;
878 req
->lpszDirectory
= lpszCurrentDirectory
;
879 req
->lpdwDirectory
= lpdwCurrentDirectory
;
881 r
= INTERNET_AsyncCall(&workRequest
);
885 r
= FTP_FtpGetCurrentDirectoryW(lpwfs
, lpszCurrentDirectory
,
886 lpdwCurrentDirectory
);
891 WININET_Release( &lpwfs
->hdr
);
897 /***********************************************************************
898 * FTP_FtpGetCurrentDirectoryW (Internal)
900 * Retrieves the current directory
907 BOOL WINAPI
FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPWSTR lpszCurrentDirectory
,
908 LPDWORD lpdwCurrentDirectory
)
911 LPWININETAPPINFOW hIC
= NULL
;
912 DWORD bSuccess
= FALSE
;
914 TRACE("len(%d)\n", *lpdwCurrentDirectory
);
916 /* Clear any error information */
917 INTERNET_SetLastError(0);
919 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
921 hIC
= lpwfs
->lpAppInfo
;
922 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
923 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
926 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
929 if (nResCode
== 257) /* Extract directory name */
931 DWORD firstpos
, lastpos
, len
;
932 LPWSTR lpszResponseBuffer
= WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
934 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
936 if ('"' == lpszResponseBuffer
[lastpos
])
945 len
= lastpos
- firstpos
- 1;
946 lstrcpynW(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1], *lpdwCurrentDirectory
);
947 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer
);
948 *lpdwCurrentDirectory
= len
;
952 FTP_SetResponseError(nResCode
);
956 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
958 INTERNET_ASYNC_RESULT iar
;
960 iar
.dwResult
= (DWORD
)bSuccess
;
961 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
962 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
963 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
966 return (DWORD
) bSuccess
;
969 /***********************************************************************
970 * FtpOpenFileA (WININET.@)
972 * Open a remote file for writing or reading
975 * HINTERNET handle on success
979 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
980 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
986 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
987 ret
= FtpOpenFileW(hFtpSession
, lpwzFileName
, fdwAccess
, dwFlags
, dwContext
);
988 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
993 static void AsyncFtpOpenFileProc(WORKREQUEST
*workRequest
)
995 struct WORKREQ_FTPOPENFILEW
const *req
= &workRequest
->u
.FtpOpenFileW
;
996 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
998 TRACE("%p\n", lpwfs
);
1000 FTP_FtpOpenFileW(lpwfs
, req
->lpszFilename
,
1001 req
->dwAccess
, req
->dwFlags
, req
->dwContext
);
1002 HeapFree(GetProcessHeap(), 0, req
->lpszFilename
);
1005 /***********************************************************************
1006 * FtpOpenFileW (WININET.@)
1008 * Open a remote file for writing or reading
1011 * HINTERNET handle on success
1015 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
1016 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
1017 DWORD_PTR dwContext
)
1019 LPWININETFTPSESSIONW lpwfs
;
1020 LPWININETAPPINFOW hIC
= NULL
;
1023 TRACE("(%p,%s,0x%08x,0x%08x,0x%08lx)\n", hFtpSession
,
1024 debugstr_w(lpszFileName
), fdwAccess
, dwFlags
, dwContext
);
1026 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1029 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1033 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1035 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1039 if ((!lpszFileName
) ||
1040 ((fdwAccess
!= GENERIC_READ
) && (fdwAccess
!= GENERIC_WRITE
)) ||
1041 ((dwFlags
& FTP_CONDITION_MASK
) > FTP_TRANSFER_TYPE_BINARY
))
1043 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1047 if (lpwfs
->download_in_progress
!= NULL
) {
1048 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1051 hIC
= lpwfs
->lpAppInfo
;
1052 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1054 WORKREQUEST workRequest
;
1055 struct WORKREQ_FTPOPENFILEW
*req
;
1057 workRequest
.asyncproc
= AsyncFtpOpenFileProc
;
1058 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1059 req
= &workRequest
.u
.FtpOpenFileW
;
1060 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
1061 req
->dwAccess
= fdwAccess
;
1062 req
->dwFlags
= dwFlags
;
1063 req
->dwContext
= dwContext
;
1065 INTERNET_AsyncCall(&workRequest
);
1070 r
= FTP_FtpOpenFileW(lpwfs
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
1074 WININET_Release( &lpwfs
->hdr
);
1080 /***********************************************************************
1081 * FTP_FtpOpenFileW (Internal)
1083 * Open a remote file for writing or reading
1086 * HINTERNET handle on success
1090 HINTERNET
FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs
,
1091 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
1092 DWORD_PTR dwContext
)
1095 BOOL bSuccess
= FALSE
;
1096 LPWININETFTPFILE lpwh
= NULL
;
1097 LPWININETAPPINFOW hIC
= NULL
;
1098 HINTERNET handle
= NULL
;
1102 /* Clear any error information */
1103 INTERNET_SetLastError(0);
1105 if (GENERIC_READ
== fdwAccess
)
1107 /* Set up socket to retrieve data */
1108 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
1110 else if (GENERIC_WRITE
== fdwAccess
)
1112 /* Set up socket to send data */
1113 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
1116 /* Get data socket to server */
1117 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1119 lpwh
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE
));
1120 lpwh
->hdr
.htype
= WH_HFILE
;
1121 lpwh
->hdr
.dwFlags
= dwFlags
;
1122 lpwh
->hdr
.dwContext
= dwContext
;
1123 lpwh
->hdr
.dwRefCount
= 1;
1124 lpwh
->hdr
.close_connection
= NULL
;
1125 lpwh
->hdr
.destroy
= FTP_CloseFileTransferHandle
;
1126 lpwh
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
1127 lpwh
->nDataSocket
= nDataSocket
;
1128 lpwh
->session_deleted
= FALSE
;
1130 WININET_AddRef( &lpwfs
->hdr
);
1131 lpwh
->lpFtpSession
= lpwfs
;
1132 list_add_head( &lpwfs
->hdr
.children
, &lpwh
->hdr
.entry
);
1134 handle
= WININET_AllocHandle( &lpwh
->hdr
);
1138 /* Indicate that a download is currently in progress */
1139 lpwfs
->download_in_progress
= lpwh
;
1142 if (lpwfs
->lstnSocket
!= -1)
1143 closesocket(lpwfs
->lstnSocket
);
1145 hIC
= lpwfs
->lpAppInfo
;
1146 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1148 INTERNET_ASYNC_RESULT iar
;
1152 iar
.dwResult
= (DWORD
)handle
;
1153 iar
.dwError
= ERROR_SUCCESS
;
1154 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1155 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1158 iar
.dwResult
= (DWORD
)bSuccess
;
1159 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1160 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1161 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1166 WININET_Release( &lpwh
->hdr
);
1172 /***********************************************************************
1173 * FtpGetFileA (WININET.@)
1175 * Retrieve file from the FTP server
1182 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1183 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1184 DWORD_PTR dwContext
)
1186 LPWSTR lpwzRemoteFile
;
1190 lpwzRemoteFile
= lpszRemoteFile
?WININET_strdup_AtoW(lpszRemoteFile
):NULL
;
1191 lpwzNewFile
= lpszNewFile
?WININET_strdup_AtoW(lpszNewFile
):NULL
;
1192 ret
= FtpGetFileW(hInternet
, lpwzRemoteFile
, lpwzNewFile
, fFailIfExists
,
1193 dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1194 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile
);
1195 HeapFree(GetProcessHeap(), 0, lpwzNewFile
);
1200 static void AsyncFtpGetFileProc(WORKREQUEST
*workRequest
)
1202 struct WORKREQ_FTPGETFILEW
const *req
= &workRequest
->u
.FtpGetFileW
;
1203 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1205 TRACE("%p\n", lpwfs
);
1207 FTP_FtpGetFileW(lpwfs
, req
->lpszRemoteFile
,
1208 req
->lpszNewFile
, req
->fFailIfExists
,
1209 req
->dwLocalFlagsAttribute
, req
->dwFlags
, req
->dwContext
);
1210 HeapFree(GetProcessHeap(), 0, req
->lpszRemoteFile
);
1211 HeapFree(GetProcessHeap(), 0, req
->lpszNewFile
);
1215 /***********************************************************************
1216 * FtpGetFileW (WININET.@)
1218 * Retrieve file from the FTP server
1225 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1226 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1227 DWORD_PTR dwContext
)
1229 LPWININETFTPSESSIONW lpwfs
;
1230 LPWININETAPPINFOW hIC
= NULL
;
1233 if (!lpszRemoteFile
|| !lpszNewFile
)
1235 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1239 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hInternet
);
1242 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1246 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1248 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1252 if ((dwInternetFlags
& FTP_CONDITION_MASK
) > FTP_TRANSFER_TYPE_BINARY
)
1254 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1258 if (lpwfs
->download_in_progress
!= NULL
) {
1259 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1263 hIC
= lpwfs
->lpAppInfo
;
1264 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1266 WORKREQUEST workRequest
;
1267 struct WORKREQ_FTPGETFILEW
*req
;
1269 workRequest
.asyncproc
= AsyncFtpGetFileProc
;
1270 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1271 req
= &workRequest
.u
.FtpGetFileW
;
1272 req
->lpszRemoteFile
= WININET_strdupW(lpszRemoteFile
);
1273 req
->lpszNewFile
= WININET_strdupW(lpszNewFile
);
1274 req
->dwLocalFlagsAttribute
= dwLocalFlagsAttribute
;
1275 req
->fFailIfExists
= fFailIfExists
;
1276 req
->dwFlags
= dwInternetFlags
;
1277 req
->dwContext
= dwContext
;
1279 r
= INTERNET_AsyncCall(&workRequest
);
1283 r
= FTP_FtpGetFileW(lpwfs
, lpszRemoteFile
, lpszNewFile
,
1284 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1288 WININET_Release( &lpwfs
->hdr
);
1294 /***********************************************************************
1295 * FTP_FtpGetFileW (Internal)
1297 * Retrieve file from the FTP server
1304 BOOL WINAPI
FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1305 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1306 DWORD_PTR dwContext
)
1308 BOOL bSuccess
= FALSE
;
1310 LPWININETAPPINFOW hIC
= NULL
;
1312 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile
), debugstr_w(lpszNewFile
));
1314 /* Clear any error information */
1315 INTERNET_SetLastError(0);
1317 /* Ensure we can write to lpszNewfile by opening it */
1318 hFile
= CreateFileW(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1319 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1320 if (INVALID_HANDLE_VALUE
== hFile
)
1323 /* Set up socket to retrieve data */
1324 if (FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
))
1328 /* Get data socket to server */
1329 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1334 FTP_RetrieveFileData(lpwfs
, nDataSocket
, hFile
);
1335 nResCode
= FTP_ReceiveResponse(lpwfs
, dwContext
);
1338 if (nResCode
== 226)
1341 FTP_SetResponseError(nResCode
);
1343 closesocket(nDataSocket
);
1347 if (lpwfs
->lstnSocket
!= -1)
1348 closesocket(lpwfs
->lstnSocket
);
1352 hIC
= lpwfs
->lpAppInfo
;
1353 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1355 INTERNET_ASYNC_RESULT iar
;
1357 iar
.dwResult
= (DWORD
)bSuccess
;
1358 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1359 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1360 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1366 /***********************************************************************
1367 * FtpGetFileSize (WININET.@)
1369 DWORD WINAPI
FtpGetFileSize( HINTERNET hFile
, LPDWORD lpdwFileSizeHigh
)
1371 FIXME("(%p, %p)\n", hFile
, lpdwFileSizeHigh
);
1373 if (lpdwFileSizeHigh
)
1374 *lpdwFileSizeHigh
= 0;
1379 /***********************************************************************
1380 * FtpDeleteFileA (WININET.@)
1382 * Delete a file on the ftp server
1389 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1391 LPWSTR lpwzFileName
;
1394 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
1395 ret
= FtpDeleteFileW(hFtpSession
, lpwzFileName
);
1396 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
1400 static void AsyncFtpDeleteFileProc(WORKREQUEST
*workRequest
)
1402 struct WORKREQ_FTPDELETEFILEW
const *req
= &workRequest
->u
.FtpDeleteFileW
;
1403 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1405 TRACE("%p\n", lpwfs
);
1407 FTP_FtpDeleteFileW(lpwfs
, req
->lpszFilename
);
1408 HeapFree(GetProcessHeap(), 0, req
->lpszFilename
);
1411 /***********************************************************************
1412 * FtpDeleteFileW (WININET.@)
1414 * Delete a file on the ftp server
1421 BOOL WINAPI
FtpDeleteFileW(HINTERNET hFtpSession
, LPCWSTR lpszFileName
)
1423 LPWININETFTPSESSIONW lpwfs
;
1424 LPWININETAPPINFOW hIC
= NULL
;
1427 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1430 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1434 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1436 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1442 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1446 hIC
= lpwfs
->lpAppInfo
;
1447 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1449 WORKREQUEST workRequest
;
1450 struct WORKREQ_FTPDELETEFILEW
*req
;
1452 workRequest
.asyncproc
= AsyncFtpDeleteFileProc
;
1453 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1454 req
= &workRequest
.u
.FtpDeleteFileW
;
1455 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
1457 r
= INTERNET_AsyncCall(&workRequest
);
1461 r
= FTP_FtpDeleteFileW(lpwfs
, lpszFileName
);
1465 WININET_Release( &lpwfs
->hdr
);
1470 /***********************************************************************
1471 * FTP_FtpDeleteFileW (Internal)
1473 * Delete a file on the ftp server
1480 BOOL
FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszFileName
)
1483 BOOL bSuccess
= FALSE
;
1484 LPWININETAPPINFOW hIC
= NULL
;
1486 TRACE("%p\n", lpwfs
);
1488 /* Clear any error information */
1489 INTERNET_SetLastError(0);
1491 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1494 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1497 if (nResCode
== 250)
1500 FTP_SetResponseError(nResCode
);
1503 hIC
= lpwfs
->lpAppInfo
;
1504 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1506 INTERNET_ASYNC_RESULT iar
;
1508 iar
.dwResult
= (DWORD
)bSuccess
;
1509 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1510 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1511 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1518 /***********************************************************************
1519 * FtpRemoveDirectoryA (WININET.@)
1521 * Remove a directory on the ftp server
1528 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1530 LPWSTR lpwzDirectory
;
1533 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
1534 ret
= FtpRemoveDirectoryW(hFtpSession
, lpwzDirectory
);
1535 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
1539 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST
*workRequest
)
1541 struct WORKREQ_FTPREMOVEDIRECTORYW
const *req
= &workRequest
->u
.FtpRemoveDirectoryW
;
1542 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1544 TRACE("%p\n", lpwfs
);
1546 FTP_FtpRemoveDirectoryW(lpwfs
, req
->lpszDirectory
);
1547 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
1550 /***********************************************************************
1551 * FtpRemoveDirectoryW (WININET.@)
1553 * Remove a directory on the ftp server
1560 BOOL WINAPI
FtpRemoveDirectoryW(HINTERNET hFtpSession
, LPCWSTR lpszDirectory
)
1562 LPWININETFTPSESSIONW lpwfs
;
1563 LPWININETAPPINFOW hIC
= NULL
;
1566 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1569 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1573 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1575 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1581 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1585 hIC
= lpwfs
->lpAppInfo
;
1586 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1588 WORKREQUEST workRequest
;
1589 struct WORKREQ_FTPREMOVEDIRECTORYW
*req
;
1591 workRequest
.asyncproc
= AsyncFtpRemoveDirectoryProc
;
1592 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1593 req
= &workRequest
.u
.FtpRemoveDirectoryW
;
1594 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
1596 r
= INTERNET_AsyncCall(&workRequest
);
1600 r
= FTP_FtpRemoveDirectoryW(lpwfs
, lpszDirectory
);
1604 WININET_Release( &lpwfs
->hdr
);
1609 /***********************************************************************
1610 * FTP_FtpRemoveDirectoryW (Internal)
1612 * Remove a directory on the ftp server
1619 BOOL
FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
1622 BOOL bSuccess
= FALSE
;
1623 LPWININETAPPINFOW hIC
= NULL
;
1627 /* Clear any error information */
1628 INTERNET_SetLastError(0);
1630 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1633 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1636 if (nResCode
== 250)
1639 FTP_SetResponseError(nResCode
);
1643 hIC
= lpwfs
->lpAppInfo
;
1644 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1646 INTERNET_ASYNC_RESULT iar
;
1648 iar
.dwResult
= (DWORD
)bSuccess
;
1649 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1650 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1651 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1658 /***********************************************************************
1659 * FtpRenameFileA (WININET.@)
1661 * Rename a file on the ftp server
1668 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1674 lpwzSrc
= lpszSrc
?WININET_strdup_AtoW(lpszSrc
):NULL
;
1675 lpwzDest
= lpszDest
?WININET_strdup_AtoW(lpszDest
):NULL
;
1676 ret
= FtpRenameFileW(hFtpSession
, lpwzSrc
, lpwzDest
);
1677 HeapFree(GetProcessHeap(), 0, lpwzSrc
);
1678 HeapFree(GetProcessHeap(), 0, lpwzDest
);
1682 static void AsyncFtpRenameFileProc(WORKREQUEST
*workRequest
)
1684 struct WORKREQ_FTPRENAMEFILEW
const *req
= &workRequest
->u
.FtpRenameFileW
;
1685 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1687 TRACE("%p\n", lpwfs
);
1689 FTP_FtpRenameFileW(lpwfs
, req
->lpszSrcFile
, req
->lpszDestFile
);
1690 HeapFree(GetProcessHeap(), 0, req
->lpszSrcFile
);
1691 HeapFree(GetProcessHeap(), 0, req
->lpszDestFile
);
1694 /***********************************************************************
1695 * FtpRenameFileW (WININET.@)
1697 * Rename a file on the ftp server
1704 BOOL WINAPI
FtpRenameFileW(HINTERNET hFtpSession
, LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1706 LPWININETFTPSESSIONW lpwfs
;
1707 LPWININETAPPINFOW hIC
= NULL
;
1710 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1713 INTERNET_SetLastError(ERROR_INVALID_HANDLE
);
1717 if (WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1719 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1723 if (!lpszSrc
|| !lpszDest
)
1725 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1729 hIC
= lpwfs
->lpAppInfo
;
1730 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1732 WORKREQUEST workRequest
;
1733 struct WORKREQ_FTPRENAMEFILEW
*req
;
1735 workRequest
.asyncproc
= AsyncFtpRenameFileProc
;
1736 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1737 req
= &workRequest
.u
.FtpRenameFileW
;
1738 req
->lpszSrcFile
= WININET_strdupW(lpszSrc
);
1739 req
->lpszDestFile
= WININET_strdupW(lpszDest
);
1741 r
= INTERNET_AsyncCall(&workRequest
);
1745 r
= FTP_FtpRenameFileW(lpwfs
, lpszSrc
, lpszDest
);
1749 WININET_Release( &lpwfs
->hdr
);
1754 /***********************************************************************
1755 * FTP_FtpRenameFileW (Internal)
1757 * Rename a file on the ftp server
1764 BOOL
FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs
,
1765 LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1768 BOOL bSuccess
= FALSE
;
1769 LPWININETAPPINFOW hIC
= NULL
;
1773 /* Clear any error information */
1774 INTERNET_SetLastError(0);
1776 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1779 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1780 if (nResCode
== 350)
1782 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1785 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1788 if (nResCode
== 250)
1791 FTP_SetResponseError(nResCode
);
1794 hIC
= lpwfs
->lpAppInfo
;
1795 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1797 INTERNET_ASYNC_RESULT iar
;
1799 iar
.dwResult
= (DWORD
)bSuccess
;
1800 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1801 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1802 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1808 /***********************************************************************
1809 * FtpCommandA (WININET.@)
1811 BOOL WINAPI
FtpCommandA( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1812 LPCSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1814 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1815 debugstr_a(lpszCommand
), dwContext
, phFtpCommand
);
1820 /***********************************************************************
1821 * FtpCommandW (WININET.@)
1823 BOOL WINAPI
FtpCommandW( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1824 LPCWSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1826 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1827 debugstr_w(lpszCommand
), dwContext
, phFtpCommand
);
1832 /***********************************************************************
1833 * FTP_Connect (internal)
1835 * Connect to a ftp server
1838 * HINTERNET a session handle on success
1843 * Windows uses 'anonymous' as the username, when given a NULL username
1844 * and a NULL password. The password is first looked up in:
1846 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1848 * If this entry is not present it uses the current username as the password.
1852 HINTERNET
FTP_Connect(LPWININETAPPINFOW hIC
, LPCWSTR lpszServerName
,
1853 INTERNET_PORT nServerPort
, LPCWSTR lpszUserName
,
1854 LPCWSTR lpszPassword
, DWORD dwFlags
, DWORD_PTR dwContext
,
1855 DWORD dwInternalFlags
)
1857 static const WCHAR szKey
[] = {'S','o','f','t','w','a','r','e','\\',
1858 'M','i','c','r','o','s','o','f','t','\\',
1859 'W','i','n','d','o','w','s','\\',
1860 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1861 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1862 static const WCHAR szValue
[] = {'E','m','a','i','l','N','a','m','e',0};
1863 static const WCHAR szDefaultUsername
[] = {'a','n','o','n','y','m','o','u','s','\0'};
1864 static const WCHAR szEmpty
[] = {'\0'};
1865 struct sockaddr_in socketAddr
;
1868 BOOL bSuccess
= FALSE
;
1869 LPWININETFTPSESSIONW lpwfs
= NULL
;
1870 HINTERNET handle
= NULL
;
1872 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1873 hIC
, debugstr_w(lpszServerName
),
1874 nServerPort
, debugstr_w(lpszUserName
), debugstr_w(lpszPassword
));
1876 assert( hIC
->hdr
.htype
== WH_HINIT
);
1878 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1880 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1884 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW
));
1887 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1891 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1892 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1894 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1895 lpwfs
->hdr
.dwFlags
= dwFlags
;
1896 lpwfs
->hdr
.dwContext
= dwContext
;
1897 lpwfs
->hdr
.dwInternalFlags
= dwInternalFlags
;
1898 lpwfs
->hdr
.dwRefCount
= 1;
1899 lpwfs
->hdr
.close_connection
= FTP_CloseConnection
;
1900 lpwfs
->hdr
.destroy
= FTP_CloseSessionHandle
;
1901 lpwfs
->hdr
.lpfnStatusCB
= hIC
->hdr
.lpfnStatusCB
;
1902 lpwfs
->download_in_progress
= NULL
;
1904 WININET_AddRef( &hIC
->hdr
);
1905 lpwfs
->lpAppInfo
= hIC
;
1906 list_add_head( &hIC
->hdr
.children
, &lpwfs
->hdr
.entry
);
1908 handle
= WININET_AllocHandle( &lpwfs
->hdr
);
1911 ERR("Failed to alloc handle\n");
1912 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1916 if(hIC
->lpszProxy
&& hIC
->dwAccessType
== INTERNET_OPEN_TYPE_PROXY
) {
1917 if(strchrW(hIC
->lpszProxy
, ' '))
1918 FIXME("Several proxies not implemented.\n");
1919 if(hIC
->lpszProxyBypass
)
1920 FIXME("Proxy bypass is ignored.\n");
1922 if ( !lpszUserName
) {
1924 WCHAR szPassword
[MAX_PATH
];
1925 DWORD len
= sizeof(szPassword
);
1927 lpwfs
->lpszUserName
= WININET_strdupW(szDefaultUsername
);
1929 RegOpenKeyW(HKEY_CURRENT_USER
, szKey
, &key
);
1930 if (RegQueryValueExW(key
, szValue
, NULL
, NULL
, (LPBYTE
)szPassword
, &len
)) {
1931 /* Nothing in the registry, get the username and use that as the password */
1932 if (!GetUserNameW(szPassword
, &len
)) {
1933 /* Should never get here, but use an empty password as failsafe */
1934 strcpyW(szPassword
, szEmpty
);
1939 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword
));
1940 lpwfs
->lpszPassword
= WININET_strdupW(szPassword
);
1943 lpwfs
->lpszUserName
= WININET_strdupW(lpszUserName
);
1946 lpwfs
->lpszPassword
= WININET_strdupW(lpszPassword
);
1948 lpwfs
->lpszPassword
= WININET_strdupW(szEmpty
);
1951 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1952 if (!(lpwfs
->hdr
.dwInternalFlags
& INET_OPENURL
))
1954 INTERNET_ASYNC_RESULT iar
;
1956 iar
.dwResult
= (DWORD
)handle
;
1957 iar
.dwError
= ERROR_SUCCESS
;
1959 SendAsyncCallback(&hIC
->hdr
, dwContext
,
1960 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
1961 sizeof(INTERNET_ASYNC_RESULT
));
1964 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1965 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1967 if (!GetAddress(lpszServerName
, nServerPort
, &socketAddr
))
1969 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1973 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1974 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1976 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1979 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1983 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1984 &socketAddr
, sizeof(struct sockaddr_in
));
1986 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1988 ERR("Unable to connect (%s)\n", strerror(errno
));
1989 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1993 TRACE("Connected to server\n");
1994 lpwfs
->sndSocket
= nsocket
;
1995 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1996 &socketAddr
, sizeof(struct sockaddr_in
));
1998 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1999 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
2001 if (FTP_ConnectToHost(lpwfs
))
2003 TRACE("Successfully logged into server\n");
2009 if (lpwfs
) WININET_Release( &lpwfs
->hdr
);
2011 if (!bSuccess
&& handle
)
2013 WININET_Release( &hIC
->hdr
);
2014 WININET_FreeHandle( handle
);
2018 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
2020 INTERNET_ASYNC_RESULT iar
;
2022 iar
.dwResult
= bSuccess
? (DWORD_PTR
)lpwfs
: 0;
2023 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
2024 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
2025 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
2032 /***********************************************************************
2033 * FTP_ConnectToHost (internal)
2035 * Connect to a ftp server
2042 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
)
2045 BOOL bSuccess
= FALSE
;
2048 FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2050 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
2053 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2056 /* Login successful... */
2057 if (nResCode
== 230)
2059 /* User name okay, need password... */
2060 else if (nResCode
== 331)
2061 bSuccess
= FTP_SendPassword(lpwfs
);
2062 /* Need account for login... */
2063 else if (nResCode
== 332)
2064 bSuccess
= FTP_SendAccount(lpwfs
);
2066 FTP_SetResponseError(nResCode
);
2069 TRACE("Returning %d\n", bSuccess
);
2075 /***********************************************************************
2076 * FTP_SendCommandA (internal)
2078 * Send command to server
2085 static BOOL
FTP_SendCommandA(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
2086 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD_PTR dwContext
)
2090 DWORD nBytesSent
= 0;
2094 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
2098 lpfnStatusCB(hdr
->hInternet
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
2101 dwParamLen
= lpszParam
?strlen(lpszParam
)+1:0;
2102 len
= dwParamLen
+ strlen(szFtpCommands
[ftpCmd
]) + strlen(szCRLF
);
2103 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
2105 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2108 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], dwParamLen
? " " : "",
2109 dwParamLen
? lpszParam
: "", szCRLF
);
2111 TRACE("Sending (%s) len(%d)\n", buf
, len
);
2112 while((nBytesSent
< len
) && (nRC
!= -1))
2114 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
2118 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
2122 lpfnStatusCB(hdr
->hInternet
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
2123 &nBytesSent
, sizeof(DWORD
));
2126 TRACE("Sent %d bytes\n", nBytesSent
);
2130 /***********************************************************************
2131 * FTP_SendCommand (internal)
2133 * Send command to server
2140 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
2141 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD_PTR dwContext
)
2144 LPSTR lpszParamA
= lpszParam
?WININET_strdup_WtoA(lpszParam
):NULL
;
2145 ret
= FTP_SendCommandA(nSocket
, ftpCmd
, lpszParamA
, lpfnStatusCB
, hdr
, dwContext
);
2146 HeapFree(GetProcessHeap(), 0, lpszParamA
);
2150 /***********************************************************************
2151 * FTP_ReceiveResponse (internal)
2153 * Receive response from server
2156 * Reply code on success
2160 INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD_PTR dwContext
)
2162 LPSTR lpszResponse
= INTERNET_GetResponseBuffer();
2165 char firstprefix
[5];
2166 BOOL multiline
= FALSE
;
2167 LPWININETAPPINFOW hIC
= NULL
;
2169 TRACE("socket(%d)\n", lpwfs
->sndSocket
);
2171 hIC
= lpwfs
->lpAppInfo
;
2172 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
2176 if (!INTERNET_GetNextLine(lpwfs
->sndSocket
, &nRecv
))
2183 if(lpszResponse
[3] != '-')
2186 { /* Start of multiline repsonse. Loop until we get "nnn " */
2188 memcpy(firstprefix
, lpszResponse
, 3);
2189 firstprefix
[3] = ' ';
2190 firstprefix
[4] = '\0';
2195 if(!memcmp(firstprefix
, lpszResponse
, 4))
2203 rc
= atoi(lpszResponse
);
2205 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
2206 &nRecv
, sizeof(DWORD
));
2210 TRACE("return %d\n", rc
);
2215 /***********************************************************************
2216 * FTP_SendPassword (internal)
2218 * Send password to ftp server
2225 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
)
2228 BOOL bSuccess
= FALSE
;
2231 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
2234 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2237 TRACE("Received reply code %d\n", nResCode
);
2238 /* Login successful... */
2239 if (nResCode
== 230)
2241 /* Command not implemented, superfluous at the server site... */
2242 /* Need account for login... */
2243 else if (nResCode
== 332)
2244 bSuccess
= FTP_SendAccount(lpwfs
);
2246 FTP_SetResponseError(nResCode
);
2250 TRACE("Returning %d\n", bSuccess
);
2255 /***********************************************************************
2256 * FTP_SendAccount (internal)
2265 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
)
2268 BOOL bSuccess
= FALSE
;
2271 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, szNoAccount
, 0, 0, 0))
2274 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2278 FTP_SetResponseError(nResCode
);
2285 /***********************************************************************
2286 * FTP_SendStore (internal)
2288 * Send request to upload file to ftp server
2295 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2298 BOOL bSuccess
= FALSE
;
2301 if (!FTP_InitListenSocket(lpwfs
))
2304 if (!FTP_SendType(lpwfs
, dwType
))
2307 if (!FTP_SendPortOrPasv(lpwfs
))
2310 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
2312 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2315 if (nResCode
== 150 || nResCode
== 125)
2318 FTP_SetResponseError(nResCode
);
2322 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
2324 closesocket(lpwfs
->lstnSocket
);
2325 lpwfs
->lstnSocket
= -1;
2332 /***********************************************************************
2333 * FTP_InitListenSocket (internal)
2335 * Create a socket to listen for server response
2342 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
)
2344 BOOL bSuccess
= FALSE
;
2345 socklen_t namelen
= sizeof(struct sockaddr_in
);
2349 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
2350 if (lpwfs
->lstnSocket
== -1)
2352 TRACE("Unable to create listening socket\n");
2356 /* We obtain our ip addr from the name of the command channel socket */
2357 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
2359 /* and get the system to assign us a port */
2360 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
2362 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
2364 TRACE("Unable to bind socket\n");
2368 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
2370 TRACE("listen failed\n");
2374 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
2378 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
2380 closesocket(lpwfs
->lstnSocket
);
2381 lpwfs
->lstnSocket
= -1;
2388 /***********************************************************************
2389 * FTP_SendType (internal)
2391 * Tell server type of data being transferred
2397 * W98SE doesn't cache the type that's currently set
2398 * (i.e. it sends it always),
2399 * so we probably don't want to do that either.
2401 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
)
2404 WCHAR type
[] = { 'I','\0' };
2405 BOOL bSuccess
= FALSE
;
2408 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
2411 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
2414 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
)/100;
2420 FTP_SetResponseError(nResCode
);
2428 #if 0 /* FIXME: should probably be used for FtpGetFileSize */
2429 /***********************************************************************
2430 * FTP_GetFileSize (internal)
2432 * Retrieves from the server the size of the given file
2439 static BOOL
FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD
*dwSize
)
2442 BOOL bSuccess
= FALSE
;
2446 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
2449 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2452 if (nResCode
== 213) {
2453 /* Now parses the output to get the actual file size */
2455 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2457 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
2458 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
2459 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2463 FTP_SetResponseError(nResCode
);
2473 /***********************************************************************
2474 * FTP_SendPort (internal)
2476 * Tell server which port to use
2483 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
)
2485 static const WCHAR szIPFormat
[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2487 WCHAR szIPAddress
[64];
2488 BOOL bSuccess
= FALSE
;
2491 sprintfW(szIPAddress
, szIPFormat
,
2492 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2493 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2494 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2495 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2496 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2497 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2499 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2502 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2505 if (nResCode
== 200)
2508 FTP_SetResponseError(nResCode
);
2516 /***********************************************************************
2517 * FTP_DoPassive (internal)
2519 * Tell server that we want to do passive transfers
2520 * and connect data socket
2527 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
)
2530 BOOL bSuccess
= FALSE
;
2533 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2536 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2539 if (nResCode
== 227)
2541 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2545 char *pAddr
, *pPort
;
2547 struct sockaddr_in dataSocketAddress
;
2549 p
= lpszResponseBuffer
+4; /* skip status code */
2550 while (*p
!= '\0' && (*p
< '0' || *p
> '9')) p
++;
2554 ERR("no address found in response, aborting\n");
2558 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2561 ERR("unknown response address format '%s', aborting\n", p
);
2564 for (i
=0; i
< 6; i
++)
2567 dataSocketAddress
= lpwfs
->socketAddress
;
2568 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2569 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2577 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2581 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2583 ERR("can't connect passive FTP data port.\n");
2584 closesocket(nsocket
);
2587 lpwfs
->pasvSocket
= nsocket
;
2591 FTP_SetResponseError(nResCode
);
2599 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
)
2601 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2603 if (!FTP_DoPassive(lpwfs
))
2608 if (!FTP_SendPort(lpwfs
))
2615 /***********************************************************************
2616 * FTP_GetDataSocket (internal)
2618 * Either accepts an incoming data socket connection from the server
2619 * or just returns the already opened socket after a PASV command
2620 * in case of passive FTP.
2628 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
)
2630 struct sockaddr_in saddr
;
2631 socklen_t addrlen
= sizeof(struct sockaddr
);
2634 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2636 *nDataSocket
= lpwfs
->pasvSocket
;
2640 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2641 closesocket(lpwfs
->lstnSocket
);
2642 lpwfs
->lstnSocket
= -1;
2644 return *nDataSocket
!= -1;
2648 /***********************************************************************
2649 * FTP_SendData (internal)
2651 * Send data to the server
2658 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
)
2660 BY_HANDLE_FILE_INFORMATION fi
;
2661 DWORD nBytesRead
= 0;
2662 DWORD nBytesSent
= 0;
2663 DWORD nTotalSent
= 0;
2664 DWORD nBytesToSend
, nLen
;
2666 time_t s_long_time
, e_long_time
;
2671 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2673 /* Get the size of the file. */
2674 GetFileInformationByHandle(hFile
, &fi
);
2679 nBytesToSend
= nBytesRead
- nBytesSent
;
2681 if (nBytesToSend
<= 0)
2683 /* Read data from file. */
2685 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2686 ERR("Failed reading from file\n");
2689 nBytesToSend
= nBytesRead
;
2694 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2695 DATA_PACKET_SIZE
: nBytesToSend
;
2696 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2704 /* Do some computation to display the status. */
2706 nSeconds
= e_long_time
- s_long_time
;
2707 if( nSeconds
/ 60 > 0 )
2709 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2710 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2711 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2715 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2716 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2717 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2719 } while (nRC
!= -1);
2721 TRACE("file transfer complete!\n");
2723 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2729 /***********************************************************************
2730 * FTP_SendRetrieve (internal)
2732 * Send request to retrieve a file
2735 * Number of bytes to be received on success
2739 static BOOL
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2745 if (!(ret
= FTP_InitListenSocket(lpwfs
)))
2748 if (!(ret
= FTP_SendType(lpwfs
, dwType
)))
2751 if (!(ret
= FTP_SendPortOrPasv(lpwfs
)))
2754 if (!(ret
= FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0)))
2757 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2758 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2759 /* That means that we got an error getting the file. */
2760 FTP_SetResponseError(nResCode
);
2765 if (!ret
&& lpwfs
->lstnSocket
!= -1)
2767 closesocket(lpwfs
->lstnSocket
);
2768 lpwfs
->lstnSocket
= -1;
2775 /***********************************************************************
2776 * FTP_RetrieveData (internal)
2778 * Retrieve data from server
2785 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
)
2787 DWORD nBytesWritten
;
2788 DWORD nBytesReceived
= 0;
2794 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2795 if (NULL
== lpszBuffer
)
2797 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2803 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2806 /* other side closed socket. */
2809 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2810 nBytesReceived
+= nRC
;
2814 TRACE("Data transfer complete\n");
2817 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2822 /***********************************************************************
2823 * FTP_CloseConnection (internal)
2827 static void FTP_CloseConnection(LPWININETHANDLEHEADER hdr
)
2829 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) hdr
;
2833 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
,
2834 INTERNET_STATUS_CLOSING_CONNECTION
, 0, 0);
2836 if (lpwfs
->download_in_progress
!= NULL
)
2837 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2839 if (lpwfs
->sndSocket
!= -1)
2840 closesocket(lpwfs
->sndSocket
);
2842 if (lpwfs
->lstnSocket
!= -1)
2843 closesocket(lpwfs
->lstnSocket
);
2845 if (lpwfs
->pasvSocket
!= -1)
2846 closesocket(lpwfs
->pasvSocket
);
2848 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
,
2849 INTERNET_STATUS_CONNECTION_CLOSED
, 0, 0);
2853 /***********************************************************************
2854 * FTP_CloseSessionHandle (internal)
2856 * Deallocate session handle
2858 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
)
2860 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) hdr
;
2864 WININET_Release(&lpwfs
->lpAppInfo
->hdr
);
2866 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2867 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2868 HeapFree(GetProcessHeap(), 0, lpwfs
);
2872 /***********************************************************************
2873 * FTP_FindNextFileW (Internal)
2875 * Continues a file search from a previous call to FindFirstFile
2882 BOOL WINAPI
FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh
, LPVOID lpvFindData
)
2884 BOOL bSuccess
= TRUE
;
2885 LPWIN32_FIND_DATAW lpFindFileData
;
2887 TRACE("index(%d) size(%d)\n", lpwh
->index
, lpwh
->size
);
2889 assert (lpwh
->hdr
.htype
== WH_HFTPFINDNEXT
);
2891 /* Clear any error information */
2892 INTERNET_SetLastError(0);
2894 lpFindFileData
= (LPWIN32_FIND_DATAW
) lpvFindData
;
2895 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2897 if (lpwh
->index
>= lpwh
->size
)
2899 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2904 FTP_ConvertFileProp(&lpwh
->lpafp
[lpwh
->index
], lpFindFileData
);
2907 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData
->cFileName
), lpFindFileData
->nFileSizeLow
);
2911 if (lpwh
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
2913 INTERNET_ASYNC_RESULT iar
;
2915 iar
.dwResult
= (DWORD
)bSuccess
;
2916 iar
.dwError
= iar
.dwError
= bSuccess
? ERROR_SUCCESS
:
2917 INTERNET_GetLastError();
2919 INTERNET_SendCallback(&lpwh
->hdr
, lpwh
->hdr
.dwContext
,
2920 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
2921 sizeof(INTERNET_ASYNC_RESULT
));
2928 /***********************************************************************
2929 * FTP_CloseFindNextHandle (internal)
2931 * Deallocate session handle
2938 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
)
2940 LPWININETFTPFINDNEXTW lpwfn
= (LPWININETFTPFINDNEXTW
) hdr
;
2945 WININET_Release(&lpwfn
->lpFtpSession
->hdr
);
2947 for (i
= 0; i
< lpwfn
->size
; i
++)
2949 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2952 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2953 HeapFree(GetProcessHeap(), 0, lpwfn
);
2956 /***********************************************************************
2957 * FTP_CloseFileTransferHandle (internal)
2959 * Closes the file transfer handle. This also 'cleans' the data queue of
2960 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2963 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
)
2965 LPWININETFTPFILE lpwh
= (LPWININETFTPFILE
) hdr
;
2966 LPWININETFTPSESSIONW lpwfs
= lpwh
->lpFtpSession
;
2971 WININET_Release(&lpwh
->lpFtpSession
->hdr
);
2973 if (!lpwh
->session_deleted
)
2974 lpwfs
->download_in_progress
= NULL
;
2976 /* This just serves to flush the control socket of any spurrious lines written
2977 to it (like '226 Transfer complete.').
2979 Wonder what to do if the server sends us an error code though...
2981 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2983 if (lpwh
->nDataSocket
!= -1)
2984 closesocket(lpwh
->nDataSocket
);
2986 HeapFree(GetProcessHeap(), 0, lpwh
);
2989 /***********************************************************************
2990 * FTP_ReceiveFileList (internal)
2992 * Read file list from server
2995 * Handle to file list on success
2999 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
3000 LPWIN32_FIND_DATAW lpFindFileData
, DWORD_PTR dwContext
)
3003 LPFILEPROPERTIESW lpafp
= NULL
;
3004 LPWININETFTPFINDNEXTW lpwfn
= NULL
;
3005 HINTERNET handle
= 0;
3007 TRACE("(%p,%d,%s,%p,%08lx)\n", lpwfs
, nSocket
, debugstr_w(lpszSearchFile
), lpFindFileData
, dwContext
);
3009 if (FTP_ParseDirectory(lpwfs
, nSocket
, lpszSearchFile
, &lpafp
, &dwSize
))
3012 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
3014 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFTPFINDNEXTW
));
3017 lpwfn
->hdr
.htype
= WH_HFTPFINDNEXT
;
3018 lpwfn
->hdr
.dwContext
= dwContext
;
3019 lpwfn
->hdr
.dwRefCount
= 1;
3020 lpwfn
->hdr
.close_connection
= NULL
;
3021 lpwfn
->hdr
.destroy
= FTP_CloseFindNextHandle
;
3022 lpwfn
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
3023 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
3024 lpwfn
->size
= dwSize
;
3025 lpwfn
->lpafp
= lpafp
;
3027 WININET_AddRef( &lpwfs
->hdr
);
3028 lpwfn
->lpFtpSession
= lpwfs
;
3029 list_add_head( &lpwfs
->hdr
.children
, &lpwfn
->hdr
.entry
);
3031 handle
= WININET_AllocHandle( &lpwfn
->hdr
);
3036 WININET_Release( &lpwfn
->hdr
);
3038 TRACE("Matched %d files\n", dwSize
);
3043 /***********************************************************************
3044 * FTP_ConvertFileProp (internal)
3046 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
3053 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp
, LPWIN32_FIND_DATAW lpFindFileData
)
3055 BOOL bSuccess
= FALSE
;
3057 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAW
));
3061 /* Convert 'Unix' time to Windows time */
3062 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
3063 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
3064 lpFindFileData
->ftLastWriteTime
= lpFindFileData
->ftLastAccessTime
;
3065 lpFindFileData
->ftCreationTime
= lpFindFileData
->ftLastAccessTime
;
3067 /* Not all fields are filled in */
3068 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3069 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
3071 if (lpafp
->bIsDirectory
)
3072 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
3074 if (lpafp
->lpszName
)
3075 lstrcpynW(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
3083 /***********************************************************************
3084 * FTP_ParseNextFile (internal)
3086 * Parse the next line in file listing
3092 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW lpfp
)
3094 static const char szSpace
[] = " \t";
3102 lpfp
->lpszName
= NULL
;
3104 if(!(pszLine
= INTERNET_GetNextLine(nSocket
, &nBufLen
)))
3107 pszToken
= strtok(pszLine
, szSpace
);
3109 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3112 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3114 if(!isdigit(pszToken
[0]) && 10 == strlen(pszToken
)) {
3115 if(!FTP_ParsePermission(pszToken
, lpfp
))
3116 lpfp
->bIsDirectory
= FALSE
;
3117 for(i
=0; i
<=3; i
++) {
3118 if(!(pszToken
= strtok(NULL
, szSpace
)))
3121 if(!pszToken
) continue;
3122 if(lpfp
->bIsDirectory
) {
3123 TRACE("Is directory\n");
3127 TRACE("Size: %s\n", pszToken
);
3128 lpfp
->nSize
= atol(pszToken
);
3131 lpfp
->tmLastModified
.tm_sec
= 0;
3132 lpfp
->tmLastModified
.tm_min
= 0;
3133 lpfp
->tmLastModified
.tm_hour
= 0;
3134 lpfp
->tmLastModified
.tm_mday
= 0;
3135 lpfp
->tmLastModified
.tm_mon
= 0;
3136 lpfp
->tmLastModified
.tm_year
= 0;
3138 /* Determine month */
3139 pszToken
= strtok(NULL
, szSpace
);
3140 if(!pszToken
) continue;
3141 if(strlen(pszToken
) >= 3) {
3143 if((pszTmp
= StrStrIA(szMonths
, pszToken
)))
3144 lpfp
->tmLastModified
.tm_mon
= ((pszTmp
- szMonths
) / 3)+1;
3147 pszToken
= strtok(NULL
, szSpace
);
3148 if(!pszToken
) continue;
3149 lpfp
->tmLastModified
.tm_mday
= atoi(pszToken
);
3150 /* Determine time or year */
3151 pszToken
= strtok(NULL
, szSpace
);
3152 if(!pszToken
) continue;
3153 if((pszTmp
= strchr(pszToken
, ':'))) {
3158 lpfp
->tmLastModified
.tm_min
= atoi(pszTmp
);
3159 lpfp
->tmLastModified
.tm_hour
= atoi(pszToken
);
3161 apTM
= localtime(&aTime
);
3162 lpfp
->tmLastModified
.tm_year
= apTM
->tm_year
;
3165 lpfp
->tmLastModified
.tm_year
= atoi(pszToken
) - 1900;
3166 lpfp
->tmLastModified
.tm_hour
= 12;
3168 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3169 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3170 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3171 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3173 pszToken
= strtok(NULL
, szSpace
);
3174 if(!pszToken
) continue;
3175 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3176 TRACE("File: %s\n", debugstr_w(lpfp
->lpszName
));
3178 /* NT way of parsing ... :
3180 07-13-03 08:55PM <DIR> sakpatch
3181 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3183 else if(isdigit(pszToken
[0]) && 8 == strlen(pszToken
)) {
3184 lpfp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
3186 sscanf(pszToken
, "%d-%d-%d",
3187 &lpfp
->tmLastModified
.tm_mon
,
3188 &lpfp
->tmLastModified
.tm_mday
,
3189 &lpfp
->tmLastModified
.tm_year
);
3191 /* Hacky and bad Y2K protection :-) */
3192 if (lpfp
->tmLastModified
.tm_year
< 70)
3193 lpfp
->tmLastModified
.tm_year
+= 100;
3195 pszToken
= strtok(NULL
, szSpace
);
3196 if(!pszToken
) continue;
3197 sscanf(pszToken
, "%d:%d",
3198 &lpfp
->tmLastModified
.tm_hour
,
3199 &lpfp
->tmLastModified
.tm_min
);
3200 if((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
3201 lpfp
->tmLastModified
.tm_hour
+= 12;
3203 lpfp
->tmLastModified
.tm_sec
= 0;
3205 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3206 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3207 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3208 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3210 pszToken
= strtok(NULL
, szSpace
);
3211 if(!pszToken
) continue;
3212 if(!strcasecmp(pszToken
, "<DIR>")) {
3213 lpfp
->bIsDirectory
= TRUE
;
3215 TRACE("Is directory\n");
3218 lpfp
->bIsDirectory
= FALSE
;
3219 lpfp
->nSize
= atol(pszToken
);
3220 TRACE("Size: %d\n", lpfp
->nSize
);
3223 pszToken
= strtok(NULL
, szSpace
);
3224 if(!pszToken
) continue;
3225 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3226 TRACE("Name: %s\n", debugstr_w(lpfp
->lpszName
));
3228 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3229 else if(pszToken
[0] == '+') {
3230 FIXME("EPLF Format not implemented\n");
3233 if(lpfp
->lpszName
) {
3234 if((lpszSearchFile
== NULL
) ||
3235 (PathMatchSpecW(lpfp
->lpszName
, lpszSearchFile
))) {
3237 TRACE("Matched: %s\n", debugstr_w(lpfp
->lpszName
));
3240 HeapFree(GetProcessHeap(), 0, lpfp
->lpszName
);
3241 lpfp
->lpszName
= NULL
;
3248 /***********************************************************************
3249 * FTP_ParseDirectory (internal)
3251 * Parse string of directory information
3257 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
3258 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
)
3260 BOOL bSuccess
= TRUE
;
3261 INT sizeFilePropArray
= 500;/*20; */
3262 INT indexFilePropArray
= -1;
3266 /* Allocate intial file properties array */
3267 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESW
)*(sizeFilePropArray
));
3272 if (indexFilePropArray
+1 >= sizeFilePropArray
)
3274 LPFILEPROPERTIESW tmpafp
;
3276 sizeFilePropArray
*= 2;
3277 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
3278 sizeof(FILEPROPERTIESW
)*sizeFilePropArray
);
3287 indexFilePropArray
++;
3288 } while (FTP_ParseNextFile(nSocket
, lpszSearchFile
, &(*lpafp
)[indexFilePropArray
]));
3290 if (bSuccess
&& indexFilePropArray
)
3292 if (indexFilePropArray
< sizeFilePropArray
- 1)
3294 LPFILEPROPERTIESW tmpafp
;
3296 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
3297 sizeof(FILEPROPERTIESW
)*indexFilePropArray
);
3301 *dwfp
= indexFilePropArray
;
3305 HeapFree(GetProcessHeap(), 0, *lpafp
);
3306 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
3314 /***********************************************************************
3315 * FTP_ParsePermission (internal)
3317 * Parse permission string of directory information
3324 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
)
3326 BOOL bSuccess
= TRUE
;
3327 unsigned short nPermission
= 0;
3332 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
3338 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
3344 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
3347 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
3350 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
3353 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
3356 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
3359 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
3362 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
3365 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
3368 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
3372 }while (nPos
<= nLast
);
3374 lpfp
->permissions
= nPermission
;
3379 /***********************************************************************
3380 * FTP_SetResponseError (internal)
3382 * Set the appropriate error code for a given response from the server
3387 static DWORD
FTP_SetResponseError(DWORD dwResponse
)
3393 case 421: /* Service not available - Server may be shutting down. */
3394 dwCode
= ERROR_INTERNET_EXTENDED_ERROR
;
3397 case 425: /* Cannot open data connection. */
3398 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
3401 case 426: /* Connection closed, transer aborted. */
3402 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
3405 case 500: /* Syntax error. Command unrecognized. */
3406 case 501: /* Syntax error. Error in parameters or arguments. */
3407 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
3410 case 530: /* Not logged in. Login incorrect. */
3411 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
3414 case 550: /* File action not taken. File not found or no access. */
3415 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
3418 case 450: /* File action not taken. File may be busy. */
3419 case 451: /* Action aborted. Server error. */
3420 case 452: /* Action not taken. Insufficient storage space on server. */
3421 case 502: /* Command not implemented. */
3422 case 503: /* Bad sequence of commands. */
3423 case 504: /* Command not implemented for that parameter. */
3424 case 532: /* Need account for storing files */
3425 case 551: /* Requested action aborted. Page type unknown */
3426 case 552: /* Action aborted. Exceeded storage allocation */
3427 case 553: /* Action not taken. File name not allowed. */
3430 dwCode
= ERROR_INTERNET_EXTENDED_ERROR
;
3434 INTERNET_SetLastError(dwCode
);