2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2004 Mike McCormack for CodeWeavers
10 * Copyright 2000 Andreas Mohr
11 * Copyright 2002 Jaco Greeff
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "wine/port.h"
36 #include <sys/types.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 # include <sys/socket.h>
55 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
60 #define NOACCOUNT "noaccount"
61 #define DATA_PACKET_SIZE 0x2000
66 /* FTP commands with arguments. */
82 /* FTP commands without arguments. */
91 static const CHAR
*szFtpCommands
[] = {
114 static const CHAR szMonths
[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
116 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
117 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
);
118 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
);
119 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
);
120 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
);
121 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
122 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
);
123 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
);
124 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
);
125 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
);
126 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
);
127 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
);
128 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
);
129 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
);
130 BOOL
FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD
*dwSize
);
131 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
);
132 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
);
133 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
);
134 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
);
135 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
);
136 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
137 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
);
138 DWORD
FTP_SetResponseError(DWORD dwResponse
);
140 inline static LPSTR
FTP_strdup( LPCSTR str
)
142 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, strlen(str
) + 1 );
143 if (ret
) strcpy( ret
, str
);
147 inline static LPSTR
FTP_strdup_WtoA( LPCWSTR str
)
149 int len
= WideCharToMultiByte( CP_ACP
, 0, str
, -1, NULL
, 0, NULL
, NULL
);
150 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, len
);
152 WideCharToMultiByte( CP_ACP
, 0, str
, -1, ret
, len
, NULL
, NULL
);
156 /***********************************************************************
157 * FtpPutFileA (WININET.@)
159 * Uploads a file to the FTP server
166 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
167 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
169 LPWININETFTPSESSIONA lpwfs
;
170 LPWININETAPPINFOW hIC
= NULL
;
172 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
173 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
175 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
179 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
180 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
182 WORKREQUEST workRequest
;
183 struct WORKREQ_FTPPUTFILEA
*req
= &workRequest
.u
.FtpPutFileA
;
185 workRequest
.asyncall
= FTPPUTFILEA
;
186 workRequest
.handle
= hConnect
;
187 req
->lpszLocalFile
= FTP_strdup(lpszLocalFile
);
188 req
->lpszNewRemoteFile
= FTP_strdup(lpszNewRemoteFile
);
189 req
->dwFlags
= dwFlags
;
190 req
->dwContext
= dwContext
;
192 return INTERNET_AsyncCall(&workRequest
);
196 return FTP_FtpPutFileA(hConnect
, lpszLocalFile
,
197 lpszNewRemoteFile
, dwFlags
, dwContext
);
201 /***********************************************************************
202 * FTP_FtpPutFileA (Internal)
204 * Uploads a file to the FTP server
211 BOOL WINAPI
FTP_FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
212 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
215 BOOL bSuccess
= FALSE
;
216 LPWININETAPPINFOW hIC
= NULL
;
217 LPWININETFTPSESSIONA lpwfs
;
220 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile
, lpszNewRemoteFile
);
222 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
223 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
225 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
229 /* Clear any error information */
230 INTERNET_SetLastError(0);
232 /* Open file to be uploaded */
233 if (INVALID_HANDLE_VALUE
==
234 (hFile
= CreateFileA(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
236 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND
);
240 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
241 if (hIC
->lpfnStatusCB
)
242 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
244 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
248 /* Get data socket to server */
249 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
251 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
253 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
254 MAX_REPLY_LEN
, 0, 0, 0);
260 FTP_SetResponseError(nResCode
);
266 if (lpwfs
->lstnSocket
!= -1)
267 close(lpwfs
->lstnSocket
);
269 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
271 INTERNET_ASYNC_RESULT iar
;
273 iar
.dwResult
= (DWORD
)bSuccess
;
274 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
275 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
276 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
286 /***********************************************************************
287 * FtpSetCurrentDirectoryA (WININET.@)
289 * Change the working directory on the FTP server
296 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
298 LPWININETFTPSESSIONA lpwfs
;
299 LPWININETAPPINFOW hIC
= NULL
;
301 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
302 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
304 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
308 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
310 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
311 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
313 WORKREQUEST workRequest
;
314 struct WORKREQ_FTPSETCURRENTDIRECTORYA
*req
;
316 workRequest
.asyncall
= FTPSETCURRENTDIRECTORYA
;
317 workRequest
.handle
= hConnect
;
318 req
= &workRequest
.u
.FtpSetCurrentDirectoryA
;
319 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
321 return INTERNET_AsyncCall(&workRequest
);
325 return FTP_FtpSetCurrentDirectoryA(hConnect
, lpszDirectory
);
330 /***********************************************************************
331 * FtpSetCurrentDirectoryW (WININET.@)
333 * Change the working directory on the FTP server
340 BOOL WINAPI
FtpSetCurrentDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
346 len
= WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, NULL
, 0, NULL
, NULL
);
347 szDir
= HeapAlloc(GetProcessHeap(), 0, len
);
350 WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, szDir
, len
, NULL
, NULL
);
351 rc
= FtpSetCurrentDirectoryA(hConnect
, szDir
);
352 HeapFree(GetProcessHeap(), 0, szDir
);
358 /***********************************************************************
359 * FTP_FtpSetCurrentDirectoryA (Internal)
361 * Change the working directory on the FTP server
368 BOOL WINAPI
FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
371 LPWININETFTPSESSIONA lpwfs
;
372 LPWININETAPPINFOW hIC
= NULL
;
373 DWORD bSuccess
= FALSE
;
375 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
377 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
378 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
380 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
384 /* Clear any error information */
385 INTERNET_SetLastError(0);
387 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
388 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
389 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
392 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
393 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
400 FTP_SetResponseError(nResCode
);
404 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
406 INTERNET_ASYNC_RESULT iar
;
408 iar
.dwResult
= (DWORD
)bSuccess
;
409 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
410 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
411 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
417 /***********************************************************************
418 * FtpCreateDirectoryA (WININET.@)
420 * Create new directory on the FTP server
427 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
429 LPWININETFTPSESSIONA lpwfs
;
430 LPWININETAPPINFOW hIC
= NULL
;
432 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
433 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
435 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
439 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
440 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
442 WORKREQUEST workRequest
;
443 struct WORKREQ_FTPCREATEDIRECTORYA
*req
;
445 workRequest
.asyncall
= FTPCREATEDIRECTORYA
;
446 workRequest
.handle
= hConnect
;
447 req
= &workRequest
.u
.FtpCreateDirectoryA
;
448 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
450 return INTERNET_AsyncCall(&workRequest
);
454 return FTP_FtpCreateDirectoryA(hConnect
, lpszDirectory
);
459 /***********************************************************************
460 * FtpCreateDirectoryW (WININET.@)
462 * Create new directory on the FTP server
469 BOOL WINAPI
FtpCreateDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
475 len
= WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, NULL
, 0, NULL
, NULL
);
476 szDir
= HeapAlloc(GetProcessHeap(), 0, len
);
479 WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, szDir
, len
, NULL
, NULL
);
480 rc
= FtpCreateDirectoryA(hConnect
, szDir
);
481 HeapFree(GetProcessHeap(), 0, szDir
);
487 /***********************************************************************
488 * FTP_FtpCreateDirectoryA (Internal)
490 * Create new directory on the FTP server
497 BOOL WINAPI
FTP_FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
500 BOOL bSuccess
= FALSE
;
501 LPWININETAPPINFOW hIC
= NULL
;
502 LPWININETFTPSESSIONA lpwfs
;
506 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
507 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
509 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
513 /* Clear any error information */
514 INTERNET_SetLastError(0);
516 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
519 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
520 MAX_REPLY_LEN
, 0, 0, 0);
526 FTP_SetResponseError(nResCode
);
530 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
531 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
533 INTERNET_ASYNC_RESULT iar
;
535 iar
.dwResult
= (DWORD
)bSuccess
;
536 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
537 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
538 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
545 /***********************************************************************
546 * FtpFindFirstFileA (WININET.@)
548 * Search the specified directory
551 * HINTERNET on success
555 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
556 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
558 LPWININETFTPSESSIONA lpwfs
;
559 LPWININETAPPINFOW hIC
= NULL
;
561 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
562 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
564 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
568 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
569 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
571 WORKREQUEST workRequest
;
572 struct WORKREQ_FTPFINDFIRSTFILEA
*req
;
574 workRequest
.asyncall
= FTPFINDFIRSTFILEA
;
575 workRequest
.handle
= hConnect
;
576 req
= &workRequest
.u
.FtpFindFirstFileA
;
577 req
->lpszSearchFile
= FTP_strdup(lpszSearchFile
);
578 req
->lpFindFileData
= lpFindFileData
;
579 req
->dwFlags
= dwFlags
;
580 req
->dwContext
= dwContext
;
582 INTERNET_AsyncCall(&workRequest
);
587 return FTP_FtpFindFirstFileA(hConnect
, lpszSearchFile
, lpFindFileData
,
593 /***********************************************************************
594 * FtpFindFirstFileA (WININET.@)
596 * Search the specified directory
599 * HINTERNET on success
603 HINTERNET WINAPI
FtpFindFirstFileW(HINTERNET hConnect
,
604 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
611 /***********************************************************************
612 * FTP_FtpFindFirstFileA (Internal)
614 * Search the specified directory
617 * HINTERNET on success
621 HINTERNET WINAPI
FTP_FtpFindFirstFileA(HINTERNET hConnect
,
622 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
625 LPWININETAPPINFOW hIC
= NULL
;
626 LPWININETFTPSESSIONA lpwfs
;
627 HINTERNET hFindNext
= NULL
;
631 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
632 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
634 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
638 /* Clear any error information */
639 INTERNET_SetLastError(0);
641 if (!FTP_InitListenSocket(lpwfs
))
644 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
647 if (!FTP_SendPortOrPasv(lpwfs
))
650 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
651 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, lpszSearchFile
,
652 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
655 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
656 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
659 if (nResCode
== 125 || nResCode
== 150)
663 /* Get data socket to server */
664 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
666 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpFindFileData
, dwContext
);
668 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
669 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
670 if (nResCode
!= 226 && nResCode
!= 250)
671 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
677 FTP_SetResponseError(nResCode
);
681 if (lpwfs
->lstnSocket
!= -1)
682 close(lpwfs
->lstnSocket
);
684 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
686 INTERNET_ASYNC_RESULT iar
;
690 iar
.dwResult
= (DWORD
)hFindNext
;
691 iar
.dwError
= ERROR_SUCCESS
;
692 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
693 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
696 iar
.dwResult
= (DWORD
)hFindNext
;
697 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
698 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
699 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
706 /***********************************************************************
707 * FtpGetCurrentDirectoryA (WININET.@)
709 * Retrieves the current directory
716 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
717 LPDWORD lpdwCurrentDirectory
)
719 LPWININETFTPSESSIONA lpwfs
;
720 LPWININETAPPINFOW hIC
= NULL
;
722 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
724 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
725 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
727 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
731 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
732 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
734 WORKREQUEST workRequest
;
735 struct WORKREQ_FTPGETCURRENTDIRECTORYA
*req
;
737 workRequest
.asyncall
= FTPGETCURRENTDIRECTORYA
;
738 workRequest
.handle
= hFtpSession
;
739 req
= &workRequest
.u
.FtpGetCurrentDirectoryA
;
740 req
->lpszDirectory
= lpszCurrentDirectory
;
741 req
->lpdwDirectory
= lpdwCurrentDirectory
;
743 return INTERNET_AsyncCall(&workRequest
);
747 return FTP_FtpGetCurrentDirectoryA(hFtpSession
, lpszCurrentDirectory
,
748 lpdwCurrentDirectory
);
753 /***********************************************************************
754 * FtpGetCurrentDirectoryW (WININET.@)
756 * Retrieves the current directory
763 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
764 LPDWORD lpdwCurrentDirectory
)
771 /***********************************************************************
772 * FTP_FtpGetCurrentDirectoryA (Internal)
774 * Retrieves the current directory
781 BOOL WINAPI
FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
782 LPDWORD lpdwCurrentDirectory
)
785 LPWININETFTPSESSIONA lpwfs
;
786 LPWININETAPPINFOW hIC
= NULL
;
787 DWORD bSuccess
= FALSE
;
789 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
791 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
792 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
794 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
798 /* Clear any error information */
799 INTERNET_SetLastError(0);
801 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
803 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
804 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
805 hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
))
808 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
809 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
);
812 if (nResCode
== 257) /* Extract directory name */
814 INT firstpos
, lastpos
, len
;
815 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
817 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
819 if ('"' == lpszResponseBuffer
[lastpos
])
828 len
= lastpos
- firstpos
- 1;
829 strncpy(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1],
830 len
< *lpdwCurrentDirectory
? len
: *lpdwCurrentDirectory
);
831 *lpdwCurrentDirectory
= len
;
835 FTP_SetResponseError(nResCode
);
839 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
841 INTERNET_ASYNC_RESULT iar
;
843 iar
.dwResult
= (DWORD
)bSuccess
;
844 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
845 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
846 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
849 return (DWORD
) bSuccess
;
852 /***********************************************************************
853 * FtpOpenFileA (WININET.@)
855 * Open a remote file for writing or reading
858 * HINTERNET handle on success
862 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
863 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
866 LPWININETFTPSESSIONA lpwfs
;
867 LPWININETAPPINFOW hIC
= NULL
;
869 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
870 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
872 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
876 if (lpwfs
->download_in_progress
!= NULL
) {
877 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
881 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
882 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
884 WORKREQUEST workRequest
;
885 struct WORKREQ_FTPOPENFILEA
*req
;
887 workRequest
.asyncall
= FTPOPENFILEA
;
888 workRequest
.handle
= hFtpSession
;
889 req
= &workRequest
.u
.FtpOpenFileA
;
890 req
->lpszFilename
= FTP_strdup(lpszFileName
);
891 req
->dwAccess
= fdwAccess
;
892 req
->dwFlags
= dwFlags
;
893 req
->dwContext
= dwContext
;
895 INTERNET_AsyncCall(&workRequest
);
900 return FTP_FtpOpenFileA(hFtpSession
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
905 /***********************************************************************
906 * FtpOpenFileW (WININET.@)
908 * Open a remote file for writing or reading
911 * HINTERNET handle on success
915 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
916 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
924 /***********************************************************************
925 * FTP_FtpOpenFileA (Internal)
927 * Open a remote file for writing or reading
930 * HINTERNET handle on success
934 HINTERNET
FTP_FtpOpenFileA(HINTERNET hFtpSession
,
935 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
939 BOOL bSuccess
= FALSE
;
940 LPWININETFILE lpwh
= NULL
;
941 LPWININETAPPINFOW hIC
= NULL
;
942 LPWININETFTPSESSIONA lpwfs
;
943 HINTERNET handle
= NULL
;
947 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
948 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
950 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
954 /* Clear any error information */
955 INTERNET_SetLastError(0);
957 if (GENERIC_READ
== fdwAccess
)
959 /* Set up socket to retrieve data */
960 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
962 else if (GENERIC_WRITE
== fdwAccess
)
964 /* Set up socket to send data */
965 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
968 /* Get data socket to server */
969 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
971 lpwh
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE
));
972 handle
= WININET_AllocHandle( &lpwh
->hdr
);
973 lpwh
->hdr
.htype
= WH_HFILE
;
974 lpwh
->hdr
.dwFlags
= dwFlags
;
975 lpwh
->hdr
.dwContext
= dwContext
;
976 lpwh
->hdr
.lpwhparent
= &lpwfs
->hdr
;
977 lpwh
->nDataSocket
= nDataSocket
;
978 lpwh
->session_deleted
= FALSE
;
980 /* Indicate that a download is currently in progress */
981 lpwfs
->download_in_progress
= lpwh
;
984 if (lpwfs
->lstnSocket
!= -1)
985 close(lpwfs
->lstnSocket
);
987 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
988 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
990 INTERNET_ASYNC_RESULT iar
;
994 iar
.dwResult
= (DWORD
)handle
;
995 iar
.dwError
= ERROR_SUCCESS
;
996 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
997 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1000 iar
.dwResult
= (DWORD
)bSuccess
;
1001 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1002 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1003 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1010 /***********************************************************************
1011 * FtpGetFileA (WININET.@)
1013 * Retrieve file from the FTP server
1020 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1021 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1024 LPWININETFTPSESSIONA lpwfs
;
1025 LPWININETAPPINFOW hIC
= NULL
;
1027 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hInternet
);
1028 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1030 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1034 if (lpwfs
->download_in_progress
!= NULL
) {
1035 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1039 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1040 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1042 WORKREQUEST workRequest
;
1043 struct WORKREQ_FTPGETFILEA
*req
;
1045 workRequest
.asyncall
= FTPGETFILEA
;
1046 workRequest
.handle
= hInternet
;
1047 req
= &workRequest
.u
.FtpGetFileA
;
1048 req
->lpszRemoteFile
= FTP_strdup(lpszRemoteFile
);
1049 req
->lpszNewFile
= FTP_strdup(lpszNewFile
);
1050 req
->dwLocalFlagsAttribute
= dwLocalFlagsAttribute
;
1051 req
->fFailIfExists
= fFailIfExists
;
1052 req
->dwFlags
= dwInternetFlags
;
1053 req
->dwContext
= dwContext
;
1055 return INTERNET_AsyncCall(&workRequest
);
1059 return FTP_FtpGetFileA(hInternet
, lpszRemoteFile
, lpszNewFile
,
1060 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1065 /***********************************************************************
1066 * FtpGetFileW (WININET.@)
1068 * Retrieve file from the FTP server
1075 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1076 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1084 /***********************************************************************
1085 * FTP_FtpGetFileA (Internal)
1087 * Retrieve file from the FTP server
1094 BOOL WINAPI
FTP_FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1095 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1099 BOOL bSuccess
= FALSE
;
1101 LPWININETAPPINFOW hIC
= NULL
;
1102 LPWININETFTPSESSIONA lpwfs
;
1104 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile
, lpszNewFile
);
1106 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hInternet
);
1107 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1109 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1113 /* Clear any error information */
1114 INTERNET_SetLastError(0);
1116 /* Ensure we can write to lpszNewfile by opening it */
1117 hFile
= CreateFileA(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1118 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1119 if (INVALID_HANDLE_VALUE
== hFile
)
1122 /* Set up socket to retrieve data */
1123 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
1129 /* Get data socket to server */
1130 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1135 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
1136 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1137 MAX_REPLY_LEN
, 0, 0, 0);
1140 if (nResCode
== 226)
1143 FTP_SetResponseError(nResCode
);
1150 if (lpwfs
->lstnSocket
!= -1)
1151 close(lpwfs
->lstnSocket
);
1156 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1157 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1159 INTERNET_ASYNC_RESULT iar
;
1161 iar
.dwResult
= (DWORD
)bSuccess
;
1162 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1163 hIC
->lpfnStatusCB(hInternet
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1164 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1171 /***********************************************************************
1172 * FtpDeleteFileA (WININET.@)
1174 * Delete a file on the ftp server
1181 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1183 LPWININETFTPSESSIONA lpwfs
;
1184 LPWININETAPPINFOW hIC
= NULL
;
1186 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1187 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1189 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1193 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1194 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1196 WORKREQUEST workRequest
;
1197 struct WORKREQ_FTPDELETEFILEA
*req
;
1199 workRequest
.asyncall
= FTPDELETEFILEA
;
1200 workRequest
.handle
= hFtpSession
;
1201 req
= &workRequest
.u
.FtpDeleteFileA
;
1202 req
->lpszFilename
= FTP_strdup(lpszFileName
);
1204 return INTERNET_AsyncCall(&workRequest
);
1208 return FTP_FtpDeleteFileA(hFtpSession
, lpszFileName
);
1213 /***********************************************************************
1214 * FTP_FtpDeleteFileA (Internal)
1216 * Delete a file on the ftp server
1223 BOOL
FTP_FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1226 BOOL bSuccess
= FALSE
;
1227 LPWININETAPPINFOW hIC
= NULL
;
1228 LPWININETFTPSESSIONA lpwfs
;
1230 TRACE("0x%08lx\n", (ULONG
) hFtpSession
);
1232 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1233 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1235 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1239 /* Clear any error information */
1240 INTERNET_SetLastError(0);
1242 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1245 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1246 MAX_REPLY_LEN
, 0, 0, 0);
1249 if (nResCode
== 250)
1252 FTP_SetResponseError(nResCode
);
1255 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1256 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1258 INTERNET_ASYNC_RESULT iar
;
1260 iar
.dwResult
= (DWORD
)bSuccess
;
1261 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1262 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1263 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1270 /***********************************************************************
1271 * FtpRemoveDirectoryA (WININET.@)
1273 * Remove a directory on the ftp server
1280 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1282 LPWININETFTPSESSIONA lpwfs
;
1283 LPWININETAPPINFOW hIC
= NULL
;
1285 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1286 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1288 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1292 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1293 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1295 WORKREQUEST workRequest
;
1296 struct WORKREQ_FTPREMOVEDIRECTORYA
*req
;
1298 workRequest
.asyncall
= FTPREMOVEDIRECTORYA
;
1299 workRequest
.handle
= hFtpSession
;
1300 req
= &workRequest
.u
.FtpRemoveDirectoryA
;
1301 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
1303 return INTERNET_AsyncCall(&workRequest
);
1307 return FTP_FtpRemoveDirectoryA(hFtpSession
, lpszDirectory
);
1312 /***********************************************************************
1313 * FTP_FtpRemoveDirectoryA (Internal)
1315 * Remove a directory on the ftp server
1322 BOOL
FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1325 BOOL bSuccess
= FALSE
;
1326 LPWININETAPPINFOW hIC
= NULL
;
1327 LPWININETFTPSESSIONA lpwfs
;
1331 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1332 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1334 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1338 /* Clear any error information */
1339 INTERNET_SetLastError(0);
1341 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1344 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1345 MAX_REPLY_LEN
, 0, 0, 0);
1348 if (nResCode
== 250)
1351 FTP_SetResponseError(nResCode
);
1355 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1356 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1358 INTERNET_ASYNC_RESULT iar
;
1360 iar
.dwResult
= (DWORD
)bSuccess
;
1361 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1362 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1363 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1370 /***********************************************************************
1371 * FtpRenameFileA (WININET.@)
1373 * Rename a file on the ftp server
1380 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1382 LPWININETFTPSESSIONA lpwfs
;
1383 LPWININETAPPINFOW hIC
= NULL
;
1385 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1386 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1388 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1392 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1393 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1395 WORKREQUEST workRequest
;
1396 struct WORKREQ_FTPRENAMEFILEA
*req
;
1398 workRequest
.asyncall
= FTPRENAMEFILEA
;
1399 workRequest
.handle
= hFtpSession
;
1400 req
= &workRequest
.u
.FtpRenameFileA
;
1401 req
->lpszSrcFile
= FTP_strdup(lpszSrc
);
1402 req
->lpszDestFile
= FTP_strdup(lpszDest
);
1404 return INTERNET_AsyncCall(&workRequest
);
1408 return FTP_FtpRenameFileA(hFtpSession
, lpszSrc
, lpszDest
);
1412 /***********************************************************************
1413 * FTP_FtpRenameFileA (Internal)
1415 * Rename a file on the ftp server
1422 BOOL
FTP_FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1425 BOOL bSuccess
= FALSE
;
1426 LPWININETAPPINFOW hIC
= NULL
;
1427 LPWININETFTPSESSIONA lpwfs
;
1431 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1432 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1434 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1438 /* Clear any error information */
1439 INTERNET_SetLastError(0);
1441 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1444 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1445 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1446 if (nResCode
== 350)
1448 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1451 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1452 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1455 if (nResCode
== 250)
1458 FTP_SetResponseError(nResCode
);
1461 hIC
= (LPWININETAPPINFOW
) lpwfs
->hdr
.lpwhparent
;
1462 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1464 INTERNET_ASYNC_RESULT iar
;
1466 iar
.dwResult
= (DWORD
)bSuccess
;
1467 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1468 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1469 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1476 /***********************************************************************
1477 * FTP_Connect (internal)
1479 * Connect to a ftp server
1482 * HINTERNET a session handle on success
1487 HINTERNET
FTP_Connect(HINTERNET hInternet
, LPCWSTR lpszServerName
,
1488 INTERNET_PORT nServerPort
, LPCWSTR lpszUserName
,
1489 LPCWSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
,
1490 DWORD dwInternalFlags
)
1492 struct sockaddr_in socketAddr
;
1493 struct hostent
*phe
= NULL
;
1494 INT nsocket
= -1, sock_namelen
;
1495 LPWININETAPPINFOW hIC
= NULL
;
1496 BOOL bSuccess
= FALSE
;
1497 LPWININETFTPSESSIONA lpwfs
= NULL
;
1498 HINTERNET handle
= NULL
;
1500 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1501 (ULONG
) hInternet
, debugstr_w(lpszServerName
),
1502 nServerPort
, debugstr_w(lpszUserName
), debugstr_w(lpszPassword
));
1504 hIC
= (LPWININETAPPINFOW
) WININET_GetObject( hInternet
);
1505 if ( (hIC
== NULL
) || (hIC
->hdr
.htype
!= WH_HINIT
) )
1508 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1510 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME
);
1514 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1515 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1517 if (hIC
->lpfnStatusCB
)
1518 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1519 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1521 if (!GetAddress(lpszServerName
, nServerPort
, &phe
, &socketAddr
))
1523 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1527 if (hIC
->lpfnStatusCB
)
1528 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1529 (LPWSTR
) lpszServerName
, strlenW(lpszServerName
));
1531 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1534 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1538 if (hIC
->lpfnStatusCB
)
1539 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1540 &socketAddr
, sizeof(struct sockaddr_in
));
1542 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1544 ERR("Unable to connect (%s)\n", strerror(errno
));
1545 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1549 TRACE("Connected to server\n");
1550 if (hIC
->lpfnStatusCB
)
1551 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1552 &socketAddr
, sizeof(struct sockaddr_in
));
1554 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA
));
1557 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1561 handle
= WININET_AllocHandle( &lpwfs
->hdr
);
1564 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1568 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1569 lpwfs
->hdr
.dwFlags
= dwFlags
;
1570 lpwfs
->hdr
.dwContext
= dwContext
;
1571 lpwfs
->hdr
.dwInternalFlags
= dwInternalFlags
;
1572 lpwfs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
1573 lpwfs
->sndSocket
= nsocket
;
1574 lpwfs
->download_in_progress
= NULL
;
1575 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1576 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1577 lpwfs
->phostent
= phe
;
1579 if (NULL
== lpszUserName
)
1581 lpwfs
->lpszUserName
= FTP_strdup("anonymous");
1582 lpwfs
->lpszPassword
= FTP_strdup("user@server");
1586 lpwfs
->lpszUserName
= FTP_strdup_WtoA(lpszUserName
);
1587 lpwfs
->lpszPassword
= FTP_strdup_WtoA(lpszPassword
);
1590 if (FTP_ConnectToHost(lpwfs
))
1592 /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1593 if (hIC
->lpfnStatusCB
&& !(lpwfs
->hdr
.dwInternalFlags
& INET_OPENURL
))
1595 INTERNET_ASYNC_RESULT iar
;
1597 iar
.dwResult
= (DWORD
)handle
;
1598 iar
.dwError
= ERROR_SUCCESS
;
1600 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1601 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1603 TRACE("Successfully logged into server\n");
1609 if (!bSuccess
&& nsocket
== -1)
1612 if (!bSuccess
&& lpwfs
)
1614 HeapFree(GetProcessHeap(), 0, lpwfs
);
1615 WININET_FreeHandle( handle
);
1619 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1621 INTERNET_ASYNC_RESULT iar
;
1623 iar
.dwResult
= (DWORD
)lpwfs
;
1624 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1625 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1626 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1633 /***********************************************************************
1634 * FTP_ConnectToHost (internal)
1636 * Connect to a ftp server
1643 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
)
1646 BOOL bSuccess
= FALSE
;
1649 FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1651 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1654 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1655 MAX_REPLY_LEN
, 0, 0, 0);
1658 /* Login successful... */
1659 if (nResCode
== 230)
1661 /* User name okay, need password... */
1662 else if (nResCode
== 331)
1663 bSuccess
= FTP_SendPassword(lpwfs
);
1664 /* Need account for login... */
1665 else if (nResCode
== 332)
1666 bSuccess
= FTP_SendAccount(lpwfs
);
1668 FTP_SetResponseError(nResCode
);
1671 TRACE("Returning %d\n", bSuccess
);
1677 /***********************************************************************
1678 * FTP_SendCommand (internal)
1680 * Send command to server
1687 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
1688 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1692 DWORD nBytesSent
= 0;
1696 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
1699 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1701 bParamHasLen
= lpszParam
&& strlen(lpszParam
) > 0;
1702 len
= (bParamHasLen
? strlen(lpszParam
) : -1) + strlen(szFtpCommands
[ftpCmd
]) +
1704 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1706 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1709 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], bParamHasLen
? " " : "",
1710 bParamHasLen
? lpszParam
: "", szCRLF
);
1712 TRACE("Sending (%s) len(%ld)\n", buf
, len
);
1713 while((nBytesSent
< len
) && (nRC
!= -1))
1715 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1719 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1722 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1723 &nBytesSent
, sizeof(DWORD
));
1725 TRACE("Sent %ld bytes\n", nBytesSent
);
1730 /***********************************************************************
1731 * FTP_ReceiveResponse (internal)
1733 * Receive response from server
1736 * Reply code on success
1741 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
1742 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1746 char firstprefix
[5];
1747 BOOL multiline
= FALSE
;
1750 TRACE("socket(%d) \n", nSocket
);
1753 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
1758 if (!INTERNET_GetNextLine(nSocket
, lpszResponse
, &nRecv
))
1765 if(lpszResponse
[3] != '-')
1768 { /* Start of multiline repsonse. Loop until we get "nnn " */
1770 memcpy(firstprefix
, lpszResponse
, 3);
1771 firstprefix
[3] = ' ';
1772 firstprefix
[4] = '\0';
1777 if(!memcmp(firstprefix
, lpszResponse
, 4))
1785 rc
= atoi(lpszResponse
);
1788 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
1789 &nRecv
, sizeof(DWORD
));
1793 TRACE("return %d\n", rc
);
1798 /***********************************************************************
1799 * FTP_SendPassword (internal)
1801 * Send password to ftp server
1808 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
)
1811 BOOL bSuccess
= FALSE
;
1814 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
1817 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1818 MAX_REPLY_LEN
, 0, 0, 0);
1821 TRACE("Received reply code %d\n", nResCode
);
1822 /* Login successful... */
1823 if (nResCode
== 230)
1825 /* Command not implemented, superfluous at the server site... */
1826 /* Need account for login... */
1827 else if (nResCode
== 332)
1828 bSuccess
= FTP_SendAccount(lpwfs
);
1830 FTP_SetResponseError(nResCode
);
1834 TRACE("Returning %d\n", bSuccess
);
1839 /***********************************************************************
1840 * FTP_SendAccount (internal)
1849 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
)
1852 BOOL bSuccess
= FALSE
;
1855 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, NOACCOUNT
, 0, 0, 0))
1858 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1859 MAX_REPLY_LEN
, 0, 0, 0);
1863 FTP_SetResponseError(nResCode
);
1870 /***********************************************************************
1871 * FTP_SendStore (internal)
1873 * Send request to upload file to ftp server
1880 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
1883 BOOL bSuccess
= FALSE
;
1886 if (!FTP_InitListenSocket(lpwfs
))
1889 if (!FTP_SendType(lpwfs
, dwType
))
1892 if (!FTP_SendPortOrPasv(lpwfs
))
1895 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
1897 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1898 MAX_REPLY_LEN
, 0, 0, 0);
1901 if (nResCode
== 150)
1904 FTP_SetResponseError(nResCode
);
1908 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
1910 close(lpwfs
->lstnSocket
);
1911 lpwfs
->lstnSocket
= -1;
1918 /***********************************************************************
1919 * FTP_InitListenSocket (internal)
1921 * Create a socket to listen for server response
1928 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
)
1930 BOOL bSuccess
= FALSE
;
1931 size_t namelen
= sizeof(struct sockaddr_in
);
1935 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
1936 if (lpwfs
->lstnSocket
== -1)
1938 TRACE("Unable to create listening socket\n");
1942 /* We obtain our ip addr from the name of the command channel socket */
1943 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
1945 /* and get the system to assign us a port */
1946 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
1948 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
1950 TRACE("Unable to bind socket\n");
1954 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
1956 TRACE("listen failed\n");
1960 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
1964 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
1966 close(lpwfs
->lstnSocket
);
1967 lpwfs
->lstnSocket
= -1;
1974 /***********************************************************************
1975 * FTP_SendType (internal)
1977 * Tell server type of data being transferred
1983 * W98SE doesn't cache the type that's currently set
1984 * (i.e. it sends it always),
1985 * so we probably don't want to do that either.
1987 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
)
1990 CHAR type
[2] = { "I" };
1991 BOOL bSuccess
= FALSE
;
1994 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
1997 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
2000 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2001 MAX_REPLY_LEN
, 0, 0, 0)/100;
2007 FTP_SetResponseError(nResCode
);
2014 /***********************************************************************
2015 * FTP_GetFileSize (internal)
2017 * Retrieves from the server the size of the given file
2024 BOOL
FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD
*dwSize
)
2027 BOOL bSuccess
= FALSE
;
2031 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
2034 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2035 MAX_REPLY_LEN
, 0, 0, 0);
2038 if (nResCode
== 213) {
2039 /* Now parses the output to get the actual file size */
2041 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2043 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
2044 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
2045 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2049 FTP_SetResponseError(nResCode
);
2058 /***********************************************************************
2059 * FTP_SendPort (internal)
2061 * Tell server which port to use
2068 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
)
2071 CHAR szIPAddress
[64];
2072 BOOL bSuccess
= FALSE
;
2075 sprintf(szIPAddress
, "%d,%d,%d,%d,%d,%d",
2076 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2077 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2078 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2079 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2080 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2081 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2083 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2086 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2087 MAX_REPLY_LEN
,0, 0, 0);
2090 if (nResCode
== 200)
2093 FTP_SetResponseError(nResCode
);
2101 /***********************************************************************
2102 * FTP_DoPassive (internal)
2104 * Tell server that we want to do passive transfers
2105 * and connect data socket
2112 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
)
2115 BOOL bSuccess
= FALSE
;
2118 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2121 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2122 MAX_REPLY_LEN
,0, 0, 0);
2125 if (nResCode
== 227)
2127 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2131 char *pAddr
, *pPort
;
2133 struct sockaddr_in dataSocketAddress
;
2135 p
= lpszResponseBuffer
+4; /* skip status code */
2137 /* do a very strict check; we can improve that later. */
2139 if (strncmp(p
, "Entering Passive Mode", 21))
2141 ERR("unknown response '%.*s', aborting\n", 21, p
);
2144 p
+= 21; /* skip string */
2145 if ((*p
++ != ' ') || (*p
++ != '('))
2147 ERR("unknown response format, aborting\n");
2151 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2154 ERR("unknown response address format '%s', aborting\n", p
);
2157 for (i
=0; i
< 6; i
++)
2160 dataSocketAddress
= lpwfs
->socketAddress
;
2161 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2162 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2170 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2174 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2176 ERR("can't connect passive FTP data port.\n");
2179 lpwfs
->pasvSocket
= nsocket
;
2183 FTP_SetResponseError(nResCode
);
2191 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
)
2193 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2195 if (!FTP_DoPassive(lpwfs
))
2200 if (!FTP_SendPort(lpwfs
))
2207 /***********************************************************************
2208 * FTP_GetDataSocket (internal)
2210 * Either accepts an incoming data socket connection from the server
2211 * or just returns the already opened socket after a PASV command
2212 * in case of passive FTP.
2220 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
)
2222 struct sockaddr_in saddr
;
2223 size_t addrlen
= sizeof(struct sockaddr
);
2226 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2228 *nDataSocket
= lpwfs
->pasvSocket
;
2232 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2233 close(lpwfs
->lstnSocket
);
2234 lpwfs
->lstnSocket
= -1;
2236 return *nDataSocket
!= -1;
2240 /***********************************************************************
2241 * FTP_SendData (internal)
2243 * Send data to the server
2250 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
)
2252 BY_HANDLE_FILE_INFORMATION fi
;
2253 DWORD nBytesRead
= 0;
2254 DWORD nBytesSent
= 0;
2255 DWORD nTotalSent
= 0;
2256 DWORD nBytesToSend
, nLen
, nRC
= 1;
2257 time_t s_long_time
, e_long_time
;
2262 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2263 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2265 /* Get the size of the file. */
2266 GetFileInformationByHandle(hFile
, &fi
);
2271 nBytesToSend
= nBytesRead
- nBytesSent
;
2273 if (nBytesToSend
<= 0)
2275 /* Read data from file. */
2277 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2278 ERR("Failed reading from file\n");
2281 nBytesToSend
= nBytesRead
;
2286 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2287 DATA_PACKET_SIZE
: nBytesToSend
;
2288 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2296 /* Do some computation to display the status. */
2298 nSeconds
= e_long_time
- s_long_time
;
2299 if( nSeconds
/ 60 > 0 )
2301 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2302 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2303 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2307 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2308 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2309 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2311 } while (nRC
!= -1);
2313 TRACE("file transfer complete!\n");
2315 if(lpszBuffer
!= NULL
)
2316 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2322 /***********************************************************************
2323 * FTP_SendRetrieve (internal)
2325 * Send request to retrieve a file
2328 * Number of bytes to be received on success
2332 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
2338 if (!FTP_InitListenSocket(lpwfs
))
2341 if (!FTP_SendType(lpwfs
, dwType
))
2344 if (!FTP_SendPortOrPasv(lpwfs
))
2347 if (!FTP_GetFileSize(lpwfs
, lpszRemoteFile
, &nResult
))
2350 TRACE("Waiting to receive %ld bytes\n", nResult
);
2352 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2355 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2356 MAX_REPLY_LEN
, 0, 0, 0);
2357 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2358 /* That means that we got an error getting the file. */
2363 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2365 close(lpwfs
->lstnSocket
);
2366 lpwfs
->lstnSocket
= -1;
2373 /***********************************************************************
2374 * FTP_RetrieveData (internal)
2376 * Retrieve data from server
2383 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2385 DWORD nBytesWritten
;
2386 DWORD nBytesReceived
= 0;
2392 if (INVALID_HANDLE_VALUE
== hFile
)
2395 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2396 if (NULL
== lpszBuffer
)
2398 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2402 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2404 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2407 /* other side closed socket. */
2410 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2411 nBytesReceived
+= nRC
;
2414 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived
, nBytes
,
2415 nBytesReceived
* 100 / nBytes
);
2418 TRACE("Data transfer complete\n");
2419 if (NULL
!= lpszBuffer
)
2420 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2427 /***********************************************************************
2428 * FTP_CloseSessionHandle (internal)
2430 * Deallocate session handle
2437 BOOL
FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs
)
2441 if (lpwfs
->download_in_progress
!= NULL
)
2442 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2444 if (lpwfs
->sndSocket
!= -1)
2445 close(lpwfs
->sndSocket
);
2447 if (lpwfs
->lstnSocket
!= -1)
2448 close(lpwfs
->lstnSocket
);
2450 if (lpwfs
->lpszPassword
)
2451 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2453 if (lpwfs
->lpszUserName
)
2454 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2456 HeapFree(GetProcessHeap(), 0, lpwfs
);
2462 /***********************************************************************
2463 * FTP_CloseFindNextHandle (internal)
2465 * Deallocate session handle
2472 BOOL
FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn
)
2478 for (i
= 0; i
< lpwfn
->size
; i
++)
2480 if (NULL
!= lpwfn
->lpafp
[i
].lpszName
)
2481 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2484 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2485 HeapFree(GetProcessHeap(), 0, lpwfn
);
2490 /***********************************************************************
2491 * FTP_CloseFileTransferHandle (internal)
2493 * Closes the file transfer handle. This also 'cleans' the data queue of
2494 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2501 BOOL
FTP_CloseFileTransferHandle(LPWININETFILE lpwh
)
2503 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) lpwh
->hdr
.lpwhparent
;
2509 if (!lpwh
->session_deleted
)
2510 lpwfs
->download_in_progress
= NULL
;
2512 /* This just serves to flush the control socket of any spurrious lines written
2513 to it (like '226 Transfer complete.').
2515 Wonder what to do if the server sends us an error code though...
2517 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2518 MAX_REPLY_LEN
, 0, 0, 0);
2520 if (lpwh
->nDataSocket
!= -1)
2521 close(lpwh
->nDataSocket
);
2523 HeapFree(GetProcessHeap(), 0, lpwh
);
2525 /* If this handle was opened with InternetOpenUrl, we need to close the parent to prevent
2528 if(lpwfs
->hdr
.dwInternalFlags
& INET_OPENURL
)
2530 handle
= WININET_FindHandle( &lpwfs
->hdr
);
2531 InternetCloseHandle(handle
);
2536 /***********************************************************************
2537 * FTP_ReceiveFileList (internal)
2539 * Read file list from server
2542 * Handle to file list on success
2546 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
2547 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
)
2550 LPFILEPROPERTIESA lpafp
= NULL
;
2551 LPWININETFINDNEXTA lpwfn
= NULL
;
2552 HINTERNET handle
= 0;
2556 if (FTP_ParseDirectory(lpwfs
, nSocket
, &lpafp
, &dwSize
))
2558 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2560 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFINDNEXTA
));
2563 handle
= WININET_AllocHandle( &lpwfn
->hdr
);
2566 lpwfn
->hdr
.htype
= WH_HFINDNEXT
;
2567 lpwfn
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)lpwfs
;
2568 lpwfn
->hdr
.dwContext
= dwContext
;
2569 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2570 lpwfn
->size
= dwSize
;
2571 lpwfn
->lpafp
= lpafp
;
2574 HeapFree( GetProcessHeap(), 0, lpwfn
);
2578 TRACE("Matched %ld files\n", dwSize
);
2583 /***********************************************************************
2584 * FTP_ConvertFileProp (internal)
2586 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2593 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp
, LPWIN32_FIND_DATAA lpFindFileData
)
2595 BOOL bSuccess
= FALSE
;
2597 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2601 /* Convert 'Unix' time to Windows time */
2602 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
2603 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
2605 /* Not all fields are filled in */
2606 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2607 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
2609 if (lpafp
->bIsDirectory
)
2610 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2612 if (lpafp
->lpszName
)
2613 strncpy(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2622 /***********************************************************************
2623 * FTP_ParseDirectory (internal)
2625 * Parse string of directory information
2631 * FIXME: - This function needs serious clea-up
2632 * - We should consider both UNIX and NT list formats
2634 #define MAX_MONTH_LEN 10
2635 #define MIN_LEN_DIR_ENTRY 15
2637 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
)
2640 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2643 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2649 CHAR pszMonth
[MAX_MONTH_LEN
];
2651 BOOL bSuccess
= TRUE
;
2652 DWORD nBufLen
= MAX_REPLY_LEN
;
2653 LPFILEPROPERTIESA curFileProp
= NULL
;
2654 CHAR
* pszLine
= NULL
;
2655 CHAR
* pszToken
= NULL
;
2656 INT nTokenToSkip
= 3;
2664 INT sizeFilePropArray
= 20;
2665 INT indexFilePropArray
= 0;
2669 /* Allocate intial file properties array */
2670 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESA
)*(sizeFilePropArray
));
2677 while ((pszLine
= INTERNET_GetNextLine(nSocket
, INTERNET_GetResponseBuffer(), &nBufLen
)) != NULL
)
2679 if (sizeFilePropArray
<= indexFilePropArray
)
2681 LPFILEPROPERTIESA tmpafp
;
2683 sizeFilePropArray
*= 2;
2684 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
2685 sizeof(FILEPROPERTIESA
)*sizeFilePropArray
);
2695 curFileProp
= &((*lpafp
)[indexFilePropArray
]);
2697 /* First Parse the permissions. */
2698 pszToken
= strtok(pszLine
, " \t" );
2700 /* HACK! If this is not a file listing skip the line */
2701 if (!pszToken
|| nBufLen
<= MIN_LEN_DIR_ENTRY
)
2703 nBufLen
= MAX_REPLY_LEN
;
2706 if (10 == strlen(pszToken
)) {
2707 /* Unix way of parsing ... */
2708 FTP_ParsePermission(pszToken
, curFileProp
);
2713 pszToken
= strtok( NULL
, " \t" );
2715 } while( nCount
<= nTokenToSkip
);
2717 /* Store the size of the file in the param list. */
2718 TRACE("nSize-> %s\n", pszToken
);
2719 if (pszToken
!= NULL
)
2720 curFileProp
->nSize
= atol(pszToken
);
2722 /* Parse last modified time. */
2730 pszToken
= strtok( NULL
, " \t" );
2731 strncpy(pszMonth
, pszToken
, MAX_MONTH_LEN
);
2732 CharUpperA(pszMonth
);
2733 pszMatch
= strstr(szMonths
, pszMonth
);
2734 if( pszMatch
!= NULL
)
2735 nMonth
= (pszMatch
- szMonths
) / 3;
2737 pszToken
= strtok(NULL
, " \t");
2738 TRACE("nDay -> %s\n", pszToken
);
2739 if (pszToken
!= NULL
)
2740 nDay
= atoi(pszToken
);
2742 pszToken
= strtok(NULL
, " \t");
2743 pszMinutes
= strchr(pszToken
, ':');
2744 if( pszMinutes
!= NULL
) {
2746 nMinutes
= atoi(pszMinutes
);
2747 pszHour
= pszMinutes
- 3;
2748 if (pszHour
!= NULL
)
2749 nHour
= atoi(pszHour
);
2751 apTM
= localtime( &aTime
);
2752 nYear
= apTM
->tm_year
;
2754 nYear
= atoi(pszToken
);
2759 curFileProp
->tmLastModified
.tm_sec
= nSeconds
;
2760 curFileProp
->tmLastModified
.tm_min
= nMinutes
;
2761 curFileProp
->tmLastModified
.tm_hour
= nHour
;
2762 curFileProp
->tmLastModified
.tm_mday
= nDay
;
2763 curFileProp
->tmLastModified
.tm_mon
= nMonth
;
2764 curFileProp
->tmLastModified
.tm_year
= nYear
;
2766 pszToken
= strtok(NULL
, " \t");
2767 if(pszToken
!= NULL
) {
2768 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2769 TRACE(": %s\n", curFileProp
->lpszName
);
2772 nBufLen
= MAX_REPLY_LEN
;
2773 indexFilePropArray
++;
2774 } else if (8 == strlen(pszToken
)) {
2775 /* NT way of parsing ... :
2777 07-13-03 08:55PM <DIR> sakpatch
2778 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2781 curFileProp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
2783 sscanf(pszToken
, "%d-%d-%d",
2784 &curFileProp
->tmLastModified
.tm_mon
,
2785 &curFileProp
->tmLastModified
.tm_mday
,
2786 &curFileProp
->tmLastModified
.tm_year
);
2788 /* Hacky and bad Y2K protection :-) */
2789 if (curFileProp
->tmLastModified
.tm_year
< 70)
2790 curFileProp
->tmLastModified
.tm_year
+= 100;
2792 pszToken
= strtok(NULL
, " \t");
2793 if (pszToken
== NULL
) {
2794 nBufLen
= MAX_REPLY_LEN
;
2797 sscanf(pszToken
, "%d:%d",
2798 &curFileProp
->tmLastModified
.tm_hour
,
2799 &curFileProp
->tmLastModified
.tm_min
);
2800 if ((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
2801 curFileProp
->tmLastModified
.tm_hour
+= 12;
2803 curFileProp
->tmLastModified
.tm_sec
= 0;
2805 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2806 curFileProp
->tmLastModified
.tm_hour
, curFileProp
->tmLastModified
.tm_min
, curFileProp
->tmLastModified
.tm_sec
,
2807 (curFileProp
->tmLastModified
.tm_year
>= 100) ? curFileProp
->tmLastModified
.tm_year
- 100 : curFileProp
->tmLastModified
.tm_year
,
2808 curFileProp
->tmLastModified
.tm_mon
, curFileProp
->tmLastModified
.tm_mday
);
2810 pszToken
= strtok(NULL
, " \t");
2811 if (pszToken
== NULL
) {
2812 nBufLen
= MAX_REPLY_LEN
;
2815 if (!strcasecmp(pszToken
, "<DIR>")) {
2816 curFileProp
->bIsDirectory
= TRUE
;
2817 TRACE("Is directory\n");
2819 curFileProp
->bIsDirectory
= FALSE
;
2820 curFileProp
->nSize
= atol(pszToken
);
2821 TRACE("nSize: %ld\n", curFileProp
->nSize
);
2824 pszToken
= strtok(NULL
, " \t");
2825 if (pszToken
== NULL
) {
2826 nBufLen
= MAX_REPLY_LEN
;
2829 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2830 TRACE("Name: %s\n", curFileProp
->lpszName
);
2832 nBufLen
= MAX_REPLY_LEN
;
2833 indexFilePropArray
++;
2835 nBufLen
= MAX_REPLY_LEN
;
2839 if (bSuccess
&& indexFilePropArray
)
2841 if (indexFilePropArray
< sizeFilePropArray
- 1)
2843 LPFILEPROPERTIESA tmpafp
;
2845 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
2846 sizeof(FILEPROPERTIESA
)*indexFilePropArray
);
2850 *dwfp
= indexFilePropArray
;
2854 HeapFree(GetProcessHeap(), 0, *lpafp
);
2855 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2864 /***********************************************************************
2865 * FTP_ParsePermission (internal)
2867 * Parse permission string of directory information
2874 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
)
2876 BOOL bSuccess
= TRUE
;
2877 unsigned short nPermission
= 0;
2882 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
2888 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
2894 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
2897 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
2900 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
2903 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
2906 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
2909 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
2912 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
2915 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
2918 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
2922 }while (nPos
<= nLast
);
2924 lpfp
->permissions
= nPermission
;
2929 /***********************************************************************
2930 * FTP_SetResponseError (internal)
2932 * Set the appropriate error code for a given response from the server
2937 DWORD
FTP_SetResponseError(DWORD dwResponse
)
2943 case 421: /* Service not available - Server may be shutting down. */
2944 dwCode
= ERROR_INTERNET_TIMEOUT
;
2947 case 425: /* Cannot open data connection. */
2948 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
2951 case 426: /* Connection closed, transer aborted. */
2952 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
2955 case 500: /* Syntax error. Command unrecognized. */
2956 case 501: /* Syntax error. Error in parameters or arguments. */
2957 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
2960 case 530: /* Not logged in. Login incorrect. */
2961 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
2964 case 550: /* File action not taken. File not found or no access. */
2965 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
2968 case 450: /* File action not taken. File may be busy. */
2969 case 451: /* Action aborted. Server error. */
2970 case 452: /* Action not taken. Insufficient storage space on server. */
2971 case 502: /* Command not implemented. */
2972 case 503: /* Bad sequence of command. */
2973 case 504: /* Command not implemented for that parameter. */
2974 case 532: /* Need account for storing files */
2975 case 551: /* Requested action aborted. Page type unknown */
2976 case 552: /* Action aborted. Exceeded storage allocation */
2977 case 553: /* Action not taken. File name not allowed. */
2980 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
2984 INTERNET_SetLastError(dwCode
);