2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
9 * Copyright 2000 Andreas Mohr
10 * Copyright 2002 Jaco Greeff
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "wine/port.h"
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_SOCKET_H
37 # include <sys/socket.h>
54 #include "wine/debug.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
59 #define NOACCOUNT "noaccount"
60 #define DATA_PACKET_SIZE 0x2000
65 /* FTP commands with arguments. */
81 /* FTP commands without arguments. */
90 static const CHAR
*szFtpCommands
[] = {
113 static const CHAR szMonths
[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
115 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
116 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
);
117 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
);
118 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
);
119 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
);
120 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
121 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
);
122 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
);
123 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
);
124 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
);
125 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
);
126 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
);
127 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
);
128 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
);
129 BOOL
FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD
*dwSize
);
130 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
);
131 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
);
132 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
);
133 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
);
134 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
);
135 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
136 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
);
137 DWORD
FTP_SetResponseError(DWORD dwResponse
);
139 inline static LPSTR
FTP_strdup( LPCSTR str
)
141 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, strlen(str
) + 1 );
142 if (ret
) strcpy( ret
, str
);
146 /***********************************************************************
147 * FtpPutFileA (WININET.@)
149 * Uploads a file to the FTP server
156 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
157 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
159 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
160 LPWININETAPPINFOA hIC
= NULL
;
162 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
164 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
168 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
169 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
171 WORKREQUEST workRequest
;
172 struct WORKREQ_FTPPUTFILEA
*req
= &workRequest
.u
.FtpPutFileA
;
174 workRequest
.asyncall
= FTPPUTFILEA
;
175 workRequest
.handle
= hConnect
;
176 req
->lpszLocalFile
= FTP_strdup(lpszLocalFile
);
177 req
->lpszNewRemoteFile
= FTP_strdup(lpszNewRemoteFile
);
178 req
->dwFlags
= dwFlags
;
179 req
->dwContext
= dwContext
;
181 return INTERNET_AsyncCall(&workRequest
);
185 return FTP_FtpPutFileA(hConnect
, lpszLocalFile
,
186 lpszNewRemoteFile
, dwFlags
, dwContext
);
190 /***********************************************************************
191 * FTP_FtpPutFileA (Internal)
193 * Uploads a file to the FTP server
200 BOOL WINAPI
FTP_FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
201 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
204 BOOL bSuccess
= FALSE
;
205 LPWININETAPPINFOA hIC
= NULL
;
206 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
209 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile
, lpszNewRemoteFile
);
210 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
212 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
216 /* Clear any error information */
217 INTERNET_SetLastError(0);
219 /* Open file to be uploaded */
220 if (INVALID_HANDLE_VALUE
==
221 (hFile
= CreateFileA(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
223 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND
);
227 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
228 if (hIC
->lpfnStatusCB
)
229 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
231 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
235 /* Get data socket to server */
236 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
238 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
240 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
241 MAX_REPLY_LEN
, 0, 0, 0);
247 FTP_SetResponseError(nResCode
);
253 if (lpwfs
->lstnSocket
!= -1)
254 close(lpwfs
->lstnSocket
);
256 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
258 INTERNET_ASYNC_RESULT iar
;
260 iar
.dwResult
= (DWORD
)bSuccess
;
261 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
262 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
263 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
273 /***********************************************************************
274 * FtpSetCurrentDirectoryA (WININET.@)
276 * Change the working directory on the FTP server
283 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
285 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
286 LPWININETAPPINFOA hIC
= NULL
;
288 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
290 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
294 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
296 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
297 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
299 WORKREQUEST workRequest
;
300 struct WORKREQ_FTPSETCURRENTDIRECTORYA
*req
;
302 workRequest
.asyncall
= FTPSETCURRENTDIRECTORYA
;
303 workRequest
.handle
= hConnect
;
304 req
= &workRequest
.u
.FtpSetCurrentDirectoryA
;
305 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
307 return INTERNET_AsyncCall(&workRequest
);
311 return FTP_FtpSetCurrentDirectoryA(hConnect
, lpszDirectory
);
316 /***********************************************************************
317 * FtpSetCurrentDirectoryW (WININET.@)
319 * Change the working directory on the FTP server
326 BOOL WINAPI
FtpSetCurrentDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
332 len
= WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, NULL
, 0, NULL
, NULL
);
333 szDir
= HeapAlloc(GetProcessHeap(), 0, len
);
336 WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, szDir
, len
, NULL
, NULL
);
337 rc
= FtpSetCurrentDirectoryA(hConnect
, szDir
);
338 HeapFree(GetProcessHeap(), 0, szDir
);
344 /***********************************************************************
345 * FTP_FtpSetCurrentDirectoryA (Internal)
347 * Change the working directory on the FTP server
354 BOOL WINAPI
FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
357 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
358 LPWININETAPPINFOA hIC
= NULL
;
359 DWORD bSuccess
= FALSE
;
361 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
363 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
365 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
369 /* Clear any error information */
370 INTERNET_SetLastError(0);
372 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
373 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
374 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
377 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
378 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
385 FTP_SetResponseError(nResCode
);
389 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
391 INTERNET_ASYNC_RESULT iar
;
393 iar
.dwResult
= (DWORD
)bSuccess
;
394 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
395 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
396 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
402 /***********************************************************************
403 * FtpCreateDirectoryA (WININET.@)
405 * Create new directory on the FTP server
412 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
414 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
415 LPWININETAPPINFOA hIC
= NULL
;
417 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
419 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
423 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
424 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
426 WORKREQUEST workRequest
;
427 struct WORKREQ_FTPCREATEDIRECTORYA
*req
;
429 workRequest
.asyncall
= FTPCREATEDIRECTORYA
;
430 workRequest
.handle
= hConnect
;
431 req
= &workRequest
.u
.FtpCreateDirectoryA
;
432 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
434 return INTERNET_AsyncCall(&workRequest
);
438 return FTP_FtpCreateDirectoryA(hConnect
, lpszDirectory
);
443 /***********************************************************************
444 * FtpCreateDirectoryW (WININET.@)
446 * Create new directory on the FTP server
453 BOOL WINAPI
FtpCreateDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
459 len
= WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, NULL
, 0, NULL
, NULL
);
460 szDir
= HeapAlloc(GetProcessHeap(), 0, len
);
463 WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, szDir
, len
, NULL
, NULL
);
464 rc
= FtpCreateDirectoryA(hConnect
, szDir
);
465 HeapFree(GetProcessHeap(), 0, szDir
);
471 /***********************************************************************
472 * FTP_FtpCreateDirectoryA (Internal)
474 * Create new directory on the FTP server
481 BOOL WINAPI
FTP_FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
484 BOOL bSuccess
= FALSE
;
485 LPWININETAPPINFOA hIC
= NULL
;
486 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
489 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
491 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
495 /* Clear any error information */
496 INTERNET_SetLastError(0);
498 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
501 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
502 MAX_REPLY_LEN
, 0, 0, 0);
508 FTP_SetResponseError(nResCode
);
512 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
513 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
515 INTERNET_ASYNC_RESULT iar
;
517 iar
.dwResult
= (DWORD
)bSuccess
;
518 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
519 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
520 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
527 /***********************************************************************
528 * FtpFindFirstFileA (WININET.@)
530 * Search the specified directory
533 * HINTERNET on success
537 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
538 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
540 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
541 LPWININETAPPINFOA hIC
= NULL
;
543 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
545 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
549 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
550 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
552 WORKREQUEST workRequest
;
553 struct WORKREQ_FTPFINDFIRSTFILEA
*req
;
555 workRequest
.asyncall
= FTPFINDFIRSTFILEA
;
556 workRequest
.handle
= hConnect
;
557 req
= &workRequest
.u
.FtpFindFirstFileA
;
558 req
->lpszSearchFile
= FTP_strdup(lpszSearchFile
);
559 req
->lpFindFileData
= lpFindFileData
;
560 req
->dwFlags
= dwFlags
;
561 req
->dwContext
= dwContext
;
563 INTERNET_AsyncCall(&workRequest
);
568 return FTP_FtpFindFirstFileA(hConnect
, lpszSearchFile
, lpFindFileData
,
574 /***********************************************************************
575 * FtpFindFirstFileA (WININET.@)
577 * Search the specified directory
580 * HINTERNET on success
584 HINTERNET WINAPI
FtpFindFirstFileW(HINTERNET hConnect
,
585 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
592 /***********************************************************************
593 * FTP_FtpFindFirstFileA (Internal)
595 * Search the specified directory
598 * HINTERNET on success
602 HINTERNET WINAPI
FTP_FtpFindFirstFileA(HINTERNET hConnect
,
603 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
606 LPWININETAPPINFOA hIC
= NULL
;
607 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
608 LPWININETFINDNEXTA hFindNext
= NULL
;
612 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
614 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
618 /* Clear any error information */
619 INTERNET_SetLastError(0);
621 if (!FTP_InitListenSocket(lpwfs
))
624 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
627 if (!FTP_SendPortOrPasv(lpwfs
))
630 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
631 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, lpszSearchFile
,
632 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
635 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
636 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
639 if (nResCode
== 125 || nResCode
== 150)
643 /* Get data socket to server */
644 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
646 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpFindFileData
, dwContext
);
648 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
649 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
650 if (nResCode
!= 226 && nResCode
!= 250)
651 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
657 FTP_SetResponseError(nResCode
);
661 if (lpwfs
->lstnSocket
!= -1)
662 close(lpwfs
->lstnSocket
);
664 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
666 INTERNET_ASYNC_RESULT iar
;
670 iar
.dwResult
= (DWORD
)hFindNext
;
671 iar
.dwError
= ERROR_SUCCESS
;
672 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
673 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
676 iar
.dwResult
= (DWORD
)hFindNext
;
677 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
678 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
679 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
682 return (HINTERNET
)hFindNext
;
686 /***********************************************************************
687 * FtpGetCurrentDirectoryA (WININET.@)
689 * Retrieves the current directory
696 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
697 LPDWORD lpdwCurrentDirectory
)
699 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
700 LPWININETAPPINFOA hIC
= NULL
;
702 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
704 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
706 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
710 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
711 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
713 WORKREQUEST workRequest
;
714 struct WORKREQ_FTPGETCURRENTDIRECTORYA
*req
;
716 workRequest
.asyncall
= FTPGETCURRENTDIRECTORYA
;
717 workRequest
.handle
= hFtpSession
;
718 req
= &workRequest
.u
.FtpGetCurrentDirectoryA
;
719 req
->lpszDirectory
= lpszCurrentDirectory
;
720 req
->lpdwDirectory
= lpdwCurrentDirectory
;
722 return INTERNET_AsyncCall(&workRequest
);
726 return FTP_FtpGetCurrentDirectoryA(hFtpSession
, lpszCurrentDirectory
,
727 lpdwCurrentDirectory
);
732 /***********************************************************************
733 * FtpGetCurrentDirectoryW (WININET.@)
735 * Retrieves the current directory
742 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
743 LPDWORD lpdwCurrentDirectory
)
750 /***********************************************************************
751 * FTP_FtpGetCurrentDirectoryA (Internal)
753 * Retrieves the current directory
760 BOOL WINAPI
FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
761 LPDWORD lpdwCurrentDirectory
)
764 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
765 LPWININETAPPINFOA hIC
= NULL
;
766 DWORD bSuccess
= FALSE
;
768 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
770 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
772 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
776 /* Clear any error information */
777 INTERNET_SetLastError(0);
779 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
781 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
782 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
783 hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
))
786 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
787 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
);
790 if (nResCode
== 257) /* Extract directory name */
792 INT firstpos
, lastpos
, len
;
793 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
795 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
797 if ('"' == lpszResponseBuffer
[lastpos
])
806 len
= lastpos
- firstpos
- 1;
807 strncpy(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1],
808 len
< *lpdwCurrentDirectory
? len
: *lpdwCurrentDirectory
);
809 *lpdwCurrentDirectory
= len
;
813 FTP_SetResponseError(nResCode
);
817 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
819 INTERNET_ASYNC_RESULT iar
;
821 iar
.dwResult
= (DWORD
)bSuccess
;
822 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
823 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
824 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
827 return (DWORD
) bSuccess
;
830 /***********************************************************************
831 * FtpOpenFileA (WININET.@)
833 * Open a remote file for writing or reading
836 * HINTERNET handle on success
840 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
841 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
844 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
845 LPWININETAPPINFOA hIC
= NULL
;
847 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
849 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
853 if (lpwfs
->download_in_progress
!= NULL
) {
854 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
858 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
859 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
861 WORKREQUEST workRequest
;
862 struct WORKREQ_FTPOPENFILEA
*req
;
864 workRequest
.asyncall
= FTPOPENFILEA
;
865 workRequest
.handle
= hFtpSession
;
866 req
= &workRequest
.u
.FtpOpenFileA
;
867 req
->lpszFilename
= FTP_strdup(lpszFileName
);
868 req
->dwAccess
= fdwAccess
;
869 req
->dwFlags
= dwFlags
;
870 req
->dwContext
= dwContext
;
872 INTERNET_AsyncCall(&workRequest
);
877 return FTP_FtpOpenFileA(hFtpSession
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
882 /***********************************************************************
883 * FtpOpenFileW (WININET.@)
885 * Open a remote file for writing or reading
888 * HINTERNET handle on success
892 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
893 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
901 /***********************************************************************
902 * FTP_FtpOpenFileA (Internal)
904 * Open a remote file for writing or reading
907 * HINTERNET handle on success
911 HINTERNET
FTP_FtpOpenFileA(HINTERNET hFtpSession
,
912 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
916 BOOL bSuccess
= FALSE
;
917 LPWININETFILE hFile
= NULL
;
918 LPWININETAPPINFOA hIC
= NULL
;
919 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
923 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
925 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
929 /* Clear any error information */
930 INTERNET_SetLastError(0);
932 if (GENERIC_READ
== fdwAccess
)
934 /* Set up socket to retrieve data */
935 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
937 else if (GENERIC_WRITE
== fdwAccess
)
939 /* Set up socket to send data */
940 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
943 /* Get data socket to server */
944 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
946 hFile
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE
));
947 hFile
->hdr
.htype
= WH_HFILE
;
948 hFile
->hdr
.dwFlags
= dwFlags
;
949 hFile
->hdr
.dwContext
= dwContext
;
950 hFile
->hdr
.lpwhparent
= hFtpSession
;
951 hFile
->nDataSocket
= nDataSocket
;
952 hFile
->session_deleted
= FALSE
;
954 /* Indicate that a download is currently in progress */
955 lpwfs
->download_in_progress
= hFile
;
958 if (lpwfs
->lstnSocket
!= -1)
959 close(lpwfs
->lstnSocket
);
961 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
962 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
964 INTERNET_ASYNC_RESULT iar
;
968 iar
.dwResult
= (DWORD
)hFile
;
969 iar
.dwError
= ERROR_SUCCESS
;
970 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
971 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
974 iar
.dwResult
= (DWORD
)bSuccess
;
975 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
976 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
977 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
980 return (HINTERNET
)hFile
;
984 /***********************************************************************
985 * FtpGetFileA (WININET.@)
987 * Retrieve file from the FTP server
994 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
995 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
998 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hInternet
;
999 LPWININETAPPINFOA hIC
= NULL
;
1001 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1003 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1007 if (lpwfs
->download_in_progress
!= NULL
) {
1008 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1012 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1013 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1015 WORKREQUEST workRequest
;
1016 struct WORKREQ_FTPGETFILEA
*req
;
1018 workRequest
.asyncall
= FTPGETFILEA
;
1019 workRequest
.handle
= hInternet
;
1020 req
= &workRequest
.u
.FtpGetFileA
;
1021 req
->lpszRemoteFile
= FTP_strdup(lpszRemoteFile
);
1022 req
->lpszNewFile
= FTP_strdup(lpszNewFile
);
1023 req
->dwLocalFlagsAttribute
= dwLocalFlagsAttribute
;
1024 req
->fFailIfExists
= fFailIfExists
;
1025 req
->dwFlags
= dwInternetFlags
;
1026 req
->dwContext
= dwContext
;
1028 return INTERNET_AsyncCall(&workRequest
);
1032 return FTP_FtpGetFileA(hInternet
, lpszRemoteFile
, lpszNewFile
,
1033 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1038 /***********************************************************************
1039 * FtpGetFileW (WININET.@)
1041 * Retrieve file from the FTP server
1048 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1049 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1057 /***********************************************************************
1058 * FTP_FtpGetFileA (Internal)
1060 * Retrieve file from the FTP server
1067 BOOL WINAPI
FTP_FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1068 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1072 BOOL bSuccess
= FALSE
;
1074 LPWININETAPPINFOA hIC
= NULL
;
1075 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hInternet
;
1077 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile
, lpszNewFile
);
1078 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1080 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1084 /* Clear any error information */
1085 INTERNET_SetLastError(0);
1087 /* Ensure we can write to lpszNewfile by opening it */
1088 hFile
= CreateFileA(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1089 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1090 if (INVALID_HANDLE_VALUE
== hFile
)
1093 /* Set up socket to retrieve data */
1094 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
1100 /* Get data socket to server */
1101 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1106 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
1107 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1108 MAX_REPLY_LEN
, 0, 0, 0);
1111 if (nResCode
== 226)
1114 FTP_SetResponseError(nResCode
);
1121 if (lpwfs
->lstnSocket
!= -1)
1122 close(lpwfs
->lstnSocket
);
1127 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1128 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1130 INTERNET_ASYNC_RESULT iar
;
1132 iar
.dwResult
= (DWORD
)bSuccess
;
1133 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1134 hIC
->lpfnStatusCB(hInternet
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1135 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1142 /***********************************************************************
1143 * FtpDeleteFileA (WININET.@)
1145 * Delete a file on the ftp server
1152 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1154 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1155 LPWININETAPPINFOA hIC
= NULL
;
1157 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1159 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1163 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1164 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1166 WORKREQUEST workRequest
;
1167 struct WORKREQ_FTPDELETEFILEA
*req
;
1169 workRequest
.asyncall
= FTPDELETEFILEA
;
1170 workRequest
.handle
= hFtpSession
;
1171 req
= &workRequest
.u
.FtpDeleteFileA
;
1172 req
->lpszFilename
= FTP_strdup(lpszFileName
);
1174 return INTERNET_AsyncCall(&workRequest
);
1178 return FTP_FtpDeleteFileA(hFtpSession
, lpszFileName
);
1183 /***********************************************************************
1184 * FTP_FtpDeleteFileA (Internal)
1186 * Delete a file on the ftp server
1193 BOOL
FTP_FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1196 BOOL bSuccess
= FALSE
;
1197 LPWININETAPPINFOA hIC
= NULL
;
1198 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1200 TRACE("0x%08lx\n", (ULONG
) hFtpSession
);
1201 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1203 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1207 /* Clear any error information */
1208 INTERNET_SetLastError(0);
1210 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1213 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1214 MAX_REPLY_LEN
, 0, 0, 0);
1217 if (nResCode
== 250)
1220 FTP_SetResponseError(nResCode
);
1223 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1224 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1226 INTERNET_ASYNC_RESULT iar
;
1228 iar
.dwResult
= (DWORD
)bSuccess
;
1229 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1230 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1231 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1238 /***********************************************************************
1239 * FtpRemoveDirectoryA (WININET.@)
1241 * Remove a directory on the ftp server
1248 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1250 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1251 LPWININETAPPINFOA hIC
= NULL
;
1253 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1255 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1259 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1260 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1262 WORKREQUEST workRequest
;
1263 struct WORKREQ_FTPREMOVEDIRECTORYA
*req
;
1265 workRequest
.asyncall
= FTPREMOVEDIRECTORYA
;
1266 workRequest
.handle
= hFtpSession
;
1267 req
= &workRequest
.u
.FtpRemoveDirectoryA
;
1268 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
1270 return INTERNET_AsyncCall(&workRequest
);
1274 return FTP_FtpRemoveDirectoryA(hFtpSession
, lpszDirectory
);
1279 /***********************************************************************
1280 * FTP_FtpRemoveDirectoryA (Internal)
1282 * Remove a directory on the ftp server
1289 BOOL
FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1292 BOOL bSuccess
= FALSE
;
1293 LPWININETAPPINFOA hIC
= NULL
;
1294 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1297 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1299 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1303 /* Clear any error information */
1304 INTERNET_SetLastError(0);
1306 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1309 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1310 MAX_REPLY_LEN
, 0, 0, 0);
1313 if (nResCode
== 250)
1316 FTP_SetResponseError(nResCode
);
1320 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1321 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1323 INTERNET_ASYNC_RESULT iar
;
1325 iar
.dwResult
= (DWORD
)bSuccess
;
1326 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1327 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1328 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1335 /***********************************************************************
1336 * FtpRenameFileA (WININET.@)
1338 * Rename a file on the ftp server
1345 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1347 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1348 LPWININETAPPINFOA hIC
= NULL
;
1350 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1352 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1356 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1357 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1359 WORKREQUEST workRequest
;
1360 struct WORKREQ_FTPRENAMEFILEA
*req
;
1362 workRequest
.asyncall
= FTPRENAMEFILEA
;
1363 workRequest
.handle
= hFtpSession
;
1364 req
= &workRequest
.u
.FtpRenameFileA
;
1365 req
->lpszSrcFile
= FTP_strdup(lpszSrc
);
1366 req
->lpszDestFile
= FTP_strdup(lpszDest
);
1368 return INTERNET_AsyncCall(&workRequest
);
1372 return FTP_FtpRenameFileA(hFtpSession
, lpszSrc
, lpszDest
);
1376 /***********************************************************************
1377 * FTP_FtpRenameFileA (Internal)
1379 * Rename a file on the ftp server
1386 BOOL
FTP_FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1389 BOOL bSuccess
= FALSE
;
1390 LPWININETAPPINFOA hIC
= NULL
;
1391 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1394 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1396 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1400 /* Clear any error information */
1401 INTERNET_SetLastError(0);
1403 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1406 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1407 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1408 if (nResCode
== 350)
1410 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1413 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1414 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1417 if (nResCode
== 250)
1420 FTP_SetResponseError(nResCode
);
1423 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1424 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1426 INTERNET_ASYNC_RESULT iar
;
1428 iar
.dwResult
= (DWORD
)bSuccess
;
1429 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1430 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1431 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1438 /***********************************************************************
1439 * FTP_Connect (internal)
1441 * Connect to a ftp server
1444 * HINTERNET a session handle on success
1449 HINTERNET
FTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
1450 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
1451 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
1453 struct sockaddr_in socketAddr
;
1454 struct hostent
*phe
= NULL
;
1455 INT nsocket
= -1, sock_namelen
;
1456 LPWININETAPPINFOA hIC
= NULL
;
1457 BOOL bSuccess
= FALSE
;
1458 LPWININETFTPSESSIONA lpwfs
= NULL
;
1460 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1461 (ULONG
) hInternet
, lpszServerName
,
1462 nServerPort
, lpszUserName
, lpszPassword
);
1464 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
1467 hIC
= (LPWININETAPPINFOA
) hInternet
;
1469 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1471 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME
);
1475 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1476 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1478 if (hIC
->lpfnStatusCB
)
1479 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1480 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1482 if (!GetAddress(lpszServerName
, nServerPort
, &phe
, &socketAddr
))
1484 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1488 if (hIC
->lpfnStatusCB
)
1489 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1490 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1492 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1495 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1499 if (hIC
->lpfnStatusCB
)
1500 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1501 &socketAddr
, sizeof(struct sockaddr_in
));
1503 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1505 ERR("Unable to connect (%s)\n", strerror(errno
));
1506 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1510 TRACE("Connected to server\n");
1511 if (hIC
->lpfnStatusCB
)
1512 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1513 &socketAddr
, sizeof(struct sockaddr_in
));
1515 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA
));
1518 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1522 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1523 lpwfs
->hdr
.dwFlags
= dwFlags
;
1524 lpwfs
->hdr
.dwContext
= dwContext
;
1525 lpwfs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
1526 lpwfs
->sndSocket
= nsocket
;
1527 lpwfs
->download_in_progress
= NULL
;
1528 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1529 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1530 lpwfs
->phostent
= phe
;
1532 if (NULL
== lpszUserName
)
1534 lpwfs
->lpszUserName
= FTP_strdup("anonymous");
1535 lpwfs
->lpszPassword
= FTP_strdup("user@server");
1539 lpwfs
->lpszUserName
= FTP_strdup(lpszUserName
);
1540 lpwfs
->lpszPassword
= FTP_strdup(lpszPassword
);
1543 if (FTP_ConnectToHost(lpwfs
))
1545 if (hIC
->lpfnStatusCB
)
1547 INTERNET_ASYNC_RESULT iar
;
1549 iar
.dwResult
= (DWORD
)lpwfs
;
1550 iar
.dwError
= ERROR_SUCCESS
;
1552 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1553 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1555 TRACE("Successfully logged into server\n");
1561 if (!bSuccess
&& nsocket
== -1)
1564 if (!bSuccess
&& lpwfs
)
1566 HeapFree(GetProcessHeap(), 0, lpwfs
);
1570 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1572 INTERNET_ASYNC_RESULT iar
;
1574 iar
.dwResult
= (DWORD
)lpwfs
;
1575 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1576 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1577 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1580 return (HINTERNET
) lpwfs
;
1584 /***********************************************************************
1585 * FTP_ConnectToHost (internal)
1587 * Connect to a ftp server
1594 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
)
1597 BOOL bSuccess
= FALSE
;
1600 FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1602 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1605 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1606 MAX_REPLY_LEN
, 0, 0, 0);
1609 /* Login successful... */
1610 if (nResCode
== 230)
1612 /* User name okay, need password... */
1613 else if (nResCode
== 331)
1614 bSuccess
= FTP_SendPassword(lpwfs
);
1615 /* Need account for login... */
1616 else if (nResCode
== 332)
1617 bSuccess
= FTP_SendAccount(lpwfs
);
1619 FTP_SetResponseError(nResCode
);
1622 TRACE("Returning %d\n", bSuccess
);
1628 /***********************************************************************
1629 * FTP_SendCommand (internal)
1631 * Send command to server
1638 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
1639 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1643 DWORD nBytesSent
= 0;
1647 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
1650 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1652 bParamHasLen
= lpszParam
&& strlen(lpszParam
) > 0;
1653 len
= (bParamHasLen
? strlen(lpszParam
) : -1) + strlen(szFtpCommands
[ftpCmd
]) +
1655 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1657 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1660 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], bParamHasLen
? " " : "",
1661 bParamHasLen
? lpszParam
: "", szCRLF
);
1663 TRACE("Sending (%s) len(%ld)\n", buf
, len
);
1664 while((nBytesSent
< len
) && (nRC
!= -1))
1666 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1670 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1673 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1674 &nBytesSent
, sizeof(DWORD
));
1676 TRACE("Sent %ld bytes\n", nBytesSent
);
1681 /***********************************************************************
1682 * FTP_ReceiveResponse (internal)
1684 * Receive response from server
1687 * Reply code on success
1692 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
1693 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1697 char firstprefix
[5];
1698 BOOL multiline
= FALSE
;
1701 TRACE("socket(%d) \n", nSocket
);
1704 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
1709 if (!INTERNET_GetNextLine(nSocket
, lpszResponse
, &nRecv
))
1716 if(lpszResponse
[3] != '-')
1719 { /* Start of multiline repsonse. Loop until we get "nnn " */
1721 memcpy(firstprefix
, lpszResponse
, 3);
1722 firstprefix
[3] = ' ';
1723 firstprefix
[4] = '\0';
1728 if(!memcmp(firstprefix
, lpszResponse
, 4))
1736 rc
= atoi(lpszResponse
);
1739 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
1740 &nRecv
, sizeof(DWORD
));
1744 TRACE("return %d\n", rc
);
1749 /***********************************************************************
1750 * FTP_SendPassword (internal)
1752 * Send password to ftp server
1759 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
)
1762 BOOL bSuccess
= FALSE
;
1765 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
1768 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1769 MAX_REPLY_LEN
, 0, 0, 0);
1772 TRACE("Received reply code %d\n", nResCode
);
1773 /* Login successful... */
1774 if (nResCode
== 230)
1776 /* Command not implemented, superfluous at the server site... */
1777 /* Need account for login... */
1778 else if (nResCode
== 332)
1779 bSuccess
= FTP_SendAccount(lpwfs
);
1781 FTP_SetResponseError(nResCode
);
1785 TRACE("Returning %d\n", bSuccess
);
1790 /***********************************************************************
1791 * FTP_SendAccount (internal)
1800 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
)
1803 BOOL bSuccess
= FALSE
;
1806 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, NOACCOUNT
, 0, 0, 0))
1809 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1810 MAX_REPLY_LEN
, 0, 0, 0);
1814 FTP_SetResponseError(nResCode
);
1821 /***********************************************************************
1822 * FTP_SendStore (internal)
1824 * Send request to upload file to ftp server
1831 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
1834 BOOL bSuccess
= FALSE
;
1837 if (!FTP_InitListenSocket(lpwfs
))
1840 if (!FTP_SendType(lpwfs
, dwType
))
1843 if (!FTP_SendPortOrPasv(lpwfs
))
1846 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
1848 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1849 MAX_REPLY_LEN
, 0, 0, 0);
1852 if (nResCode
== 150)
1855 FTP_SetResponseError(nResCode
);
1859 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
1861 close(lpwfs
->lstnSocket
);
1862 lpwfs
->lstnSocket
= -1;
1869 /***********************************************************************
1870 * FTP_InitListenSocket (internal)
1872 * Create a socket to listen for server response
1879 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
)
1881 BOOL bSuccess
= FALSE
;
1882 size_t namelen
= sizeof(struct sockaddr_in
);
1886 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
1887 if (lpwfs
->lstnSocket
== -1)
1889 TRACE("Unable to create listening socket\n");
1893 /* We obtain our ip addr from the name of the command channel socket */
1894 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
1896 /* and get the system to assign us a port */
1897 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
1899 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
1901 TRACE("Unable to bind socket\n");
1905 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
1907 TRACE("listen failed\n");
1911 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
1915 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
1917 close(lpwfs
->lstnSocket
);
1918 lpwfs
->lstnSocket
= -1;
1925 /***********************************************************************
1926 * FTP_SendType (internal)
1928 * Tell server type of data being transferred
1934 * W98SE doesn't cache the type that's currently set
1935 * (i.e. it sends it always),
1936 * so we probably don't want to do that either.
1938 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
)
1941 CHAR type
[2] = { "I" };
1942 BOOL bSuccess
= FALSE
;
1945 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
1948 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
1951 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1952 MAX_REPLY_LEN
, 0, 0, 0)/100;
1958 FTP_SetResponseError(nResCode
);
1965 /***********************************************************************
1966 * FTP_GetFileSize (internal)
1968 * Retrieves from the server the size of the given file
1975 BOOL
FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD
*dwSize
)
1978 BOOL bSuccess
= FALSE
;
1982 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
1985 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1986 MAX_REPLY_LEN
, 0, 0, 0);
1989 if (nResCode
== 213) {
1990 /* Now parses the output to get the actual file size */
1992 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
1994 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
1995 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
1996 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2000 FTP_SetResponseError(nResCode
);
2009 /***********************************************************************
2010 * FTP_SendPort (internal)
2012 * Tell server which port to use
2019 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
)
2022 CHAR szIPAddress
[64];
2023 BOOL bSuccess
= FALSE
;
2026 sprintf(szIPAddress
, "%d,%d,%d,%d,%d,%d",
2027 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2028 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2029 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2030 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2031 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2032 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2034 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2037 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2038 MAX_REPLY_LEN
,0, 0, 0);
2041 if (nResCode
== 200)
2044 FTP_SetResponseError(nResCode
);
2052 /***********************************************************************
2053 * FTP_DoPassive (internal)
2055 * Tell server that we want to do passive transfers
2056 * and connect data socket
2063 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
)
2066 BOOL bSuccess
= FALSE
;
2069 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2072 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2073 MAX_REPLY_LEN
,0, 0, 0);
2076 if (nResCode
== 227)
2078 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2082 char *pAddr
, *pPort
;
2084 struct sockaddr_in dataSocketAddress
;
2086 p
= lpszResponseBuffer
+4; /* skip status code */
2088 /* do a very strict check; we can improve that later. */
2090 if (strncmp(p
, "Entering Passive Mode", 21))
2092 ERR("unknown response '%.*s', aborting\n", 21, p
);
2095 p
+= 21; /* skip string */
2096 if ((*p
++ != ' ') || (*p
++ != '('))
2098 ERR("unknown response format, aborting\n");
2102 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2105 ERR("unknown response address format '%s', aborting\n", p
);
2108 for (i
=0; i
< 6; i
++)
2111 dataSocketAddress
= lpwfs
->socketAddress
;
2112 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2113 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2121 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2125 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2127 ERR("can't connect passive FTP data port.\n");
2130 lpwfs
->pasvSocket
= nsocket
;
2134 FTP_SetResponseError(nResCode
);
2142 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
)
2144 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2146 if (!FTP_DoPassive(lpwfs
))
2151 if (!FTP_SendPort(lpwfs
))
2158 /***********************************************************************
2159 * FTP_GetDataSocket (internal)
2161 * Either accepts an incoming data socket connection from the server
2162 * or just returns the already opened socket after a PASV command
2163 * in case of passive FTP.
2171 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
)
2173 struct sockaddr_in saddr
;
2174 size_t addrlen
= sizeof(struct sockaddr
);
2177 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2179 *nDataSocket
= lpwfs
->pasvSocket
;
2183 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2184 close(lpwfs
->lstnSocket
);
2185 lpwfs
->lstnSocket
= -1;
2187 return *nDataSocket
!= -1;
2191 /***********************************************************************
2192 * FTP_SendData (internal)
2194 * Send data to the server
2201 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
)
2203 BY_HANDLE_FILE_INFORMATION fi
;
2204 DWORD nBytesRead
= 0;
2205 DWORD nBytesSent
= 0;
2206 DWORD nTotalSent
= 0;
2207 DWORD nBytesToSend
, nLen
, nRC
= 1;
2208 time_t s_long_time
, e_long_time
;
2213 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2214 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2216 /* Get the size of the file. */
2217 GetFileInformationByHandle(hFile
, &fi
);
2222 nBytesToSend
= nBytesRead
- nBytesSent
;
2224 if (nBytesToSend
<= 0)
2226 /* Read data from file. */
2228 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2229 ERR("Failed reading from file\n");
2232 nBytesToSend
= nBytesRead
;
2237 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2238 DATA_PACKET_SIZE
: nBytesToSend
;
2239 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2247 /* Do some computation to display the status. */
2249 nSeconds
= e_long_time
- s_long_time
;
2250 if( nSeconds
/ 60 > 0 )
2252 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2253 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2254 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2258 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2259 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2260 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2262 } while (nRC
!= -1);
2264 TRACE("file transfer complete!\n");
2266 if(lpszBuffer
!= NULL
)
2267 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2273 /***********************************************************************
2274 * FTP_SendRetrieve (internal)
2276 * Send request to retrieve a file
2279 * Number of bytes to be received on success
2283 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
2289 if (!FTP_InitListenSocket(lpwfs
))
2292 if (!FTP_SendType(lpwfs
, dwType
))
2295 if (!FTP_SendPortOrPasv(lpwfs
))
2298 if (!FTP_GetFileSize(lpwfs
, lpszRemoteFile
, &nResult
))
2301 TRACE("Waiting to receive %ld bytes\n", nResult
);
2303 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2306 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2307 MAX_REPLY_LEN
, 0, 0, 0);
2308 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2309 /* That means that we got an error getting the file. */
2314 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2316 close(lpwfs
->lstnSocket
);
2317 lpwfs
->lstnSocket
= -1;
2324 /***********************************************************************
2325 * FTP_RetrieveData (internal)
2327 * Retrieve data from server
2334 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2336 DWORD nBytesWritten
;
2337 DWORD nBytesReceived
= 0;
2343 if (INVALID_HANDLE_VALUE
== hFile
)
2346 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2347 if (NULL
== lpszBuffer
)
2349 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2353 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2355 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2358 /* other side closed socket. */
2361 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2362 nBytesReceived
+= nRC
;
2365 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived
, nBytes
,
2366 nBytesReceived
* 100 / nBytes
);
2369 TRACE("Data transfer complete\n");
2370 if (NULL
!= lpszBuffer
)
2371 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2378 /***********************************************************************
2379 * FTP_CloseSessionHandle (internal)
2381 * Deallocate session handle
2388 BOOL
FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs
)
2392 if (lpwfs
->download_in_progress
!= NULL
)
2393 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2395 if (lpwfs
->sndSocket
!= -1)
2396 close(lpwfs
->sndSocket
);
2398 if (lpwfs
->lstnSocket
!= -1)
2399 close(lpwfs
->lstnSocket
);
2401 if (lpwfs
->lpszPassword
)
2402 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2404 if (lpwfs
->lpszUserName
)
2405 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2407 HeapFree(GetProcessHeap(), 0, lpwfs
);
2413 /***********************************************************************
2414 * FTP_CloseFindNextHandle (internal)
2416 * Deallocate session handle
2423 BOOL
FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn
)
2429 for (i
= 0; i
< lpwfn
->size
; i
++)
2431 if (NULL
!= lpwfn
->lpafp
[i
].lpszName
)
2432 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2435 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2436 HeapFree(GetProcessHeap(), 0, lpwfn
);
2441 /***********************************************************************
2442 * FTP_CloseFileTransferHandle (internal)
2444 * Closes the file transfer handle. This also 'cleans' the data queue of
2445 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2452 BOOL
FTP_CloseFileTransferHandle(LPWININETFILE lpwh
)
2454 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) lpwh
->hdr
.lpwhparent
;
2459 if (!lpwh
->session_deleted
)
2460 lpwfs
->download_in_progress
= NULL
;
2462 /* This just serves to flush the control socket of any spurrious lines written
2463 to it (like '226 Transfer complete.').
2465 Wonder what to do if the server sends us an error code though...
2467 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2468 MAX_REPLY_LEN
, 0, 0, 0);
2470 if (lpwh
->nDataSocket
!= -1)
2471 close(lpwh
->nDataSocket
);
2473 HeapFree(GetProcessHeap(), 0, lpwh
);
2478 /***********************************************************************
2479 * FTP_ReceiveFileList (internal)
2481 * Read file list from server
2484 * Handle to file list on success
2488 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
2489 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
)
2492 LPFILEPROPERTIESA lpafp
= NULL
;
2493 LPWININETFINDNEXTA lpwfn
= NULL
;
2497 if (FTP_ParseDirectory(lpwfs
, nSocket
, &lpafp
, &dwSize
))
2499 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2501 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFINDNEXTA
));
2504 lpwfn
->hdr
.htype
= WH_HFINDNEXT
;
2505 lpwfn
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)lpwfs
;
2506 lpwfn
->hdr
.dwContext
= dwContext
;
2507 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2508 lpwfn
->size
= dwSize
;
2509 lpwfn
->lpafp
= lpafp
;
2513 TRACE("Matched %ld files\n", dwSize
);
2514 return (HINTERNET
)lpwfn
;
2518 /***********************************************************************
2519 * FTP_ConvertFileProp (internal)
2521 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2528 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp
, LPWIN32_FIND_DATAA lpFindFileData
)
2530 BOOL bSuccess
= FALSE
;
2532 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2536 /* Convert 'Unix' time to Windows time */
2537 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
2538 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
2540 /* Not all fields are filled in */
2541 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2542 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
2544 if (lpafp
->bIsDirectory
)
2545 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2547 if (lpafp
->lpszName
)
2548 strncpy(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2557 /***********************************************************************
2558 * FTP_ParseDirectory (internal)
2560 * Parse string of directory information
2566 * FIXME: - This function needs serious clea-up
2567 * - We should consider both UNIX and NT list formats
2569 #define MAX_MONTH_LEN 10
2570 #define MIN_LEN_DIR_ENTRY 15
2572 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
)
2575 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2578 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2584 CHAR pszMonth
[MAX_MONTH_LEN
];
2586 BOOL bSuccess
= TRUE
;
2587 DWORD nBufLen
= MAX_REPLY_LEN
;
2588 LPFILEPROPERTIESA curFileProp
= NULL
;
2589 CHAR
* pszLine
= NULL
;
2590 CHAR
* pszToken
= NULL
;
2591 INT nTokenToSkip
= 3;
2599 INT sizeFilePropArray
= 20;
2600 INT indexFilePropArray
= 0;
2604 /* Allocate intial file properties array */
2605 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESA
)*(sizeFilePropArray
));
2612 while ((pszLine
= INTERNET_GetNextLine(nSocket
, INTERNET_GetResponseBuffer(), &nBufLen
)) != NULL
)
2614 if (sizeFilePropArray
<= indexFilePropArray
)
2616 LPFILEPROPERTIESA tmpafp
;
2618 sizeFilePropArray
*= 2;
2619 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
2620 sizeof(FILEPROPERTIESA
)*sizeFilePropArray
);
2630 curFileProp
= &((*lpafp
)[indexFilePropArray
]);
2632 /* First Parse the permissions. */
2633 pszToken
= strtok(pszLine
, " \t" );
2635 /* HACK! If this is not a file listing skip the line */
2636 if (!pszToken
|| nBufLen
<= MIN_LEN_DIR_ENTRY
)
2638 nBufLen
= MAX_REPLY_LEN
;
2641 if (10 == strlen(pszToken
)) {
2642 /* Unix way of parsing ... */
2643 FTP_ParsePermission(pszToken
, curFileProp
);
2648 pszToken
= strtok( NULL
, " \t" );
2650 } while( nCount
<= nTokenToSkip
);
2652 /* Store the size of the file in the param list. */
2653 TRACE("nSize-> %s\n", pszToken
);
2654 if (pszToken
!= NULL
)
2655 curFileProp
->nSize
= atol(pszToken
);
2657 /* Parse last modified time. */
2665 pszToken
= strtok( NULL
, " \t" );
2666 strncpy(pszMonth
, pszToken
, MAX_MONTH_LEN
);
2667 CharUpperA(pszMonth
);
2668 pszMatch
= strstr(szMonths
, pszMonth
);
2669 if( pszMatch
!= NULL
)
2670 nMonth
= (pszMatch
- szMonths
) / 3;
2672 pszToken
= strtok(NULL
, " \t");
2673 TRACE("nDay -> %s\n", pszToken
);
2674 if (pszToken
!= NULL
)
2675 nDay
= atoi(pszToken
);
2677 pszToken
= strtok(NULL
, " \t");
2678 pszMinutes
= strchr(pszToken
, ':');
2679 if( pszMinutes
!= NULL
) {
2681 nMinutes
= atoi(pszMinutes
);
2682 pszHour
= pszMinutes
- 3;
2683 if (pszHour
!= NULL
)
2684 nHour
= atoi(pszHour
);
2686 apTM
= localtime( &aTime
);
2687 nYear
= apTM
->tm_year
;
2689 nYear
= atoi(pszToken
);
2694 curFileProp
->tmLastModified
.tm_sec
= nSeconds
;
2695 curFileProp
->tmLastModified
.tm_min
= nMinutes
;
2696 curFileProp
->tmLastModified
.tm_hour
= nHour
;
2697 curFileProp
->tmLastModified
.tm_mday
= nDay
;
2698 curFileProp
->tmLastModified
.tm_mon
= nMonth
;
2699 curFileProp
->tmLastModified
.tm_year
= nYear
;
2701 pszToken
= strtok(NULL
, " \t");
2702 if(pszToken
!= NULL
) {
2703 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2704 TRACE(": %s\n", curFileProp
->lpszName
);
2707 nBufLen
= MAX_REPLY_LEN
;
2708 indexFilePropArray
++;
2709 } else if (8 == strlen(pszToken
)) {
2710 /* NT way of parsing ... :
2712 07-13-03 08:55PM <DIR> sakpatch
2713 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2716 curFileProp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
2718 sscanf(pszToken
, "%d-%d-%d",
2719 &curFileProp
->tmLastModified
.tm_mon
,
2720 &curFileProp
->tmLastModified
.tm_mday
,
2721 &curFileProp
->tmLastModified
.tm_year
);
2723 /* Hacky and bad Y2K protection :-) */
2724 if (curFileProp
->tmLastModified
.tm_year
< 70)
2725 curFileProp
->tmLastModified
.tm_year
+= 100;
2727 pszToken
= strtok(NULL
, " \t");
2728 if (pszToken
== NULL
) {
2729 nBufLen
= MAX_REPLY_LEN
;
2732 sscanf(pszToken
, "%d:%d",
2733 &curFileProp
->tmLastModified
.tm_hour
,
2734 &curFileProp
->tmLastModified
.tm_min
);
2735 if ((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
2736 curFileProp
->tmLastModified
.tm_hour
+= 12;
2738 curFileProp
->tmLastModified
.tm_sec
= 0;
2740 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2741 curFileProp
->tmLastModified
.tm_hour
, curFileProp
->tmLastModified
.tm_min
, curFileProp
->tmLastModified
.tm_sec
,
2742 (curFileProp
->tmLastModified
.tm_year
>= 100) ? curFileProp
->tmLastModified
.tm_year
- 100 : curFileProp
->tmLastModified
.tm_year
,
2743 curFileProp
->tmLastModified
.tm_mon
, curFileProp
->tmLastModified
.tm_mday
);
2745 pszToken
= strtok(NULL
, " \t");
2746 if (pszToken
== NULL
) {
2747 nBufLen
= MAX_REPLY_LEN
;
2750 if (!strcasecmp(pszToken
, "<DIR>")) {
2751 curFileProp
->bIsDirectory
= TRUE
;
2752 TRACE("Is directory\n");
2754 curFileProp
->bIsDirectory
= FALSE
;
2755 curFileProp
->nSize
= atol(pszToken
);
2756 TRACE("nSize: %ld\n", curFileProp
->nSize
);
2759 pszToken
= strtok(NULL
, " \t");
2760 if (pszToken
== NULL
) {
2761 nBufLen
= MAX_REPLY_LEN
;
2764 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2765 TRACE("Name: %s\n", curFileProp
->lpszName
);
2767 nBufLen
= MAX_REPLY_LEN
;
2768 indexFilePropArray
++;
2770 nBufLen
= MAX_REPLY_LEN
;
2774 if (bSuccess
&& indexFilePropArray
)
2776 if (indexFilePropArray
< sizeFilePropArray
- 1)
2778 LPFILEPROPERTIESA tmpafp
;
2780 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
2781 sizeof(FILEPROPERTIESA
)*indexFilePropArray
);
2785 *dwfp
= indexFilePropArray
;
2789 HeapFree(GetProcessHeap(), 0, *lpafp
);
2790 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2799 /***********************************************************************
2800 * FTP_ParsePermission (internal)
2802 * Parse permission string of directory information
2809 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
)
2811 BOOL bSuccess
= TRUE
;
2812 unsigned short nPermission
= 0;
2817 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
2823 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
2829 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
2832 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
2835 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
2838 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
2841 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
2844 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
2847 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
2850 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
2853 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
2857 }while (nPos
<= nLast
);
2859 lpfp
->permissions
= nPermission
;
2864 /***********************************************************************
2865 * FTP_SetResponseError (internal)
2867 * Set the appropriate error code for a given response from the server
2872 DWORD
FTP_SetResponseError(DWORD dwResponse
)
2878 case 421: /* Service not available - Server may be shutting down. */
2879 dwCode
= ERROR_INTERNET_TIMEOUT
;
2882 case 425: /* Cannot open data connection. */
2883 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
2886 case 426: /* Connection closed, transer aborted. */
2887 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
2890 case 500: /* Syntax error. Command unrecognized. */
2891 case 501: /* Syntax error. Error in parameters or arguments. */
2892 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
2895 case 530: /* Not logged in. Login incorrect. */
2896 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
2899 case 550: /* File action not taken. File not found or no access. */
2900 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
2903 case 450: /* File action not taken. File may be busy. */
2904 case 451: /* Action aborted. Server error. */
2905 case 452: /* Action not taken. Insufficient storage space on server. */
2906 case 502: /* Command not implemented. */
2907 case 503: /* Bad sequence of command. */
2908 case 504: /* Command not implemented for that parameter. */
2909 case 532: /* Need account for storing files */
2910 case 551: /* Requested action aborted. Page type unknown */
2911 case 552: /* Action aborted. Exceeded storage allocation */
2912 case 553: /* Action not taken. File name not allowed. */
2915 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
2919 INTERNET_SetLastError(dwCode
);