2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
6 * Copyright 2004 Kevin Koltzau
11 * Copyright 2000 Andreas Mohr
12 * Copyright 2002 Jaco Greeff
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wine/port.h"
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_SOCKET_H
39 # include <sys/socket.h>
58 #include "wine/debug.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
63 #define DATA_PACKET_SIZE 0x2000
68 /* FTP commands with arguments. */
84 /* FTP commands without arguments. */
93 static const CHAR
*szFtpCommands
[] = {
116 static const CHAR szMonths
[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
117 static const WCHAR szNoAccount
[] = {'n','o','a','c','c','o','u','n','t','\0'};
119 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
);
120 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
);
121 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
);
122 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
123 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
);
124 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
);
125 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
);
126 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
);
127 static INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD dwContext
);
128 static DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
);
129 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
);
130 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
);
131 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
);
132 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
);
133 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
);
134 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
);
135 static BOOL
FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD
*dwSize
);
136 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
);
137 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
);
138 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
);
139 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
);
140 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW fileprop
);
141 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
142 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
);
143 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
144 LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwContext
);
145 static DWORD
FTP_SetResponseError(DWORD dwResponse
);
147 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
157 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
158 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
160 LPWSTR lpwzLocalFile
;
161 LPWSTR lpwzNewRemoteFile
;
164 lpwzLocalFile
= lpszLocalFile
?WININET_strdup_AtoW(lpszLocalFile
):NULL
;
165 lpwzNewRemoteFile
= lpszNewRemoteFile
?WININET_strdup_AtoW(lpszNewRemoteFile
):NULL
;
166 ret
= FtpPutFileW(hConnect
, lpwzLocalFile
, lpwzNewRemoteFile
,
168 HeapFree(GetProcessHeap(), 0, lpwzLocalFile
);
169 HeapFree(GetProcessHeap(), 0, lpwzNewRemoteFile
);
173 /***********************************************************************
174 * FtpPutFileW (WININET.@)
176 * Uploads a file to the FTP server
183 static void AsyncFtpPutFileProc(WORKREQUEST
*workRequest
)
185 struct WORKREQ_FTPPUTFILEW
const *req
= &workRequest
->u
.FtpPutFileW
;
186 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
188 TRACE("%p\n", lpwfs
);
190 FTP_FtpPutFileW(lpwfs
, req
->lpszLocalFile
,
191 req
->lpszNewRemoteFile
, req
->dwFlags
, req
->dwContext
);
193 HeapFree(GetProcessHeap(), 0, req
->lpszLocalFile
);
194 HeapFree(GetProcessHeap(), 0, req
->lpszNewRemoteFile
);
197 BOOL WINAPI
FtpPutFileW(HINTERNET hConnect
, LPCWSTR lpszLocalFile
,
198 LPCWSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
200 LPWININETFTPSESSIONW lpwfs
;
201 LPWININETAPPINFOW hIC
= NULL
;
204 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
205 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
207 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
211 hIC
= lpwfs
->lpAppInfo
;
212 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
214 WORKREQUEST workRequest
;
215 struct WORKREQ_FTPPUTFILEW
*req
= &workRequest
.u
.FtpPutFileW
;
217 workRequest
.asyncproc
= AsyncFtpPutFileProc
;
218 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
219 req
->lpszLocalFile
= WININET_strdupW(lpszLocalFile
);
220 req
->lpszNewRemoteFile
= WININET_strdupW(lpszNewRemoteFile
);
221 req
->dwFlags
= dwFlags
;
222 req
->dwContext
= dwContext
;
224 r
= INTERNET_AsyncCall(&workRequest
);
228 r
= FTP_FtpPutFileW(lpwfs
, lpszLocalFile
,
229 lpszNewRemoteFile
, dwFlags
, dwContext
);
234 WININET_Release( &lpwfs
->hdr
);
239 /***********************************************************************
240 * FTP_FtpPutFileW (Internal)
242 * Uploads a file to the FTP server
249 BOOL WINAPI
FTP_FtpPutFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszLocalFile
,
250 LPCWSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
253 BOOL bSuccess
= FALSE
;
254 LPWININETAPPINFOW hIC
= NULL
;
257 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", debugstr_w(lpszLocalFile
), debugstr_w(lpszNewRemoteFile
));
259 if (!lpszLocalFile
|| !lpszNewRemoteFile
)
261 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
265 /* Clear any error information */
266 INTERNET_SetLastError(0);
267 hIC
= lpwfs
->lpAppInfo
;
269 /* Open file to be uploaded */
270 if (INVALID_HANDLE_VALUE
==
271 (hFile
= CreateFileW(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
273 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND
);
277 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
279 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
283 /* Get data socket to server */
284 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
286 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
287 closesocket(nDataSocket
);
288 nResCode
= FTP_ReceiveResponse(lpwfs
, dwContext
);
294 FTP_SetResponseError(nResCode
);
300 if (lpwfs
->lstnSocket
!= -1)
301 closesocket(lpwfs
->lstnSocket
);
303 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
305 INTERNET_ASYNC_RESULT iar
;
307 iar
.dwResult
= (DWORD
)bSuccess
;
308 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
309 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
310 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
320 /***********************************************************************
321 * FtpSetCurrentDirectoryA (WININET.@)
323 * Change the working directory on the FTP server
330 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
332 LPWSTR lpwzDirectory
;
335 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
336 ret
= FtpSetCurrentDirectoryW(hConnect
, lpwzDirectory
);
337 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
342 /***********************************************************************
343 * FtpSetCurrentDirectoryW (WININET.@)
345 * Change the working directory on the FTP server
352 static void AsyncFtpSetCurrentDirectoryProc(WORKREQUEST
*workRequest
)
354 struct WORKREQ_FTPSETCURRENTDIRECTORYW
const *req
= &workRequest
->u
.FtpSetCurrentDirectoryW
;
355 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
357 TRACE("%p\n", lpwfs
);
359 FTP_FtpSetCurrentDirectoryW(lpwfs
, req
->lpszDirectory
);
360 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
363 BOOL WINAPI
FtpSetCurrentDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
365 LPWININETFTPSESSIONW lpwfs
= NULL
;
366 LPWININETAPPINFOW hIC
= NULL
;
371 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
375 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
376 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
378 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
382 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
384 hIC
= lpwfs
->lpAppInfo
;
385 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
387 WORKREQUEST workRequest
;
388 struct WORKREQ_FTPSETCURRENTDIRECTORYW
*req
;
390 workRequest
.asyncproc
= AsyncFtpSetCurrentDirectoryProc
;
391 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
392 req
= &workRequest
.u
.FtpSetCurrentDirectoryW
;
393 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
395 r
= INTERNET_AsyncCall(&workRequest
);
399 r
= FTP_FtpSetCurrentDirectoryW(lpwfs
, lpszDirectory
);
404 WININET_Release( &lpwfs
->hdr
);
410 /***********************************************************************
411 * FTP_FtpSetCurrentDirectoryW (Internal)
413 * Change the working directory on the FTP server
420 BOOL WINAPI
FTP_FtpSetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
423 LPWININETAPPINFOW hIC
= NULL
;
424 DWORD bSuccess
= FALSE
;
426 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
428 /* Clear any error information */
429 INTERNET_SetLastError(0);
431 hIC
= lpwfs
->lpAppInfo
;
432 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
433 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
436 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
443 FTP_SetResponseError(nResCode
);
447 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
449 INTERNET_ASYNC_RESULT iar
;
451 iar
.dwResult
= (DWORD
)bSuccess
;
452 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
453 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
454 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
460 /***********************************************************************
461 * FtpCreateDirectoryA (WININET.@)
463 * Create new directory on the FTP server
470 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
472 LPWSTR lpwzDirectory
;
475 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
476 ret
= FtpCreateDirectoryW(hConnect
, lpwzDirectory
);
477 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
482 /***********************************************************************
483 * FtpCreateDirectoryW (WININET.@)
485 * Create new directory on the FTP server
492 static void AsyncFtpCreateDirectoryProc(WORKREQUEST
*workRequest
)
494 struct WORKREQ_FTPCREATEDIRECTORYW
const *req
= &workRequest
->u
.FtpCreateDirectoryW
;
495 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
497 TRACE(" %p\n", lpwfs
);
499 FTP_FtpCreateDirectoryW(lpwfs
, req
->lpszDirectory
);
500 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
503 BOOL WINAPI
FtpCreateDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
505 LPWININETFTPSESSIONW lpwfs
;
506 LPWININETAPPINFOW hIC
= NULL
;
509 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
510 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
512 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
516 hIC
= lpwfs
->lpAppInfo
;
517 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
519 WORKREQUEST workRequest
;
520 struct WORKREQ_FTPCREATEDIRECTORYW
*req
;
522 workRequest
.asyncproc
= AsyncFtpCreateDirectoryProc
;
523 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
524 req
= &workRequest
.u
.FtpCreateDirectoryW
;
525 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
527 r
= INTERNET_AsyncCall(&workRequest
);
531 r
= FTP_FtpCreateDirectoryW(lpwfs
, lpszDirectory
);
535 WININET_Release( &lpwfs
->hdr
);
541 /***********************************************************************
542 * FTP_FtpCreateDirectoryW (Internal)
544 * Create new directory on the FTP server
551 BOOL WINAPI
FTP_FtpCreateDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
554 BOOL bSuccess
= FALSE
;
555 LPWININETAPPINFOW hIC
= NULL
;
557 TRACE("lpszDirectory(%s)\n", debugstr_w(lpszDirectory
));
559 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
561 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
565 /* Clear any error information */
566 INTERNET_SetLastError(0);
568 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
571 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
577 FTP_SetResponseError(nResCode
);
581 hIC
= lpwfs
->lpAppInfo
;
582 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
584 INTERNET_ASYNC_RESULT iar
;
586 iar
.dwResult
= (DWORD
)bSuccess
;
587 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
588 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
589 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
595 /***********************************************************************
596 * FtpFindFirstFileA (WININET.@)
598 * Search the specified directory
601 * HINTERNET on success
605 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
606 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
608 LPWSTR lpwzSearchFile
;
609 WIN32_FIND_DATAW wfd
;
610 LPWIN32_FIND_DATAW lpFindFileDataW
;
613 lpwzSearchFile
= lpszSearchFile
?WININET_strdup_AtoW(lpszSearchFile
):NULL
;
614 lpFindFileDataW
= lpFindFileData
?&wfd
:NULL
;
615 ret
= FtpFindFirstFileW(hConnect
, lpwzSearchFile
, lpFindFileDataW
, dwFlags
, dwContext
);
616 HeapFree(GetProcessHeap(), 0, lpwzSearchFile
);
619 WININET_find_data_WtoA(lpFindFileDataW
, lpFindFileData
);
625 /***********************************************************************
626 * FtpFindFirstFileW (WININET.@)
628 * Search the specified directory
631 * HINTERNET on success
635 static void AsyncFtpFindFirstFileProc(WORKREQUEST
*workRequest
)
637 struct WORKREQ_FTPFINDFIRSTFILEW
const *req
= &workRequest
->u
.FtpFindFirstFileW
;
638 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
640 TRACE("%p\n", lpwfs
);
642 FTP_FtpFindFirstFileW(lpwfs
, req
->lpszSearchFile
,
643 req
->lpFindFileData
, req
->dwFlags
, req
->dwContext
);
644 HeapFree(GetProcessHeap(), 0, req
->lpszSearchFile
);
647 HINTERNET WINAPI
FtpFindFirstFileW(HINTERNET hConnect
,
648 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
650 LPWININETFTPSESSIONW lpwfs
;
651 LPWININETAPPINFOW hIC
= NULL
;
654 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hConnect
);
655 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
657 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
661 hIC
= lpwfs
->lpAppInfo
;
662 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
664 WORKREQUEST workRequest
;
665 struct WORKREQ_FTPFINDFIRSTFILEW
*req
;
667 workRequest
.asyncproc
= AsyncFtpFindFirstFileProc
;
668 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
669 req
= &workRequest
.u
.FtpFindFirstFileW
;
670 req
->lpszSearchFile
= (lpszSearchFile
== NULL
) ? NULL
: WININET_strdupW(lpszSearchFile
);
671 req
->lpFindFileData
= lpFindFileData
;
672 req
->dwFlags
= dwFlags
;
673 req
->dwContext
= dwContext
;
675 INTERNET_AsyncCall(&workRequest
);
680 r
= FTP_FtpFindFirstFileW(lpwfs
, lpszSearchFile
, lpFindFileData
,
685 WININET_Release( &lpwfs
->hdr
);
691 /***********************************************************************
692 * FTP_FtpFindFirstFileW (Internal)
694 * Search the specified directory
697 * HINTERNET on success
701 HINTERNET WINAPI
FTP_FtpFindFirstFileW(LPWININETFTPSESSIONW lpwfs
,
702 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
705 LPWININETAPPINFOW hIC
= NULL
;
706 HINTERNET hFindNext
= NULL
;
710 assert(WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
712 /* Clear any error information */
713 INTERNET_SetLastError(0);
715 if (!FTP_InitListenSocket(lpwfs
))
718 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
721 if (!FTP_SendPortOrPasv(lpwfs
))
724 hIC
= lpwfs
->lpAppInfo
;
725 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, NULL
,
726 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
729 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
732 if (nResCode
== 125 || nResCode
== 150)
736 /* Get data socket to server */
737 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
739 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpszSearchFile
, lpFindFileData
, dwContext
);
740 closesocket(nDataSocket
);
741 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
742 if (nResCode
!= 226 && nResCode
!= 250)
743 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
747 FTP_SetResponseError(nResCode
);
751 if (lpwfs
->lstnSocket
!= -1)
752 closesocket(lpwfs
->lstnSocket
);
754 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
756 INTERNET_ASYNC_RESULT iar
;
760 iar
.dwResult
= (DWORD
)hFindNext
;
761 iar
.dwError
= ERROR_SUCCESS
;
762 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
763 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
766 iar
.dwResult
= (DWORD
)hFindNext
;
767 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
768 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
769 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
776 /***********************************************************************
777 * FtpGetCurrentDirectoryA (WININET.@)
779 * Retrieves the current directory
786 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
787 LPDWORD lpdwCurrentDirectory
)
793 if(lpdwCurrentDirectory
) {
794 len
= *lpdwCurrentDirectory
;
795 if(lpszCurrentDirectory
)
797 dir
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
800 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
805 ret
= FtpGetCurrentDirectoryW(hFtpSession
, lpszCurrentDirectory
?dir
:NULL
, lpdwCurrentDirectory
?&len
:NULL
);
806 if(lpdwCurrentDirectory
) {
807 *lpdwCurrentDirectory
= len
;
808 if(lpszCurrentDirectory
) {
809 WideCharToMultiByte(CP_ACP
, 0, dir
, len
, lpszCurrentDirectory
, *lpdwCurrentDirectory
, NULL
, NULL
);
810 HeapFree(GetProcessHeap(), 0, dir
);
817 /***********************************************************************
818 * FtpGetCurrentDirectoryW (WININET.@)
820 * Retrieves the current directory
827 static void AsyncFtpGetCurrentDirectoryProc(WORKREQUEST
*workRequest
)
829 struct WORKREQ_FTPGETCURRENTDIRECTORYW
const *req
= &workRequest
->u
.FtpGetCurrentDirectoryW
;
830 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
832 TRACE("%p\n", lpwfs
);
834 FTP_FtpGetCurrentDirectoryW(lpwfs
, req
->lpszDirectory
, req
->lpdwDirectory
);
837 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
838 LPDWORD lpdwCurrentDirectory
)
840 LPWININETFTPSESSIONW lpwfs
;
841 LPWININETAPPINFOW hIC
= NULL
;
844 TRACE("len(%d)\n", *lpdwCurrentDirectory
);
846 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
847 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
849 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
853 hIC
= lpwfs
->lpAppInfo
;
854 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
856 WORKREQUEST workRequest
;
857 struct WORKREQ_FTPGETCURRENTDIRECTORYW
*req
;
859 workRequest
.asyncproc
= AsyncFtpGetCurrentDirectoryProc
;
860 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
861 req
= &workRequest
.u
.FtpGetCurrentDirectoryW
;
862 req
->lpszDirectory
= lpszCurrentDirectory
;
863 req
->lpdwDirectory
= lpdwCurrentDirectory
;
865 r
= INTERNET_AsyncCall(&workRequest
);
869 r
= FTP_FtpGetCurrentDirectoryW(lpwfs
, lpszCurrentDirectory
,
870 lpdwCurrentDirectory
);
875 WININET_Release( &lpwfs
->hdr
);
881 /***********************************************************************
882 * FTP_FtpGetCurrentDirectoryA (Internal)
884 * Retrieves the current directory
891 BOOL WINAPI
FTP_FtpGetCurrentDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPWSTR lpszCurrentDirectory
,
892 LPDWORD lpdwCurrentDirectory
)
895 LPWININETAPPINFOW hIC
= NULL
;
896 DWORD bSuccess
= FALSE
;
898 TRACE("len(%d)\n", *lpdwCurrentDirectory
);
900 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
902 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
906 /* Clear any error information */
907 INTERNET_SetLastError(0);
909 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
911 hIC
= lpwfs
->lpAppInfo
;
912 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
913 lpwfs
->hdr
.lpfnStatusCB
, &lpwfs
->hdr
, lpwfs
->hdr
.dwContext
))
916 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
919 if (nResCode
== 257) /* Extract directory name */
921 DWORD firstpos
, lastpos
, len
;
922 LPWSTR lpszResponseBuffer
= WININET_strdup_AtoW(INTERNET_GetResponseBuffer());
924 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
926 if ('"' == lpszResponseBuffer
[lastpos
])
935 len
= lastpos
- firstpos
- 1;
936 lstrcpynW(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1], *lpdwCurrentDirectory
);
937 HeapFree(GetProcessHeap(), 0, lpszResponseBuffer
);
938 *lpdwCurrentDirectory
= len
;
942 FTP_SetResponseError(nResCode
);
946 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
948 INTERNET_ASYNC_RESULT iar
;
950 iar
.dwResult
= (DWORD
)bSuccess
;
951 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
952 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
953 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
956 return (DWORD
) bSuccess
;
959 /***********************************************************************
960 * FtpOpenFileA (WININET.@)
962 * Open a remote file for writing or reading
965 * HINTERNET handle on success
969 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
970 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
976 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
977 ret
= FtpOpenFileW(hFtpSession
, lpwzFileName
, fdwAccess
, dwFlags
, dwContext
);
978 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
983 /***********************************************************************
984 * FtpOpenFileW (WININET.@)
986 * Open a remote file for writing or reading
989 * HINTERNET handle on success
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 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
1006 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
1009 LPWININETFTPSESSIONW lpwfs
;
1010 LPWININETAPPINFOW hIC
= NULL
;
1013 TRACE("(%p,%s,0x%08x,0x%08x,0x%08x)\n", hFtpSession
,
1014 debugstr_w(lpszFileName
), fdwAccess
, dwFlags
, dwContext
);
1016 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1017 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1019 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1023 if (lpwfs
->download_in_progress
!= NULL
) {
1024 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1027 hIC
= lpwfs
->lpAppInfo
;
1028 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1030 WORKREQUEST workRequest
;
1031 struct WORKREQ_FTPOPENFILEW
*req
;
1033 workRequest
.asyncproc
= AsyncFtpOpenFileProc
;
1034 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1035 req
= &workRequest
.u
.FtpOpenFileW
;
1036 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
1037 req
->dwAccess
= fdwAccess
;
1038 req
->dwFlags
= dwFlags
;
1039 req
->dwContext
= dwContext
;
1041 INTERNET_AsyncCall(&workRequest
);
1046 r
= FTP_FtpOpenFileW(lpwfs
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
1051 WININET_Release( &lpwfs
->hdr
);
1057 /***********************************************************************
1058 * FTP_FtpOpenFileW (Internal)
1060 * Open a remote file for writing or reading
1063 * HINTERNET handle on success
1067 HINTERNET
FTP_FtpOpenFileW(LPWININETFTPSESSIONW lpwfs
,
1068 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
1072 BOOL bSuccess
= FALSE
;
1073 LPWININETFTPFILE lpwh
= NULL
;
1074 LPWININETAPPINFOW hIC
= NULL
;
1075 HINTERNET handle
= NULL
;
1079 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1081 /* Clear any error information */
1082 INTERNET_SetLastError(0);
1084 if (GENERIC_READ
== fdwAccess
)
1086 /* Set up socket to retrieve data */
1087 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
1089 else if (GENERIC_WRITE
== fdwAccess
)
1091 /* Set up socket to send data */
1092 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
1095 /* Get data socket to server */
1096 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1098 lpwh
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPFILE
));
1099 lpwh
->hdr
.htype
= WH_HFILE
;
1100 lpwh
->hdr
.dwFlags
= dwFlags
;
1101 lpwh
->hdr
.dwContext
= dwContext
;
1102 lpwh
->hdr
.dwRefCount
= 1;
1103 lpwh
->hdr
.destroy
= FTP_CloseFileTransferHandle
;
1104 lpwh
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
1105 lpwh
->nDataSocket
= nDataSocket
;
1106 lpwh
->session_deleted
= FALSE
;
1108 WININET_AddRef( &lpwfs
->hdr
);
1109 lpwh
->lpFtpSession
= lpwfs
;
1111 handle
= WININET_AllocHandle( &lpwh
->hdr
);
1115 /* Indicate that a download is currently in progress */
1116 lpwfs
->download_in_progress
= lpwh
;
1119 if (lpwfs
->lstnSocket
!= -1)
1120 closesocket(lpwfs
->lstnSocket
);
1122 hIC
= lpwfs
->lpAppInfo
;
1123 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1125 INTERNET_ASYNC_RESULT iar
;
1129 iar
.dwResult
= (DWORD
)handle
;
1130 iar
.dwError
= ERROR_SUCCESS
;
1131 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1132 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1135 iar
.dwResult
= (DWORD
)bSuccess
;
1136 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1137 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1138 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1143 WININET_Release( &lpwh
->hdr
);
1149 /***********************************************************************
1150 * FtpGetFileA (WININET.@)
1152 * Retrieve file from the FTP server
1159 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1160 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1163 LPWSTR lpwzRemoteFile
;
1167 lpwzRemoteFile
= lpszRemoteFile
?WININET_strdup_AtoW(lpszRemoteFile
):NULL
;
1168 lpwzNewFile
= lpszNewFile
?WININET_strdup_AtoW(lpszNewFile
):NULL
;
1169 ret
= FtpGetFileW(hInternet
, lpwzRemoteFile
, lpwzNewFile
, fFailIfExists
,
1170 dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1171 HeapFree(GetProcessHeap(), 0, lpwzRemoteFile
);
1172 HeapFree(GetProcessHeap(), 0, lpwzNewFile
);
1177 /***********************************************************************
1178 * FtpGetFileW (WININET.@)
1180 * Retrieve file from the FTP server
1187 static void AsyncFtpGetFileProc(WORKREQUEST
*workRequest
)
1189 struct WORKREQ_FTPGETFILEW
const *req
= &workRequest
->u
.FtpGetFileW
;
1190 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1192 TRACE("%p\n", lpwfs
);
1194 FTP_FtpGetFileW(lpwfs
, req
->lpszRemoteFile
,
1195 req
->lpszNewFile
, req
->fFailIfExists
,
1196 req
->dwLocalFlagsAttribute
, req
->dwFlags
, req
->dwContext
);
1197 HeapFree(GetProcessHeap(), 0, req
->lpszRemoteFile
);
1198 HeapFree(GetProcessHeap(), 0, req
->lpszNewFile
);
1201 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1202 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1205 LPWININETFTPSESSIONW lpwfs
;
1206 LPWININETAPPINFOW hIC
= NULL
;
1209 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hInternet
);
1210 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1212 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1216 if (lpwfs
->download_in_progress
!= NULL
) {
1217 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1221 hIC
= lpwfs
->lpAppInfo
;
1222 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1224 WORKREQUEST workRequest
;
1225 struct WORKREQ_FTPGETFILEW
*req
;
1227 workRequest
.asyncproc
= AsyncFtpGetFileProc
;
1228 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1229 req
= &workRequest
.u
.FtpGetFileW
;
1230 req
->lpszRemoteFile
= WININET_strdupW(lpszRemoteFile
);
1231 req
->lpszNewFile
= WININET_strdupW(lpszNewFile
);
1232 req
->dwLocalFlagsAttribute
= dwLocalFlagsAttribute
;
1233 req
->fFailIfExists
= fFailIfExists
;
1234 req
->dwFlags
= dwInternetFlags
;
1235 req
->dwContext
= dwContext
;
1237 r
= INTERNET_AsyncCall(&workRequest
);
1241 r
= FTP_FtpGetFileW(lpwfs
, lpszRemoteFile
, lpszNewFile
,
1242 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1247 WININET_Release( &lpwfs
->hdr
);
1253 /***********************************************************************
1254 * FTP_FtpGetFileW (Internal)
1256 * Retrieve file from the FTP server
1263 BOOL WINAPI
FTP_FtpGetFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1264 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1268 BOOL bSuccess
= FALSE
;
1270 LPWININETAPPINFOW hIC
= NULL
;
1272 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", debugstr_w(lpszRemoteFile
), debugstr_w(lpszNewFile
));
1274 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1276 /* Clear any error information */
1277 INTERNET_SetLastError(0);
1279 /* Ensure we can write to lpszNewfile by opening it */
1280 hFile
= CreateFileW(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1281 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1282 if (INVALID_HANDLE_VALUE
== hFile
)
1285 /* Set up socket to retrieve data */
1286 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
1292 /* Get data socket to server */
1293 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1298 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
1299 nResCode
= FTP_ReceiveResponse(lpwfs
, dwContext
);
1302 if (nResCode
== 226)
1305 FTP_SetResponseError(nResCode
);
1307 closesocket(nDataSocket
);
1312 if (lpwfs
->lstnSocket
!= -1)
1313 closesocket(lpwfs
->lstnSocket
);
1318 hIC
= lpwfs
->lpAppInfo
;
1319 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1321 INTERNET_ASYNC_RESULT iar
;
1323 iar
.dwResult
= (DWORD
)bSuccess
;
1324 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1325 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1326 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1332 /***********************************************************************
1333 * FtpGetFileSize (WININET.@)
1335 DWORD WINAPI
FtpGetFileSize( HINTERNET hFile
, LPDWORD lpdwFileSizeHigh
)
1337 FIXME("(%p, %p)\n", hFile
, lpdwFileSizeHigh
);
1339 if (lpdwFileSizeHigh
)
1340 *lpdwFileSizeHigh
= 0;
1345 /***********************************************************************
1346 * FtpDeleteFileA (WININET.@)
1348 * Delete a file on the ftp server
1355 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1357 LPWSTR lpwzFileName
;
1360 lpwzFileName
= lpszFileName
?WININET_strdup_AtoW(lpszFileName
):NULL
;
1361 ret
= FtpDeleteFileW(hFtpSession
, lpwzFileName
);
1362 HeapFree(GetProcessHeap(), 0, lpwzFileName
);
1366 /***********************************************************************
1367 * FtpDeleteFileW (WININET.@)
1369 * Delete a file on the ftp server
1376 static void AsyncFtpDeleteFileProc(WORKREQUEST
*workRequest
)
1378 struct WORKREQ_FTPDELETEFILEW
const *req
= &workRequest
->u
.FtpDeleteFileW
;
1379 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1381 TRACE("%p\n", lpwfs
);
1383 FTP_FtpDeleteFileW(lpwfs
, req
->lpszFilename
);
1384 HeapFree(GetProcessHeap(), 0, req
->lpszFilename
);
1387 BOOL WINAPI
FtpDeleteFileW(HINTERNET hFtpSession
, LPCWSTR lpszFileName
)
1389 LPWININETFTPSESSIONW lpwfs
;
1390 LPWININETAPPINFOW hIC
= NULL
;
1393 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1394 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1396 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1400 hIC
= lpwfs
->lpAppInfo
;
1401 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1403 WORKREQUEST workRequest
;
1404 struct WORKREQ_FTPDELETEFILEW
*req
;
1406 workRequest
.asyncproc
= AsyncFtpDeleteFileProc
;
1407 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1408 req
= &workRequest
.u
.FtpDeleteFileW
;
1409 req
->lpszFilename
= WININET_strdupW(lpszFileName
);
1411 r
= INTERNET_AsyncCall(&workRequest
);
1415 r
= FTP_FtpDeleteFileW(lpwfs
, lpszFileName
);
1420 WININET_Release( &lpwfs
->hdr
);
1425 /***********************************************************************
1426 * FTP_FtpDeleteFileW (Internal)
1428 * Delete a file on the ftp server
1435 BOOL
FTP_FtpDeleteFileW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszFileName
)
1438 BOOL bSuccess
= FALSE
;
1439 LPWININETAPPINFOW hIC
= NULL
;
1441 TRACE("%p\n", lpwfs
);
1443 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1445 /* Clear any error information */
1446 INTERNET_SetLastError(0);
1448 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1451 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1454 if (nResCode
== 250)
1457 FTP_SetResponseError(nResCode
);
1460 hIC
= lpwfs
->lpAppInfo
;
1461 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1463 INTERNET_ASYNC_RESULT iar
;
1465 iar
.dwResult
= (DWORD
)bSuccess
;
1466 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1467 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1468 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1475 /***********************************************************************
1476 * FtpRemoveDirectoryA (WININET.@)
1478 * Remove a directory on the ftp server
1485 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1487 LPWSTR lpwzDirectory
;
1490 lpwzDirectory
= lpszDirectory
?WININET_strdup_AtoW(lpszDirectory
):NULL
;
1491 ret
= FtpRemoveDirectoryW(hFtpSession
, lpwzDirectory
);
1492 HeapFree(GetProcessHeap(), 0, lpwzDirectory
);
1496 /***********************************************************************
1497 * FtpRemoveDirectoryW (WININET.@)
1499 * Remove a directory on the ftp server
1506 static void AsyncFtpRemoveDirectoryProc(WORKREQUEST
*workRequest
)
1508 struct WORKREQ_FTPREMOVEDIRECTORYW
const *req
= &workRequest
->u
.FtpRemoveDirectoryW
;
1509 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1511 TRACE("%p\n", lpwfs
);
1513 FTP_FtpRemoveDirectoryW(lpwfs
, req
->lpszDirectory
);
1514 HeapFree(GetProcessHeap(), 0, req
->lpszDirectory
);
1517 BOOL WINAPI
FtpRemoveDirectoryW(HINTERNET hFtpSession
, LPCWSTR lpszDirectory
)
1519 LPWININETFTPSESSIONW lpwfs
;
1520 LPWININETAPPINFOW hIC
= NULL
;
1523 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1524 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1526 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1530 hIC
= lpwfs
->lpAppInfo
;
1531 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1533 WORKREQUEST workRequest
;
1534 struct WORKREQ_FTPREMOVEDIRECTORYW
*req
;
1536 workRequest
.asyncproc
= AsyncFtpRemoveDirectoryProc
;
1537 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1538 req
= &workRequest
.u
.FtpRemoveDirectoryW
;
1539 req
->lpszDirectory
= WININET_strdupW(lpszDirectory
);
1541 r
= INTERNET_AsyncCall(&workRequest
);
1545 r
= FTP_FtpRemoveDirectoryW(lpwfs
, lpszDirectory
);
1550 WININET_Release( &lpwfs
->hdr
);
1555 /***********************************************************************
1556 * FTP_FtpRemoveDirectoryW (Internal)
1558 * Remove a directory on the ftp server
1565 BOOL
FTP_FtpRemoveDirectoryW(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszDirectory
)
1568 BOOL bSuccess
= FALSE
;
1569 LPWININETAPPINFOW hIC
= NULL
;
1573 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1575 /* Clear any error information */
1576 INTERNET_SetLastError(0);
1578 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1581 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1584 if (nResCode
== 250)
1587 FTP_SetResponseError(nResCode
);
1591 hIC
= lpwfs
->lpAppInfo
;
1592 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1594 INTERNET_ASYNC_RESULT iar
;
1596 iar
.dwResult
= (DWORD
)bSuccess
;
1597 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1598 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1599 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1606 /***********************************************************************
1607 * FtpRenameFileA (WININET.@)
1609 * Rename a file on the ftp server
1616 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1622 lpwzSrc
= lpszSrc
?WININET_strdup_AtoW(lpszSrc
):NULL
;
1623 lpwzDest
= lpszDest
?WININET_strdup_AtoW(lpszDest
):NULL
;
1624 ret
= FtpRenameFileW(hFtpSession
, lpwzSrc
, lpwzDest
);
1625 HeapFree(GetProcessHeap(), 0, lpwzSrc
);
1626 HeapFree(GetProcessHeap(), 0, lpwzDest
);
1630 /***********************************************************************
1631 * FtpRenameFileW (WININET.@)
1633 * Rename a file on the ftp server
1640 static void AsyncFtpRenameFileProc(WORKREQUEST
*workRequest
)
1642 struct WORKREQ_FTPRENAMEFILEW
const *req
= &workRequest
->u
.FtpRenameFileW
;
1643 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) workRequest
->hdr
;
1645 TRACE("%p\n", lpwfs
);
1647 FTP_FtpRenameFileW(lpwfs
, req
->lpszSrcFile
, req
->lpszDestFile
);
1648 HeapFree(GetProcessHeap(), 0, req
->lpszSrcFile
);
1649 HeapFree(GetProcessHeap(), 0, req
->lpszDestFile
);
1652 BOOL WINAPI
FtpRenameFileW(HINTERNET hFtpSession
, LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1654 LPWININETFTPSESSIONW lpwfs
;
1655 LPWININETAPPINFOW hIC
= NULL
;
1658 lpwfs
= (LPWININETFTPSESSIONW
) WININET_GetObject( hFtpSession
);
1659 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1661 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1665 hIC
= lpwfs
->lpAppInfo
;
1666 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1668 WORKREQUEST workRequest
;
1669 struct WORKREQ_FTPRENAMEFILEW
*req
;
1671 workRequest
.asyncproc
= AsyncFtpRenameFileProc
;
1672 workRequest
.hdr
= WININET_AddRef( &lpwfs
->hdr
);
1673 req
= &workRequest
.u
.FtpRenameFileW
;
1674 req
->lpszSrcFile
= WININET_strdupW(lpszSrc
);
1675 req
->lpszDestFile
= WININET_strdupW(lpszDest
);
1677 r
= INTERNET_AsyncCall(&workRequest
);
1681 r
= FTP_FtpRenameFileW(lpwfs
, lpszSrc
, lpszDest
);
1686 WININET_Release( &lpwfs
->hdr
);
1691 /***********************************************************************
1692 * FTP_FtpRenameFileW (Internal)
1694 * Rename a file on the ftp server
1701 BOOL
FTP_FtpRenameFileW( LPWININETFTPSESSIONW lpwfs
,
1702 LPCWSTR lpszSrc
, LPCWSTR lpszDest
)
1705 BOOL bSuccess
= FALSE
;
1706 LPWININETAPPINFOW hIC
= NULL
;
1710 assert (WH_HFTPSESSION
== lpwfs
->hdr
.htype
);
1712 /* Clear any error information */
1713 INTERNET_SetLastError(0);
1715 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1718 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1719 if (nResCode
== 350)
1721 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1724 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1727 if (nResCode
== 250)
1730 FTP_SetResponseError(nResCode
);
1733 hIC
= lpwfs
->lpAppInfo
;
1734 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1736 INTERNET_ASYNC_RESULT iar
;
1738 iar
.dwResult
= (DWORD
)bSuccess
;
1739 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1740 SendAsyncCallback(&lpwfs
->hdr
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1741 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1747 /***********************************************************************
1748 * FtpCommandA (WININET.@)
1750 BOOL WINAPI
FtpCommandA( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1751 LPCSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1753 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1754 debugstr_a(lpszCommand
), dwContext
, phFtpCommand
);
1759 /***********************************************************************
1760 * FtpCommandW (WININET.@)
1762 BOOL WINAPI
FtpCommandW( HINTERNET hConnect
, BOOL fExpectResponse
, DWORD dwFlags
,
1763 LPCWSTR lpszCommand
, DWORD_PTR dwContext
, HINTERNET
* phFtpCommand
)
1765 FIXME("%p %d 0x%08x %s 0x%08lx %p\n", hConnect
, fExpectResponse
, dwFlags
,
1766 debugstr_w(lpszCommand
), dwContext
, phFtpCommand
);
1771 /***********************************************************************
1772 * FTP_Connect (internal)
1774 * Connect to a ftp server
1777 * HINTERNET a session handle on success
1782 * Windows uses 'anonymous' as the username, when given a NULL username
1783 * and a NULL password. The password is first looked up in:
1785 * HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings\EmailName
1787 * If this entry is not present it uses the current username as the password.
1791 HINTERNET
FTP_Connect(LPWININETAPPINFOW hIC
, LPCWSTR lpszServerName
,
1792 INTERNET_PORT nServerPort
, LPCWSTR lpszUserName
,
1793 LPCWSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
,
1794 DWORD dwInternalFlags
)
1796 static const WCHAR szKey
[] = {'S','o','f','t','w','a','r','e','\\',
1797 'M','i','c','r','o','s','o','f','t','\\',
1798 'W','i','n','d','o','w','s','\\',
1799 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
1800 'I','n','t','e','r','n','e','t',' ','S','e','t','t','i','n','g','s',0};
1801 static const WCHAR szValue
[] = {'E','m','a','i','l','N','a','m','e',0};
1802 static const WCHAR szDefaultUsername
[] = {'a','n','o','n','y','m','o','u','s','\0'};
1803 static const WCHAR szEmpty
[] = {'\0'};
1804 struct sockaddr_in socketAddr
;
1807 BOOL bSuccess
= FALSE
;
1808 LPWININETFTPSESSIONW lpwfs
= NULL
;
1809 HINTERNET handle
= NULL
;
1811 TRACE("%p Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1812 hIC
, debugstr_w(lpszServerName
),
1813 nServerPort
, debugstr_w(lpszUserName
), debugstr_w(lpszPassword
));
1815 assert( hIC
->hdr
.htype
== WH_HINIT
);
1817 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1819 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
1823 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONW
));
1826 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1830 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1831 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1833 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1834 lpwfs
->hdr
.dwFlags
= dwFlags
;
1835 lpwfs
->hdr
.dwContext
= dwContext
;
1836 lpwfs
->hdr
.dwInternalFlags
= dwInternalFlags
;
1837 lpwfs
->hdr
.dwRefCount
= 1;
1838 lpwfs
->hdr
.destroy
= FTP_CloseSessionHandle
;
1839 lpwfs
->hdr
.lpfnStatusCB
= hIC
->hdr
.lpfnStatusCB
;
1840 lpwfs
->download_in_progress
= NULL
;
1842 WININET_AddRef( &hIC
->hdr
);
1843 lpwfs
->lpAppInfo
= hIC
;
1845 handle
= WININET_AllocHandle( &lpwfs
->hdr
);
1848 ERR("Failed to alloc handle\n");
1849 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1853 if(hIC
->lpszProxy
&& hIC
->dwAccessType
== INTERNET_OPEN_TYPE_PROXY
) {
1854 if(strchrW(hIC
->lpszProxy
, ' '))
1855 FIXME("Several proxies not implemented.\n");
1856 if(hIC
->lpszProxyBypass
)
1857 FIXME("Proxy bypass is ignored.\n");
1859 if ( !lpszUserName
) {
1861 WCHAR szPassword
[MAX_PATH
];
1862 DWORD len
= sizeof(szPassword
);
1864 lpwfs
->lpszUserName
= WININET_strdupW(szDefaultUsername
);
1866 RegOpenKeyW(HKEY_CURRENT_USER
, szKey
, &key
);
1867 if (RegQueryValueExW(key
, szValue
, NULL
, NULL
, (LPBYTE
)szPassword
, &len
)) {
1868 /* Nothing in the registry, get the username and use that as the password */
1869 if (!GetUserNameW(szPassword
, &len
)) {
1870 /* Should never get here, but use an empty password as failsafe */
1871 strcpyW(szPassword
, szEmpty
);
1876 TRACE("Password used for anonymous ftp : (%s)\n", debugstr_w(szPassword
));
1877 lpwfs
->lpszPassword
= WININET_strdupW(szPassword
);
1880 lpwfs
->lpszUserName
= WININET_strdupW(lpszUserName
);
1883 lpwfs
->lpszPassword
= WININET_strdupW(lpszPassword
);
1885 lpwfs
->lpszPassword
= WININET_strdupW(szEmpty
);
1888 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1889 if (!(lpwfs
->hdr
.dwInternalFlags
& INET_OPENURL
))
1891 INTERNET_ASYNC_RESULT iar
;
1893 iar
.dwResult
= (DWORD
)handle
;
1894 iar
.dwError
= ERROR_SUCCESS
;
1896 SendAsyncCallback(&hIC
->hdr
, dwContext
,
1897 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
1898 sizeof(INTERNET_ASYNC_RESULT
));
1901 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1902 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1904 if (!GetAddress(lpszServerName
, nServerPort
, &socketAddr
))
1906 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1910 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1911 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1913 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1916 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1920 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1921 &socketAddr
, sizeof(struct sockaddr_in
));
1923 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1925 ERR("Unable to connect (%s)\n", strerror(errno
));
1926 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1930 TRACE("Connected to server\n");
1931 lpwfs
->sndSocket
= nsocket
;
1932 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1933 &socketAddr
, sizeof(struct sockaddr_in
));
1935 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1936 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1938 if (FTP_ConnectToHost(lpwfs
))
1940 TRACE("Successfully logged into server\n");
1946 if (!bSuccess
&& nsocket
== -1)
1947 closesocket(nsocket
);
1949 if (!bSuccess
&& lpwfs
)
1951 HeapFree(GetProcessHeap(), 0, lpwfs
);
1952 WININET_FreeHandle( handle
);
1957 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1959 INTERNET_ASYNC_RESULT iar
;
1961 iar
.dwResult
= (DWORD
)lpwfs
;
1962 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1963 SendAsyncCallback(&hIC
->hdr
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1964 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1971 /***********************************************************************
1972 * FTP_ConnectToHost (internal)
1974 * Connect to a ftp server
1981 static BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONW lpwfs
)
1984 BOOL bSuccess
= FALSE
;
1987 FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1989 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1992 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
1995 /* Login successful... */
1996 if (nResCode
== 230)
1998 /* User name okay, need password... */
1999 else if (nResCode
== 331)
2000 bSuccess
= FTP_SendPassword(lpwfs
);
2001 /* Need account for login... */
2002 else if (nResCode
== 332)
2003 bSuccess
= FTP_SendAccount(lpwfs
);
2005 FTP_SetResponseError(nResCode
);
2008 TRACE("Returning %d\n", bSuccess
);
2014 /***********************************************************************
2015 * FTP_SendCommandA (internal)
2017 * Send command to server
2024 static BOOL
FTP_SendCommandA(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
2025 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
)
2029 DWORD nBytesSent
= 0;
2033 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
2037 lpfnStatusCB(hdr
->hInternet
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
2040 dwParamLen
= lpszParam
?strlen(lpszParam
)+1:0;
2041 len
= dwParamLen
+ strlen(szFtpCommands
[ftpCmd
]) + strlen(szCRLF
);
2042 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
2044 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2047 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], dwParamLen
? " " : "",
2048 dwParamLen
? lpszParam
: "", szCRLF
);
2050 TRACE("Sending (%s) len(%d)\n", buf
, len
);
2051 while((nBytesSent
< len
) && (nRC
!= -1))
2053 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
2057 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
2061 lpfnStatusCB(hdr
->hInternet
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
2062 &nBytesSent
, sizeof(DWORD
));
2065 TRACE("Sent %d bytes\n", nBytesSent
);
2069 /***********************************************************************
2070 * FTP_SendCommand (internal)
2072 * Send command to server
2079 static BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCWSTR lpszParam
,
2080 INTERNET_STATUS_CALLBACK lpfnStatusCB
, LPWININETHANDLEHEADER hdr
, DWORD dwContext
)
2083 LPSTR lpszParamA
= lpszParam
?WININET_strdup_WtoA(lpszParam
):NULL
;
2084 ret
= FTP_SendCommandA(nSocket
, ftpCmd
, lpszParamA
, lpfnStatusCB
, hdr
, dwContext
);
2085 HeapFree(GetProcessHeap(), 0, lpszParamA
);
2089 /***********************************************************************
2090 * FTP_ReceiveResponse (internal)
2092 * Receive response from server
2095 * Reply code on success
2099 INT
FTP_ReceiveResponse(LPWININETFTPSESSIONW lpwfs
, DWORD dwContext
)
2101 LPSTR lpszResponse
= INTERNET_GetResponseBuffer();
2104 char firstprefix
[5];
2105 BOOL multiline
= FALSE
;
2106 LPWININETAPPINFOW hIC
= NULL
;
2108 TRACE("socket(%d)\n", lpwfs
->sndSocket
);
2110 hIC
= lpwfs
->lpAppInfo
;
2111 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
2115 if (!INTERNET_GetNextLine(lpwfs
->sndSocket
, &nRecv
))
2122 if(lpszResponse
[3] != '-')
2125 { /* Start of multiline repsonse. Loop until we get "nnn " */
2127 memcpy(firstprefix
, lpszResponse
, 3);
2128 firstprefix
[3] = ' ';
2129 firstprefix
[4] = '\0';
2134 if(!memcmp(firstprefix
, lpszResponse
, 4))
2142 rc
= atoi(lpszResponse
);
2144 SendAsyncCallback(&lpwfs
->hdr
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
2145 &nRecv
, sizeof(DWORD
));
2149 TRACE("return %d\n", rc
);
2154 /***********************************************************************
2155 * FTP_SendPassword (internal)
2157 * Send password to ftp server
2164 static BOOL
FTP_SendPassword(LPWININETFTPSESSIONW lpwfs
)
2167 BOOL bSuccess
= FALSE
;
2170 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
2173 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2176 TRACE("Received reply code %d\n", nResCode
);
2177 /* Login successful... */
2178 if (nResCode
== 230)
2180 /* Command not implemented, superfluous at the server site... */
2181 /* Need account for login... */
2182 else if (nResCode
== 332)
2183 bSuccess
= FTP_SendAccount(lpwfs
);
2185 FTP_SetResponseError(nResCode
);
2189 TRACE("Returning %d\n", bSuccess
);
2194 /***********************************************************************
2195 * FTP_SendAccount (internal)
2204 static BOOL
FTP_SendAccount(LPWININETFTPSESSIONW lpwfs
)
2207 BOOL bSuccess
= FALSE
;
2210 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, szNoAccount
, 0, 0, 0))
2213 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2217 FTP_SetResponseError(nResCode
);
2224 /***********************************************************************
2225 * FTP_SendStore (internal)
2227 * Send request to upload file to ftp server
2234 static BOOL
FTP_SendStore(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2237 BOOL bSuccess
= FALSE
;
2240 if (!FTP_InitListenSocket(lpwfs
))
2243 if (!FTP_SendType(lpwfs
, dwType
))
2246 if (!FTP_SendPortOrPasv(lpwfs
))
2249 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
2251 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2254 if (nResCode
== 150 || nResCode
== 125)
2257 FTP_SetResponseError(nResCode
);
2261 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
2263 closesocket(lpwfs
->lstnSocket
);
2264 lpwfs
->lstnSocket
= -1;
2271 /***********************************************************************
2272 * FTP_InitListenSocket (internal)
2274 * Create a socket to listen for server response
2281 static BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONW lpwfs
)
2283 BOOL bSuccess
= FALSE
;
2284 socklen_t namelen
= sizeof(struct sockaddr_in
);
2288 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
2289 if (lpwfs
->lstnSocket
== -1)
2291 TRACE("Unable to create listening socket\n");
2295 /* We obtain our ip addr from the name of the command channel socket */
2296 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
2298 /* and get the system to assign us a port */
2299 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
2301 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
2303 TRACE("Unable to bind socket\n");
2307 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
2309 TRACE("listen failed\n");
2313 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
2317 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
2319 closesocket(lpwfs
->lstnSocket
);
2320 lpwfs
->lstnSocket
= -1;
2327 /***********************************************************************
2328 * FTP_SendType (internal)
2330 * Tell server type of data being transferred
2336 * W98SE doesn't cache the type that's currently set
2337 * (i.e. it sends it always),
2338 * so we probably don't want to do that either.
2340 static BOOL
FTP_SendType(LPWININETFTPSESSIONW lpwfs
, DWORD dwType
)
2343 WCHAR type
[] = { 'I','\0' };
2344 BOOL bSuccess
= FALSE
;
2347 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
2350 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
2353 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
)/100;
2359 FTP_SetResponseError(nResCode
);
2366 /***********************************************************************
2367 * FTP_GetFileSize (internal)
2369 * Retrieves from the server the size of the given file
2376 static BOOL
FTP_GetFileSize(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD
*dwSize
)
2379 BOOL bSuccess
= FALSE
;
2383 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
2386 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2389 if (nResCode
== 213) {
2390 /* Now parses the output to get the actual file size */
2392 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2394 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
2395 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
2396 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2400 FTP_SetResponseError(nResCode
);
2409 /***********************************************************************
2410 * FTP_SendPort (internal)
2412 * Tell server which port to use
2419 static BOOL
FTP_SendPort(LPWININETFTPSESSIONW lpwfs
)
2421 static const WCHAR szIPFormat
[] = {'%','d',',','%','d',',','%','d',',','%','d',',','%','d',',','%','d','\0'};
2423 WCHAR szIPAddress
[64];
2424 BOOL bSuccess
= FALSE
;
2427 sprintfW(szIPAddress
, szIPFormat
,
2428 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2429 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2430 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2431 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2432 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2433 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2435 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2438 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2441 if (nResCode
== 200)
2444 FTP_SetResponseError(nResCode
);
2452 /***********************************************************************
2453 * FTP_DoPassive (internal)
2455 * Tell server that we want to do passive transfers
2456 * and connect data socket
2463 static BOOL
FTP_DoPassive(LPWININETFTPSESSIONW lpwfs
)
2466 BOOL bSuccess
= FALSE
;
2469 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2472 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2475 if (nResCode
== 227)
2477 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2481 char *pAddr
, *pPort
;
2483 struct sockaddr_in dataSocketAddress
;
2485 p
= lpszResponseBuffer
+4; /* skip status code */
2487 /* do a very strict check; we can improve that later. */
2489 if (strncmp(p
, "Entering Passive Mode", 21))
2491 ERR("unknown response '%.*s', aborting\n", 21, p
);
2494 p
+= 21; /* skip string */
2495 if ((*p
++ != ' ') || (*p
++ != '('))
2497 ERR("unknown response format, aborting\n");
2501 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2504 ERR("unknown response address format '%s', aborting\n", p
);
2507 for (i
=0; i
< 6; i
++)
2510 dataSocketAddress
= lpwfs
->socketAddress
;
2511 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2512 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2520 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2524 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2526 ERR("can't connect passive FTP data port.\n");
2527 closesocket(nsocket
);
2530 lpwfs
->pasvSocket
= nsocket
;
2534 FTP_SetResponseError(nResCode
);
2542 static BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONW lpwfs
)
2544 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2546 if (!FTP_DoPassive(lpwfs
))
2551 if (!FTP_SendPort(lpwfs
))
2558 /***********************************************************************
2559 * FTP_GetDataSocket (internal)
2561 * Either accepts an incoming data socket connection from the server
2562 * or just returns the already opened socket after a PASV command
2563 * in case of passive FTP.
2571 static BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONW lpwfs
, LPINT nDataSocket
)
2573 struct sockaddr_in saddr
;
2574 socklen_t addrlen
= sizeof(struct sockaddr
);
2577 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2579 *nDataSocket
= lpwfs
->pasvSocket
;
2583 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2584 closesocket(lpwfs
->lstnSocket
);
2585 lpwfs
->lstnSocket
= -1;
2587 return *nDataSocket
!= -1;
2591 /***********************************************************************
2592 * FTP_SendData (internal)
2594 * Send data to the server
2601 static BOOL
FTP_SendData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, HANDLE hFile
)
2603 BY_HANDLE_FILE_INFORMATION fi
;
2604 DWORD nBytesRead
= 0;
2605 DWORD nBytesSent
= 0;
2606 DWORD nTotalSent
= 0;
2607 DWORD nBytesToSend
, nLen
;
2609 time_t s_long_time
, e_long_time
;
2614 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2615 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2617 /* Get the size of the file. */
2618 GetFileInformationByHandle(hFile
, &fi
);
2623 nBytesToSend
= nBytesRead
- nBytesSent
;
2625 if (nBytesToSend
<= 0)
2627 /* Read data from file. */
2629 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2630 ERR("Failed reading from file\n");
2633 nBytesToSend
= nBytesRead
;
2638 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2639 DATA_PACKET_SIZE
: nBytesToSend
;
2640 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2648 /* Do some computation to display the status. */
2650 nSeconds
= e_long_time
- s_long_time
;
2651 if( nSeconds
/ 60 > 0 )
2653 TRACE( "%d bytes of %d bytes (%d%%) in %d min %d sec estimated remaining time %d sec\n",
2654 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2655 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2659 TRACE( "%d bytes of %d bytes (%d%%) in %d sec estimated remaining time %d sec\n",
2660 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2661 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2663 } while (nRC
!= -1);
2665 TRACE("file transfer complete!\n");
2667 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2673 /***********************************************************************
2674 * FTP_SendRetrieve (internal)
2676 * Send request to retrieve a file
2679 * Number of bytes to be received on success
2683 static DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONW lpwfs
, LPCWSTR lpszRemoteFile
, DWORD dwType
)
2689 if (!FTP_InitListenSocket(lpwfs
))
2692 if (!FTP_SendType(lpwfs
, dwType
))
2695 if (!FTP_SendPortOrPasv(lpwfs
))
2698 if (!FTP_GetFileSize(lpwfs
, lpszRemoteFile
, &nResult
))
2701 TRACE("Waiting to receive %d bytes\n", nResult
);
2703 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2706 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2707 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2708 /* That means that we got an error getting the file. */
2713 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2715 closesocket(lpwfs
->lstnSocket
);
2716 lpwfs
->lstnSocket
= -1;
2723 /***********************************************************************
2724 * FTP_RetrieveData (internal)
2726 * Retrieve data from server
2733 static BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONW lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2735 DWORD nBytesWritten
;
2736 DWORD nBytesReceived
= 0;
2742 if (INVALID_HANDLE_VALUE
== hFile
)
2745 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2746 if (NULL
== lpszBuffer
)
2748 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2752 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2754 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2757 /* other side closed socket. */
2760 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2761 nBytesReceived
+= nRC
;
2764 TRACE("%d bytes of %d (%d%%)\r", nBytesReceived
, nBytes
,
2765 nBytesReceived
* 100 / nBytes
);
2768 TRACE("Data transfer complete\n");
2769 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2776 /***********************************************************************
2777 * FTP_CloseSessionHandle (internal)
2779 * Deallocate session handle
2786 static void FTP_CloseSessionHandle(LPWININETHANDLEHEADER hdr
)
2788 LPWININETFTPSESSIONW lpwfs
= (LPWININETFTPSESSIONW
) hdr
;
2792 WININET_Release(&lpwfs
->lpAppInfo
->hdr
);
2794 if (lpwfs
->download_in_progress
!= NULL
)
2795 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2797 if (lpwfs
->sndSocket
!= -1)
2798 closesocket(lpwfs
->sndSocket
);
2800 if (lpwfs
->lstnSocket
!= -1)
2801 closesocket(lpwfs
->lstnSocket
);
2803 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2804 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2805 HeapFree(GetProcessHeap(), 0, lpwfs
);
2809 /***********************************************************************
2810 * FTP_FindNextFileW (Internal)
2812 * Continues a file search from a previous call to FindFirstFile
2819 BOOL WINAPI
FTP_FindNextFileW(LPWININETFTPFINDNEXTW lpwh
, LPVOID lpvFindData
)
2821 BOOL bSuccess
= TRUE
;
2822 LPWIN32_FIND_DATAW lpFindFileData
;
2824 TRACE("index(%d) size(%d)\n", lpwh
->index
, lpwh
->size
);
2826 assert (lpwh
->hdr
.htype
== WH_HFTPFINDNEXT
);
2828 /* Clear any error information */
2829 INTERNET_SetLastError(0);
2831 lpFindFileData
= (LPWIN32_FIND_DATAW
) lpvFindData
;
2832 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2834 if (lpwh
->index
>= lpwh
->size
)
2836 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2841 FTP_ConvertFileProp(&lpwh
->lpafp
[lpwh
->index
], lpFindFileData
);
2844 TRACE("\nName: %s\nSize: %d\n", debugstr_w(lpFindFileData
->cFileName
), lpFindFileData
->nFileSizeLow
);
2848 if (lpwh
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
2850 INTERNET_ASYNC_RESULT iar
;
2852 iar
.dwResult
= (DWORD
)bSuccess
;
2853 iar
.dwError
= iar
.dwError
= bSuccess
? ERROR_SUCCESS
:
2854 INTERNET_GetLastError();
2856 INTERNET_SendCallback(&lpwh
->hdr
, lpwh
->hdr
.dwContext
,
2857 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
2858 sizeof(INTERNET_ASYNC_RESULT
));
2865 /***********************************************************************
2866 * FTP_CloseFindNextHandle (internal)
2868 * Deallocate session handle
2875 static void FTP_CloseFindNextHandle(LPWININETHANDLEHEADER hdr
)
2877 LPWININETFTPFINDNEXTW lpwfn
= (LPWININETFTPFINDNEXTW
) hdr
;
2882 WININET_Release(&lpwfn
->lpFtpSession
->hdr
);
2884 for (i
= 0; i
< lpwfn
->size
; i
++)
2886 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2889 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2890 HeapFree(GetProcessHeap(), 0, lpwfn
);
2893 /***********************************************************************
2894 * FTP_CloseFileTransferHandle (internal)
2896 * Closes the file transfer handle. This also 'cleans' the data queue of
2897 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2900 static void FTP_CloseFileTransferHandle(LPWININETHANDLEHEADER hdr
)
2902 LPWININETFTPFILE lpwh
= (LPWININETFTPFILE
) hdr
;
2903 LPWININETFTPSESSIONW lpwfs
= lpwh
->lpFtpSession
;
2908 WININET_Release(&lpwh
->lpFtpSession
->hdr
);
2910 if (!lpwh
->session_deleted
)
2911 lpwfs
->download_in_progress
= NULL
;
2913 /* This just serves to flush the control socket of any spurrious lines written
2914 to it (like '226 Transfer complete.').
2916 Wonder what to do if the server sends us an error code though...
2918 nResCode
= FTP_ReceiveResponse(lpwfs
, lpwfs
->hdr
.dwContext
);
2920 if (lpwh
->nDataSocket
!= -1)
2921 closesocket(lpwh
->nDataSocket
);
2923 HeapFree(GetProcessHeap(), 0, lpwh
);
2926 /***********************************************************************
2927 * FTP_ReceiveFileList (internal)
2929 * Read file list from server
2932 * Handle to file list on success
2936 static HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
2937 LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwContext
)
2940 LPFILEPROPERTIESW lpafp
= NULL
;
2941 LPWININETFTPFINDNEXTW lpwfn
= NULL
;
2942 HINTERNET handle
= 0;
2944 TRACE("(%p,%d,%s,%p,%d)\n", lpwfs
, nSocket
, debugstr_w(lpszSearchFile
), lpFindFileData
, dwContext
);
2946 if (FTP_ParseDirectory(lpwfs
, nSocket
, lpszSearchFile
, &lpafp
, &dwSize
))
2949 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2951 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFTPFINDNEXTW
));
2954 lpwfn
->hdr
.htype
= WH_HFTPFINDNEXT
;
2955 lpwfn
->hdr
.dwContext
= dwContext
;
2956 lpwfn
->hdr
.dwRefCount
= 1;
2957 lpwfn
->hdr
.destroy
= FTP_CloseFindNextHandle
;
2958 lpwfn
->hdr
.lpfnStatusCB
= lpwfs
->hdr
.lpfnStatusCB
;
2959 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2960 lpwfn
->size
= dwSize
;
2961 lpwfn
->lpafp
= lpafp
;
2963 WININET_AddRef( &lpwfs
->hdr
);
2964 lpwfn
->lpFtpSession
= lpwfs
;
2966 handle
= WININET_AllocHandle( &lpwfn
->hdr
);
2971 WININET_Release( &lpwfn
->hdr
);
2973 TRACE("Matched %d files\n", dwSize
);
2978 /***********************************************************************
2979 * FTP_ConvertFileProp (internal)
2981 * Converts FILEPROPERTIESW struct to WIN32_FIND_DATAA
2988 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESW lpafp
, LPWIN32_FIND_DATAW lpFindFileData
)
2990 BOOL bSuccess
= FALSE
;
2992 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAW
));
2996 /* Convert 'Unix' time to Windows time */
2997 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
2998 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
2999 lpFindFileData
->ftLastWriteTime
= lpFindFileData
->ftLastAccessTime
;
3000 lpFindFileData
->ftCreationTime
= lpFindFileData
->ftLastAccessTime
;
3002 /* Not all fields are filled in */
3003 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
3004 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
3006 if (lpafp
->bIsDirectory
)
3007 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
3009 if (lpafp
->lpszName
)
3010 lstrcpynW(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
3018 /***********************************************************************
3019 * FTP_ParseNextFile (internal)
3021 * Parse the next line in file listing
3027 static BOOL
FTP_ParseNextFile(INT nSocket
, LPCWSTR lpszSearchFile
, LPFILEPROPERTIESW lpfp
)
3029 static const char szSpace
[] = " \t";
3037 lpfp
->lpszName
= NULL
;
3039 if(!(pszLine
= INTERNET_GetNextLine(nSocket
, &nBufLen
)))
3042 pszToken
= strtok(pszLine
, szSpace
);
3044 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
3047 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
3049 if(!isdigit(pszToken
[0]) && 10 == strlen(pszToken
)) {
3050 if(!FTP_ParsePermission(pszToken
, lpfp
))
3051 lpfp
->bIsDirectory
= FALSE
;
3052 for(i
=0; i
<=3; i
++) {
3053 if(!(pszToken
= strtok(NULL
, szSpace
)))
3056 if(!pszToken
) continue;
3057 if(lpfp
->bIsDirectory
) {
3058 TRACE("Is directory\n");
3062 TRACE("Size: %s\n", pszToken
);
3063 lpfp
->nSize
= atol(pszToken
);
3066 lpfp
->tmLastModified
.tm_sec
= 0;
3067 lpfp
->tmLastModified
.tm_min
= 0;
3068 lpfp
->tmLastModified
.tm_hour
= 0;
3069 lpfp
->tmLastModified
.tm_mday
= 0;
3070 lpfp
->tmLastModified
.tm_mon
= 0;
3071 lpfp
->tmLastModified
.tm_year
= 0;
3073 /* Determine month */
3074 pszToken
= strtok(NULL
, szSpace
);
3075 if(!pszToken
) continue;
3076 if(strlen(pszToken
) >= 3) {
3078 if((pszTmp
= StrStrIA(szMonths
, pszToken
)))
3079 lpfp
->tmLastModified
.tm_mon
= ((pszTmp
- szMonths
) / 3)+1;
3082 pszToken
= strtok(NULL
, szSpace
);
3083 if(!pszToken
) continue;
3084 lpfp
->tmLastModified
.tm_mday
= atoi(pszToken
);
3085 /* Determine time or year */
3086 pszToken
= strtok(NULL
, szSpace
);
3087 if(!pszToken
) continue;
3088 if((pszTmp
= strchr(pszToken
, ':'))) {
3093 lpfp
->tmLastModified
.tm_min
= atoi(pszTmp
);
3094 lpfp
->tmLastModified
.tm_hour
= atoi(pszToken
);
3096 apTM
= localtime(&aTime
);
3097 lpfp
->tmLastModified
.tm_year
= apTM
->tm_year
;
3100 lpfp
->tmLastModified
.tm_year
= atoi(pszToken
) - 1900;
3101 lpfp
->tmLastModified
.tm_hour
= 12;
3103 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3104 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3105 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3106 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3108 pszToken
= strtok(NULL
, szSpace
);
3109 if(!pszToken
) continue;
3110 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3111 TRACE("File: %s\n", debugstr_w(lpfp
->lpszName
));
3113 /* NT way of parsing ... :
3115 07-13-03 08:55PM <DIR> sakpatch
3116 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
3118 else if(isdigit(pszToken
[0]) && 8 == strlen(pszToken
)) {
3119 lpfp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
3121 sscanf(pszToken
, "%d-%d-%d",
3122 &lpfp
->tmLastModified
.tm_mon
,
3123 &lpfp
->tmLastModified
.tm_mday
,
3124 &lpfp
->tmLastModified
.tm_year
);
3126 /* Hacky and bad Y2K protection :-) */
3127 if (lpfp
->tmLastModified
.tm_year
< 70)
3128 lpfp
->tmLastModified
.tm_year
+= 100;
3130 pszToken
= strtok(NULL
, szSpace
);
3131 if(!pszToken
) continue;
3132 sscanf(pszToken
, "%d:%d",
3133 &lpfp
->tmLastModified
.tm_hour
,
3134 &lpfp
->tmLastModified
.tm_min
);
3135 if((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
3136 lpfp
->tmLastModified
.tm_hour
+= 12;
3138 lpfp
->tmLastModified
.tm_sec
= 0;
3140 TRACE("Mod time: %02d:%02d:%02d %02d/%02d/%02d\n",
3141 lpfp
->tmLastModified
.tm_hour
, lpfp
->tmLastModified
.tm_min
, lpfp
->tmLastModified
.tm_sec
,
3142 (lpfp
->tmLastModified
.tm_year
>= 100) ? lpfp
->tmLastModified
.tm_year
- 100 : lpfp
->tmLastModified
.tm_year
,
3143 lpfp
->tmLastModified
.tm_mon
, lpfp
->tmLastModified
.tm_mday
);
3145 pszToken
= strtok(NULL
, szSpace
);
3146 if(!pszToken
) continue;
3147 if(!strcasecmp(pszToken
, "<DIR>")) {
3148 lpfp
->bIsDirectory
= TRUE
;
3150 TRACE("Is directory\n");
3153 lpfp
->bIsDirectory
= FALSE
;
3154 lpfp
->nSize
= atol(pszToken
);
3155 TRACE("Size: %d\n", lpfp
->nSize
);
3158 pszToken
= strtok(NULL
, szSpace
);
3159 if(!pszToken
) continue;
3160 lpfp
->lpszName
= WININET_strdup_AtoW(pszToken
);
3161 TRACE("Name: %s\n", debugstr_w(lpfp
->lpszName
));
3163 /* EPLF format - http://cr.yp.to/ftp/list/eplf.html */
3164 else if(pszToken
[0] == '+') {
3165 FIXME("EPLF Format not implemented\n");
3168 if(lpfp
->lpszName
) {
3169 if((lpszSearchFile
== NULL
) ||
3170 (PathMatchSpecW(lpfp
->lpszName
, lpszSearchFile
))) {
3172 TRACE("Matched: %s\n", debugstr_w(lpfp
->lpszName
));
3175 HeapFree(GetProcessHeap(), 0, lpfp
->lpszName
);
3176 lpfp
->lpszName
= NULL
;
3183 /***********************************************************************
3184 * FTP_ParseDirectory (internal)
3186 * Parse string of directory information
3192 static BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONW lpwfs
, INT nSocket
, LPCWSTR lpszSearchFile
,
3193 LPFILEPROPERTIESW
*lpafp
, LPDWORD dwfp
)
3195 BOOL bSuccess
= TRUE
;
3196 INT sizeFilePropArray
= 500;/*20; */
3197 INT indexFilePropArray
= -1;
3201 /* Allocate intial file properties array */
3202 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESW
)*(sizeFilePropArray
));
3207 if (indexFilePropArray
+1 >= sizeFilePropArray
)
3209 LPFILEPROPERTIESW tmpafp
;
3211 sizeFilePropArray
*= 2;
3212 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
3213 sizeof(FILEPROPERTIESW
)*sizeFilePropArray
);
3222 indexFilePropArray
++;
3223 } while (FTP_ParseNextFile(nSocket
, lpszSearchFile
, &(*lpafp
)[indexFilePropArray
]));
3225 if (bSuccess
&& indexFilePropArray
)
3227 if (indexFilePropArray
< sizeFilePropArray
- 1)
3229 LPFILEPROPERTIESW tmpafp
;
3231 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
3232 sizeof(FILEPROPERTIESW
)*indexFilePropArray
);
3236 *dwfp
= indexFilePropArray
;
3240 HeapFree(GetProcessHeap(), 0, *lpafp
);
3241 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
3249 /***********************************************************************
3250 * FTP_ParsePermission (internal)
3252 * Parse permission string of directory information
3259 static BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESW lpfp
)
3261 BOOL bSuccess
= TRUE
;
3262 unsigned short nPermission
= 0;
3267 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
3273 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
3279 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
3282 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
3285 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
3288 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
3291 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
3294 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
3297 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
3300 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
3303 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
3307 }while (nPos
<= nLast
);
3309 lpfp
->permissions
= nPermission
;
3314 /***********************************************************************
3315 * FTP_SetResponseError (internal)
3317 * Set the appropriate error code for a given response from the server
3322 static DWORD
FTP_SetResponseError(DWORD dwResponse
)
3328 case 421: /* Service not available - Server may be shutting down. */
3329 dwCode
= ERROR_INTERNET_TIMEOUT
;
3332 case 425: /* Cannot open data connection. */
3333 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
3336 case 426: /* Connection closed, transer aborted. */
3337 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
3340 case 500: /* Syntax error. Command unrecognized. */
3341 case 501: /* Syntax error. Error in parameters or arguments. */
3342 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
3345 case 530: /* Not logged in. Login incorrect. */
3346 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
3349 case 550: /* File action not taken. File not found or no access. */
3350 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
3353 case 450: /* File action not taken. File may be busy. */
3354 case 451: /* Action aborted. Server error. */
3355 case 452: /* Action not taken. Insufficient storage space on server. */
3356 case 502: /* Command not implemented. */
3357 case 503: /* Bad sequence of command. */
3358 case 504: /* Command not implemented for that parameter. */
3359 case 532: /* Need account for storing files */
3360 case 551: /* Requested action aborted. Page type unknown */
3361 case 552: /* Action aborted. Exceeded storage allocation */
3362 case 553: /* Action not taken. File name not allowed. */
3365 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
3369 INTERNET_SetLastError(dwCode
);