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 /***********************************************************************
148 * FtpPutFileA (WININET.@)
150 * Uploads a file to the FTP server
157 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
158 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
160 LPWININETFTPSESSIONA lpwfs
;
161 LPWININETAPPINFOA hIC
= NULL
;
163 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
164 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
166 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
170 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
171 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
173 WORKREQUEST workRequest
;
174 struct WORKREQ_FTPPUTFILEA
*req
= &workRequest
.u
.FtpPutFileA
;
176 workRequest
.asyncall
= FTPPUTFILEA
;
177 workRequest
.handle
= hConnect
;
178 req
->lpszLocalFile
= FTP_strdup(lpszLocalFile
);
179 req
->lpszNewRemoteFile
= FTP_strdup(lpszNewRemoteFile
);
180 req
->dwFlags
= dwFlags
;
181 req
->dwContext
= dwContext
;
183 return INTERNET_AsyncCall(&workRequest
);
187 return FTP_FtpPutFileA(hConnect
, lpszLocalFile
,
188 lpszNewRemoteFile
, dwFlags
, dwContext
);
192 /***********************************************************************
193 * FTP_FtpPutFileA (Internal)
195 * Uploads a file to the FTP server
202 BOOL WINAPI
FTP_FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
203 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
206 BOOL bSuccess
= FALSE
;
207 LPWININETAPPINFOA hIC
= NULL
;
208 LPWININETFTPSESSIONA lpwfs
;
211 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile
, lpszNewRemoteFile
);
213 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
214 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
216 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
220 /* Clear any error information */
221 INTERNET_SetLastError(0);
223 /* Open file to be uploaded */
224 if (INVALID_HANDLE_VALUE
==
225 (hFile
= CreateFileA(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
227 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND
);
231 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
232 if (hIC
->lpfnStatusCB
)
233 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
235 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
239 /* Get data socket to server */
240 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
242 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
244 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
245 MAX_REPLY_LEN
, 0, 0, 0);
251 FTP_SetResponseError(nResCode
);
257 if (lpwfs
->lstnSocket
!= -1)
258 close(lpwfs
->lstnSocket
);
260 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
262 INTERNET_ASYNC_RESULT iar
;
264 iar
.dwResult
= (DWORD
)bSuccess
;
265 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
266 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
267 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
277 /***********************************************************************
278 * FtpSetCurrentDirectoryA (WININET.@)
280 * Change the working directory on the FTP server
287 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
289 LPWININETFTPSESSIONA lpwfs
;
290 LPWININETAPPINFOA hIC
= NULL
;
292 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
293 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
295 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
299 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
301 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
302 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
304 WORKREQUEST workRequest
;
305 struct WORKREQ_FTPSETCURRENTDIRECTORYA
*req
;
307 workRequest
.asyncall
= FTPSETCURRENTDIRECTORYA
;
308 workRequest
.handle
= hConnect
;
309 req
= &workRequest
.u
.FtpSetCurrentDirectoryA
;
310 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
312 return INTERNET_AsyncCall(&workRequest
);
316 return FTP_FtpSetCurrentDirectoryA(hConnect
, lpszDirectory
);
321 /***********************************************************************
322 * FtpSetCurrentDirectoryW (WININET.@)
324 * Change the working directory on the FTP server
331 BOOL WINAPI
FtpSetCurrentDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
337 len
= WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, NULL
, 0, NULL
, NULL
);
338 szDir
= HeapAlloc(GetProcessHeap(), 0, len
);
341 WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, szDir
, len
, NULL
, NULL
);
342 rc
= FtpSetCurrentDirectoryA(hConnect
, szDir
);
343 HeapFree(GetProcessHeap(), 0, szDir
);
349 /***********************************************************************
350 * FTP_FtpSetCurrentDirectoryA (Internal)
352 * Change the working directory on the FTP server
359 BOOL WINAPI
FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
362 LPWININETFTPSESSIONA lpwfs
;
363 LPWININETAPPINFOA hIC
= NULL
;
364 DWORD bSuccess
= FALSE
;
366 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
368 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
369 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
371 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
375 /* Clear any error information */
376 INTERNET_SetLastError(0);
378 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
379 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
380 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
383 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
384 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
391 FTP_SetResponseError(nResCode
);
395 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
397 INTERNET_ASYNC_RESULT iar
;
399 iar
.dwResult
= (DWORD
)bSuccess
;
400 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
401 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
402 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
408 /***********************************************************************
409 * FtpCreateDirectoryA (WININET.@)
411 * Create new directory on the FTP server
418 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
420 LPWININETFTPSESSIONA lpwfs
;
421 LPWININETAPPINFOA hIC
= NULL
;
423 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
424 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
426 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
430 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
431 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
433 WORKREQUEST workRequest
;
434 struct WORKREQ_FTPCREATEDIRECTORYA
*req
;
436 workRequest
.asyncall
= FTPCREATEDIRECTORYA
;
437 workRequest
.handle
= hConnect
;
438 req
= &workRequest
.u
.FtpCreateDirectoryA
;
439 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
441 return INTERNET_AsyncCall(&workRequest
);
445 return FTP_FtpCreateDirectoryA(hConnect
, lpszDirectory
);
450 /***********************************************************************
451 * FtpCreateDirectoryW (WININET.@)
453 * Create new directory on the FTP server
460 BOOL WINAPI
FtpCreateDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
466 len
= WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, NULL
, 0, NULL
, NULL
);
467 szDir
= HeapAlloc(GetProcessHeap(), 0, len
);
470 WideCharToMultiByte(CP_ACP
, 0, lpszDirectory
, -1, szDir
, len
, NULL
, NULL
);
471 rc
= FtpCreateDirectoryA(hConnect
, szDir
);
472 HeapFree(GetProcessHeap(), 0, szDir
);
478 /***********************************************************************
479 * FTP_FtpCreateDirectoryA (Internal)
481 * Create new directory on the FTP server
488 BOOL WINAPI
FTP_FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
491 BOOL bSuccess
= FALSE
;
492 LPWININETAPPINFOA hIC
= NULL
;
493 LPWININETFTPSESSIONA lpwfs
;
497 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
498 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
500 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
504 /* Clear any error information */
505 INTERNET_SetLastError(0);
507 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
510 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
511 MAX_REPLY_LEN
, 0, 0, 0);
517 FTP_SetResponseError(nResCode
);
521 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
522 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
524 INTERNET_ASYNC_RESULT iar
;
526 iar
.dwResult
= (DWORD
)bSuccess
;
527 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
528 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
529 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
536 /***********************************************************************
537 * FtpFindFirstFileA (WININET.@)
539 * Search the specified directory
542 * HINTERNET on success
546 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
547 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
549 LPWININETFTPSESSIONA lpwfs
;
550 LPWININETAPPINFOA hIC
= NULL
;
552 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
553 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
555 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
559 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
560 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
562 WORKREQUEST workRequest
;
563 struct WORKREQ_FTPFINDFIRSTFILEA
*req
;
565 workRequest
.asyncall
= FTPFINDFIRSTFILEA
;
566 workRequest
.handle
= hConnect
;
567 req
= &workRequest
.u
.FtpFindFirstFileA
;
568 req
->lpszSearchFile
= FTP_strdup(lpszSearchFile
);
569 req
->lpFindFileData
= lpFindFileData
;
570 req
->dwFlags
= dwFlags
;
571 req
->dwContext
= dwContext
;
573 INTERNET_AsyncCall(&workRequest
);
578 return FTP_FtpFindFirstFileA(hConnect
, lpszSearchFile
, lpFindFileData
,
584 /***********************************************************************
585 * FtpFindFirstFileA (WININET.@)
587 * Search the specified directory
590 * HINTERNET on success
594 HINTERNET WINAPI
FtpFindFirstFileW(HINTERNET hConnect
,
595 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
602 /***********************************************************************
603 * FTP_FtpFindFirstFileA (Internal)
605 * Search the specified directory
608 * HINTERNET on success
612 HINTERNET WINAPI
FTP_FtpFindFirstFileA(HINTERNET hConnect
,
613 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
616 LPWININETAPPINFOA hIC
= NULL
;
617 LPWININETFTPSESSIONA lpwfs
;
618 HINTERNET hFindNext
= NULL
;
622 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hConnect
);
623 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
625 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
629 /* Clear any error information */
630 INTERNET_SetLastError(0);
632 if (!FTP_InitListenSocket(lpwfs
))
635 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
638 if (!FTP_SendPortOrPasv(lpwfs
))
641 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
642 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, lpszSearchFile
,
643 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
646 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
647 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
650 if (nResCode
== 125 || nResCode
== 150)
654 /* Get data socket to server */
655 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
657 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpFindFileData
, dwContext
);
659 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
660 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
661 if (nResCode
!= 226 && nResCode
!= 250)
662 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
668 FTP_SetResponseError(nResCode
);
672 if (lpwfs
->lstnSocket
!= -1)
673 close(lpwfs
->lstnSocket
);
675 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
677 INTERNET_ASYNC_RESULT iar
;
681 iar
.dwResult
= (DWORD
)hFindNext
;
682 iar
.dwError
= ERROR_SUCCESS
;
683 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
684 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
687 iar
.dwResult
= (DWORD
)hFindNext
;
688 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
689 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
690 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
697 /***********************************************************************
698 * FtpGetCurrentDirectoryA (WININET.@)
700 * Retrieves the current directory
707 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
708 LPDWORD lpdwCurrentDirectory
)
710 LPWININETFTPSESSIONA lpwfs
;
711 LPWININETAPPINFOA hIC
= NULL
;
713 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
715 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
716 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
718 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
722 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
723 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
725 WORKREQUEST workRequest
;
726 struct WORKREQ_FTPGETCURRENTDIRECTORYA
*req
;
728 workRequest
.asyncall
= FTPGETCURRENTDIRECTORYA
;
729 workRequest
.handle
= hFtpSession
;
730 req
= &workRequest
.u
.FtpGetCurrentDirectoryA
;
731 req
->lpszDirectory
= lpszCurrentDirectory
;
732 req
->lpdwDirectory
= lpdwCurrentDirectory
;
734 return INTERNET_AsyncCall(&workRequest
);
738 return FTP_FtpGetCurrentDirectoryA(hFtpSession
, lpszCurrentDirectory
,
739 lpdwCurrentDirectory
);
744 /***********************************************************************
745 * FtpGetCurrentDirectoryW (WININET.@)
747 * Retrieves the current directory
754 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
755 LPDWORD lpdwCurrentDirectory
)
762 /***********************************************************************
763 * FTP_FtpGetCurrentDirectoryA (Internal)
765 * Retrieves the current directory
772 BOOL WINAPI
FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
773 LPDWORD lpdwCurrentDirectory
)
776 LPWININETFTPSESSIONA lpwfs
;
777 LPWININETAPPINFOA hIC
= NULL
;
778 DWORD bSuccess
= FALSE
;
780 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
782 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
783 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
785 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
789 /* Clear any error information */
790 INTERNET_SetLastError(0);
792 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
794 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
795 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
796 hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
))
799 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
800 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
);
803 if (nResCode
== 257) /* Extract directory name */
805 INT firstpos
, lastpos
, len
;
806 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
808 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
810 if ('"' == lpszResponseBuffer
[lastpos
])
819 len
= lastpos
- firstpos
- 1;
820 strncpy(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1],
821 len
< *lpdwCurrentDirectory
? len
: *lpdwCurrentDirectory
);
822 *lpdwCurrentDirectory
= len
;
826 FTP_SetResponseError(nResCode
);
830 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
832 INTERNET_ASYNC_RESULT iar
;
834 iar
.dwResult
= (DWORD
)bSuccess
;
835 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
836 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
837 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
840 return (DWORD
) bSuccess
;
843 /***********************************************************************
844 * FtpOpenFileA (WININET.@)
846 * Open a remote file for writing or reading
849 * HINTERNET handle on success
853 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
854 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
857 LPWININETFTPSESSIONA lpwfs
;
858 LPWININETAPPINFOA hIC
= NULL
;
860 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
861 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
863 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
867 if (lpwfs
->download_in_progress
!= NULL
) {
868 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
872 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
873 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
875 WORKREQUEST workRequest
;
876 struct WORKREQ_FTPOPENFILEA
*req
;
878 workRequest
.asyncall
= FTPOPENFILEA
;
879 workRequest
.handle
= hFtpSession
;
880 req
= &workRequest
.u
.FtpOpenFileA
;
881 req
->lpszFilename
= FTP_strdup(lpszFileName
);
882 req
->dwAccess
= fdwAccess
;
883 req
->dwFlags
= dwFlags
;
884 req
->dwContext
= dwContext
;
886 INTERNET_AsyncCall(&workRequest
);
891 return FTP_FtpOpenFileA(hFtpSession
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
896 /***********************************************************************
897 * FtpOpenFileW (WININET.@)
899 * Open a remote file for writing or reading
902 * HINTERNET handle on success
906 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
907 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
915 /***********************************************************************
916 * FTP_FtpOpenFileA (Internal)
918 * Open a remote file for writing or reading
921 * HINTERNET handle on success
925 HINTERNET
FTP_FtpOpenFileA(HINTERNET hFtpSession
,
926 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
930 BOOL bSuccess
= FALSE
;
931 LPWININETFILE lpwh
= NULL
;
932 LPWININETAPPINFOA hIC
= NULL
;
933 LPWININETFTPSESSIONA lpwfs
;
934 HINTERNET handle
= NULL
;
938 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
939 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
941 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
945 /* Clear any error information */
946 INTERNET_SetLastError(0);
948 if (GENERIC_READ
== fdwAccess
)
950 /* Set up socket to retrieve data */
951 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
953 else if (GENERIC_WRITE
== fdwAccess
)
955 /* Set up socket to send data */
956 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
959 /* Get data socket to server */
960 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
962 lpwh
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE
));
963 handle
= WININET_AllocHandle( &lpwh
->hdr
);
964 lpwh
->hdr
.htype
= WH_HFILE
;
965 lpwh
->hdr
.dwFlags
= dwFlags
;
966 lpwh
->hdr
.dwContext
= dwContext
;
967 lpwh
->hdr
.lpwhparent
= &lpwfs
->hdr
;
968 lpwh
->nDataSocket
= nDataSocket
;
969 lpwh
->session_deleted
= FALSE
;
971 /* Indicate that a download is currently in progress */
972 lpwfs
->download_in_progress
= lpwh
;
975 if (lpwfs
->lstnSocket
!= -1)
976 close(lpwfs
->lstnSocket
);
978 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
979 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
981 INTERNET_ASYNC_RESULT iar
;
985 iar
.dwResult
= (DWORD
)handle
;
986 iar
.dwError
= ERROR_SUCCESS
;
987 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
988 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
991 iar
.dwResult
= (DWORD
)bSuccess
;
992 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
993 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
994 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1001 /***********************************************************************
1002 * FtpGetFileA (WININET.@)
1004 * Retrieve file from the FTP server
1011 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1012 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1015 LPWININETFTPSESSIONA lpwfs
;
1016 LPWININETAPPINFOA hIC
= NULL
;
1018 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hInternet
);
1019 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1021 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1025 if (lpwfs
->download_in_progress
!= NULL
) {
1026 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
1030 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1031 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1033 WORKREQUEST workRequest
;
1034 struct WORKREQ_FTPGETFILEA
*req
;
1036 workRequest
.asyncall
= FTPGETFILEA
;
1037 workRequest
.handle
= hInternet
;
1038 req
= &workRequest
.u
.FtpGetFileA
;
1039 req
->lpszRemoteFile
= FTP_strdup(lpszRemoteFile
);
1040 req
->lpszNewFile
= FTP_strdup(lpszNewFile
);
1041 req
->dwLocalFlagsAttribute
= dwLocalFlagsAttribute
;
1042 req
->fFailIfExists
= fFailIfExists
;
1043 req
->dwFlags
= dwInternetFlags
;
1044 req
->dwContext
= dwContext
;
1046 return INTERNET_AsyncCall(&workRequest
);
1050 return FTP_FtpGetFileA(hInternet
, lpszRemoteFile
, lpszNewFile
,
1051 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1056 /***********************************************************************
1057 * FtpGetFileW (WININET.@)
1059 * Retrieve file from the FTP server
1066 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1067 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1075 /***********************************************************************
1076 * FTP_FtpGetFileA (Internal)
1078 * Retrieve file from the FTP server
1085 BOOL WINAPI
FTP_FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1086 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1090 BOOL bSuccess
= FALSE
;
1092 LPWININETAPPINFOA hIC
= NULL
;
1093 LPWININETFTPSESSIONA lpwfs
;
1095 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile
, lpszNewFile
);
1097 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hInternet
);
1098 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1100 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1104 /* Clear any error information */
1105 INTERNET_SetLastError(0);
1107 /* Ensure we can write to lpszNewfile by opening it */
1108 hFile
= CreateFileA(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1109 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1110 if (INVALID_HANDLE_VALUE
== hFile
)
1113 /* Set up socket to retrieve data */
1114 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
1120 /* Get data socket to server */
1121 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1126 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
1127 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1128 MAX_REPLY_LEN
, 0, 0, 0);
1131 if (nResCode
== 226)
1134 FTP_SetResponseError(nResCode
);
1141 if (lpwfs
->lstnSocket
!= -1)
1142 close(lpwfs
->lstnSocket
);
1147 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1148 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1150 INTERNET_ASYNC_RESULT iar
;
1152 iar
.dwResult
= (DWORD
)bSuccess
;
1153 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1154 hIC
->lpfnStatusCB(hInternet
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1155 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1162 /***********************************************************************
1163 * FtpDeleteFileA (WININET.@)
1165 * Delete a file on the ftp server
1172 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1174 LPWININETFTPSESSIONA lpwfs
;
1175 LPWININETAPPINFOA hIC
= NULL
;
1177 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1178 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1180 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1184 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1185 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1187 WORKREQUEST workRequest
;
1188 struct WORKREQ_FTPDELETEFILEA
*req
;
1190 workRequest
.asyncall
= FTPDELETEFILEA
;
1191 workRequest
.handle
= hFtpSession
;
1192 req
= &workRequest
.u
.FtpDeleteFileA
;
1193 req
->lpszFilename
= FTP_strdup(lpszFileName
);
1195 return INTERNET_AsyncCall(&workRequest
);
1199 return FTP_FtpDeleteFileA(hFtpSession
, lpszFileName
);
1204 /***********************************************************************
1205 * FTP_FtpDeleteFileA (Internal)
1207 * Delete a file on the ftp server
1214 BOOL
FTP_FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1217 BOOL bSuccess
= FALSE
;
1218 LPWININETAPPINFOA hIC
= NULL
;
1219 LPWININETFTPSESSIONA lpwfs
;
1221 TRACE("0x%08lx\n", (ULONG
) hFtpSession
);
1223 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1224 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1226 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1230 /* Clear any error information */
1231 INTERNET_SetLastError(0);
1233 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1236 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1237 MAX_REPLY_LEN
, 0, 0, 0);
1240 if (nResCode
== 250)
1243 FTP_SetResponseError(nResCode
);
1246 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1247 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1249 INTERNET_ASYNC_RESULT iar
;
1251 iar
.dwResult
= (DWORD
)bSuccess
;
1252 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1253 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1254 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1261 /***********************************************************************
1262 * FtpRemoveDirectoryA (WININET.@)
1264 * Remove a directory on the ftp server
1271 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1273 LPWININETFTPSESSIONA lpwfs
;
1274 LPWININETAPPINFOA hIC
= NULL
;
1276 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1277 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1279 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1283 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1284 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1286 WORKREQUEST workRequest
;
1287 struct WORKREQ_FTPREMOVEDIRECTORYA
*req
;
1289 workRequest
.asyncall
= FTPREMOVEDIRECTORYA
;
1290 workRequest
.handle
= hFtpSession
;
1291 req
= &workRequest
.u
.FtpRemoveDirectoryA
;
1292 req
->lpszDirectory
= FTP_strdup(lpszDirectory
);
1294 return INTERNET_AsyncCall(&workRequest
);
1298 return FTP_FtpRemoveDirectoryA(hFtpSession
, lpszDirectory
);
1303 /***********************************************************************
1304 * FTP_FtpRemoveDirectoryA (Internal)
1306 * Remove a directory on the ftp server
1313 BOOL
FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1316 BOOL bSuccess
= FALSE
;
1317 LPWININETAPPINFOA hIC
= NULL
;
1318 LPWININETFTPSESSIONA lpwfs
;
1322 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1323 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1325 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1329 /* Clear any error information */
1330 INTERNET_SetLastError(0);
1332 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1335 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1336 MAX_REPLY_LEN
, 0, 0, 0);
1339 if (nResCode
== 250)
1342 FTP_SetResponseError(nResCode
);
1346 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1347 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1349 INTERNET_ASYNC_RESULT iar
;
1351 iar
.dwResult
= (DWORD
)bSuccess
;
1352 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1353 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1354 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1361 /***********************************************************************
1362 * FtpRenameFileA (WININET.@)
1364 * Rename a file on the ftp server
1371 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1373 LPWININETFTPSESSIONA lpwfs
;
1374 LPWININETAPPINFOA hIC
= NULL
;
1376 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1377 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1379 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1383 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1384 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1386 WORKREQUEST workRequest
;
1387 struct WORKREQ_FTPRENAMEFILEA
*req
;
1389 workRequest
.asyncall
= FTPRENAMEFILEA
;
1390 workRequest
.handle
= hFtpSession
;
1391 req
= &workRequest
.u
.FtpRenameFileA
;
1392 req
->lpszSrcFile
= FTP_strdup(lpszSrc
);
1393 req
->lpszDestFile
= FTP_strdup(lpszDest
);
1395 return INTERNET_AsyncCall(&workRequest
);
1399 return FTP_FtpRenameFileA(hFtpSession
, lpszSrc
, lpszDest
);
1403 /***********************************************************************
1404 * FTP_FtpRenameFileA (Internal)
1406 * Rename a file on the ftp server
1413 BOOL
FTP_FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1416 BOOL bSuccess
= FALSE
;
1417 LPWININETAPPINFOA hIC
= NULL
;
1418 LPWININETFTPSESSIONA lpwfs
;
1422 lpwfs
= (LPWININETFTPSESSIONA
) WININET_GetObject( hFtpSession
);
1423 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1425 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1429 /* Clear any error information */
1430 INTERNET_SetLastError(0);
1432 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1435 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1436 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1437 if (nResCode
== 350)
1439 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1442 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1443 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1446 if (nResCode
== 250)
1449 FTP_SetResponseError(nResCode
);
1452 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1453 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1455 INTERNET_ASYNC_RESULT iar
;
1457 iar
.dwResult
= (DWORD
)bSuccess
;
1458 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1459 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1460 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1467 /***********************************************************************
1468 * FTP_Connect (internal)
1470 * Connect to a ftp server
1473 * HINTERNET a session handle on success
1478 HINTERNET
FTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
1479 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
1480 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
1482 struct sockaddr_in socketAddr
;
1483 struct hostent
*phe
= NULL
;
1484 INT nsocket
= -1, sock_namelen
;
1485 LPWININETAPPINFOA hIC
= NULL
;
1486 BOOL bSuccess
= FALSE
;
1487 LPWININETFTPSESSIONA lpwfs
= NULL
;
1488 HINTERNET handle
= NULL
;
1490 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1491 (ULONG
) hInternet
, lpszServerName
,
1492 nServerPort
, lpszUserName
, lpszPassword
);
1494 hIC
= (LPWININETAPPINFOA
) WININET_GetObject( hInternet
);
1495 if ( (hIC
== NULL
) || (hIC
->hdr
.htype
!= WH_HINIT
) )
1498 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1500 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME
);
1504 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1505 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1507 if (hIC
->lpfnStatusCB
)
1508 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1509 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1511 if (!GetAddress(lpszServerName
, nServerPort
, &phe
, &socketAddr
))
1513 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1517 if (hIC
->lpfnStatusCB
)
1518 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1519 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1521 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1524 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1528 if (hIC
->lpfnStatusCB
)
1529 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1530 &socketAddr
, sizeof(struct sockaddr_in
));
1532 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1534 ERR("Unable to connect (%s)\n", strerror(errno
));
1535 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1539 TRACE("Connected to server\n");
1540 if (hIC
->lpfnStatusCB
)
1541 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1542 &socketAddr
, sizeof(struct sockaddr_in
));
1544 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA
));
1547 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1551 handle
= WININET_AllocHandle( &lpwfs
->hdr
);
1554 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1558 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1559 lpwfs
->hdr
.dwFlags
= dwFlags
;
1560 lpwfs
->hdr
.dwContext
= dwContext
;
1561 lpwfs
->hdr
.lpwhparent
= &hIC
->hdr
;
1562 lpwfs
->sndSocket
= nsocket
;
1563 lpwfs
->download_in_progress
= NULL
;
1564 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1565 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1566 lpwfs
->phostent
= phe
;
1568 if (NULL
== lpszUserName
)
1570 lpwfs
->lpszUserName
= FTP_strdup("anonymous");
1571 lpwfs
->lpszPassword
= FTP_strdup("user@server");
1575 lpwfs
->lpszUserName
= FTP_strdup(lpszUserName
);
1576 lpwfs
->lpszPassword
= FTP_strdup(lpszPassword
);
1579 if (FTP_ConnectToHost(lpwfs
))
1581 if (hIC
->lpfnStatusCB
)
1583 INTERNET_ASYNC_RESULT iar
;
1585 iar
.dwResult
= (DWORD
)handle
;
1586 iar
.dwError
= ERROR_SUCCESS
;
1588 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1589 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1591 TRACE("Successfully logged into server\n");
1597 if (!bSuccess
&& nsocket
== -1)
1600 if (!bSuccess
&& lpwfs
)
1602 HeapFree(GetProcessHeap(), 0, lpwfs
);
1603 WININET_FreeHandle( handle
);
1607 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1609 INTERNET_ASYNC_RESULT iar
;
1611 iar
.dwResult
= (DWORD
)lpwfs
;
1612 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1613 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1614 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1621 /***********************************************************************
1622 * FTP_ConnectToHost (internal)
1624 * Connect to a ftp server
1631 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
)
1634 BOOL bSuccess
= FALSE
;
1637 FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1639 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1642 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1643 MAX_REPLY_LEN
, 0, 0, 0);
1646 /* Login successful... */
1647 if (nResCode
== 230)
1649 /* User name okay, need password... */
1650 else if (nResCode
== 331)
1651 bSuccess
= FTP_SendPassword(lpwfs
);
1652 /* Need account for login... */
1653 else if (nResCode
== 332)
1654 bSuccess
= FTP_SendAccount(lpwfs
);
1656 FTP_SetResponseError(nResCode
);
1659 TRACE("Returning %d\n", bSuccess
);
1665 /***********************************************************************
1666 * FTP_SendCommand (internal)
1668 * Send command to server
1675 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
1676 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1680 DWORD nBytesSent
= 0;
1684 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
1687 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1689 bParamHasLen
= lpszParam
&& strlen(lpszParam
) > 0;
1690 len
= (bParamHasLen
? strlen(lpszParam
) : -1) + strlen(szFtpCommands
[ftpCmd
]) +
1692 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1694 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1697 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], bParamHasLen
? " " : "",
1698 bParamHasLen
? lpszParam
: "", szCRLF
);
1700 TRACE("Sending (%s) len(%ld)\n", buf
, len
);
1701 while((nBytesSent
< len
) && (nRC
!= -1))
1703 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1707 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1710 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1711 &nBytesSent
, sizeof(DWORD
));
1713 TRACE("Sent %ld bytes\n", nBytesSent
);
1718 /***********************************************************************
1719 * FTP_ReceiveResponse (internal)
1721 * Receive response from server
1724 * Reply code on success
1729 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
1730 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1734 char firstprefix
[5];
1735 BOOL multiline
= FALSE
;
1738 TRACE("socket(%d) \n", nSocket
);
1741 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
1746 if (!INTERNET_GetNextLine(nSocket
, lpszResponse
, &nRecv
))
1753 if(lpszResponse
[3] != '-')
1756 { /* Start of multiline repsonse. Loop until we get "nnn " */
1758 memcpy(firstprefix
, lpszResponse
, 3);
1759 firstprefix
[3] = ' ';
1760 firstprefix
[4] = '\0';
1765 if(!memcmp(firstprefix
, lpszResponse
, 4))
1773 rc
= atoi(lpszResponse
);
1776 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
1777 &nRecv
, sizeof(DWORD
));
1781 TRACE("return %d\n", rc
);
1786 /***********************************************************************
1787 * FTP_SendPassword (internal)
1789 * Send password to ftp server
1796 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
)
1799 BOOL bSuccess
= FALSE
;
1802 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
1805 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1806 MAX_REPLY_LEN
, 0, 0, 0);
1809 TRACE("Received reply code %d\n", nResCode
);
1810 /* Login successful... */
1811 if (nResCode
== 230)
1813 /* Command not implemented, superfluous at the server site... */
1814 /* Need account for login... */
1815 else if (nResCode
== 332)
1816 bSuccess
= FTP_SendAccount(lpwfs
);
1818 FTP_SetResponseError(nResCode
);
1822 TRACE("Returning %d\n", bSuccess
);
1827 /***********************************************************************
1828 * FTP_SendAccount (internal)
1837 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
)
1840 BOOL bSuccess
= FALSE
;
1843 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, NOACCOUNT
, 0, 0, 0))
1846 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1847 MAX_REPLY_LEN
, 0, 0, 0);
1851 FTP_SetResponseError(nResCode
);
1858 /***********************************************************************
1859 * FTP_SendStore (internal)
1861 * Send request to upload file to ftp server
1868 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
1871 BOOL bSuccess
= FALSE
;
1874 if (!FTP_InitListenSocket(lpwfs
))
1877 if (!FTP_SendType(lpwfs
, dwType
))
1880 if (!FTP_SendPortOrPasv(lpwfs
))
1883 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
1885 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1886 MAX_REPLY_LEN
, 0, 0, 0);
1889 if (nResCode
== 150)
1892 FTP_SetResponseError(nResCode
);
1896 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
1898 close(lpwfs
->lstnSocket
);
1899 lpwfs
->lstnSocket
= -1;
1906 /***********************************************************************
1907 * FTP_InitListenSocket (internal)
1909 * Create a socket to listen for server response
1916 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
)
1918 BOOL bSuccess
= FALSE
;
1919 size_t namelen
= sizeof(struct sockaddr_in
);
1923 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
1924 if (lpwfs
->lstnSocket
== -1)
1926 TRACE("Unable to create listening socket\n");
1930 /* We obtain our ip addr from the name of the command channel socket */
1931 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
1933 /* and get the system to assign us a port */
1934 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
1936 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
1938 TRACE("Unable to bind socket\n");
1942 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
1944 TRACE("listen failed\n");
1948 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
1952 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
1954 close(lpwfs
->lstnSocket
);
1955 lpwfs
->lstnSocket
= -1;
1962 /***********************************************************************
1963 * FTP_SendType (internal)
1965 * Tell server type of data being transferred
1971 * W98SE doesn't cache the type that's currently set
1972 * (i.e. it sends it always),
1973 * so we probably don't want to do that either.
1975 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
)
1978 CHAR type
[2] = { "I" };
1979 BOOL bSuccess
= FALSE
;
1982 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
1985 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
1988 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1989 MAX_REPLY_LEN
, 0, 0, 0)/100;
1995 FTP_SetResponseError(nResCode
);
2002 /***********************************************************************
2003 * FTP_GetFileSize (internal)
2005 * Retrieves from the server the size of the given file
2012 BOOL
FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD
*dwSize
)
2015 BOOL bSuccess
= FALSE
;
2019 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
2022 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2023 MAX_REPLY_LEN
, 0, 0, 0);
2026 if (nResCode
== 213) {
2027 /* Now parses the output to get the actual file size */
2029 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2031 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
2032 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
2033 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
2037 FTP_SetResponseError(nResCode
);
2046 /***********************************************************************
2047 * FTP_SendPort (internal)
2049 * Tell server which port to use
2056 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
)
2059 CHAR szIPAddress
[64];
2060 BOOL bSuccess
= FALSE
;
2063 sprintf(szIPAddress
, "%d,%d,%d,%d,%d,%d",
2064 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2065 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2066 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2067 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2068 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2069 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2071 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2074 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2075 MAX_REPLY_LEN
,0, 0, 0);
2078 if (nResCode
== 200)
2081 FTP_SetResponseError(nResCode
);
2089 /***********************************************************************
2090 * FTP_DoPassive (internal)
2092 * Tell server that we want to do passive transfers
2093 * and connect data socket
2100 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
)
2103 BOOL bSuccess
= FALSE
;
2106 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2109 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2110 MAX_REPLY_LEN
,0, 0, 0);
2113 if (nResCode
== 227)
2115 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2119 char *pAddr
, *pPort
;
2121 struct sockaddr_in dataSocketAddress
;
2123 p
= lpszResponseBuffer
+4; /* skip status code */
2125 /* do a very strict check; we can improve that later. */
2127 if (strncmp(p
, "Entering Passive Mode", 21))
2129 ERR("unknown response '%.*s', aborting\n", 21, p
);
2132 p
+= 21; /* skip string */
2133 if ((*p
++ != ' ') || (*p
++ != '('))
2135 ERR("unknown response format, aborting\n");
2139 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2142 ERR("unknown response address format '%s', aborting\n", p
);
2145 for (i
=0; i
< 6; i
++)
2148 dataSocketAddress
= lpwfs
->socketAddress
;
2149 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2150 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2158 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2162 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2164 ERR("can't connect passive FTP data port.\n");
2167 lpwfs
->pasvSocket
= nsocket
;
2171 FTP_SetResponseError(nResCode
);
2179 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
)
2181 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2183 if (!FTP_DoPassive(lpwfs
))
2188 if (!FTP_SendPort(lpwfs
))
2195 /***********************************************************************
2196 * FTP_GetDataSocket (internal)
2198 * Either accepts an incoming data socket connection from the server
2199 * or just returns the already opened socket after a PASV command
2200 * in case of passive FTP.
2208 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
)
2210 struct sockaddr_in saddr
;
2211 size_t addrlen
= sizeof(struct sockaddr
);
2214 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2216 *nDataSocket
= lpwfs
->pasvSocket
;
2220 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2221 close(lpwfs
->lstnSocket
);
2222 lpwfs
->lstnSocket
= -1;
2224 return *nDataSocket
!= -1;
2228 /***********************************************************************
2229 * FTP_SendData (internal)
2231 * Send data to the server
2238 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
)
2240 BY_HANDLE_FILE_INFORMATION fi
;
2241 DWORD nBytesRead
= 0;
2242 DWORD nBytesSent
= 0;
2243 DWORD nTotalSent
= 0;
2244 DWORD nBytesToSend
, nLen
, nRC
= 1;
2245 time_t s_long_time
, e_long_time
;
2250 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2251 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2253 /* Get the size of the file. */
2254 GetFileInformationByHandle(hFile
, &fi
);
2259 nBytesToSend
= nBytesRead
- nBytesSent
;
2261 if (nBytesToSend
<= 0)
2263 /* Read data from file. */
2265 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2266 ERR("Failed reading from file\n");
2269 nBytesToSend
= nBytesRead
;
2274 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2275 DATA_PACKET_SIZE
: nBytesToSend
;
2276 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2284 /* Do some computation to display the status. */
2286 nSeconds
= e_long_time
- s_long_time
;
2287 if( nSeconds
/ 60 > 0 )
2289 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2290 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2291 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2295 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2296 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2297 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2299 } while (nRC
!= -1);
2301 TRACE("file transfer complete!\n");
2303 if(lpszBuffer
!= NULL
)
2304 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2310 /***********************************************************************
2311 * FTP_SendRetrieve (internal)
2313 * Send request to retrieve a file
2316 * Number of bytes to be received on success
2320 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
2326 if (!FTP_InitListenSocket(lpwfs
))
2329 if (!FTP_SendType(lpwfs
, dwType
))
2332 if (!FTP_SendPortOrPasv(lpwfs
))
2335 if (!FTP_GetFileSize(lpwfs
, lpszRemoteFile
, &nResult
))
2338 TRACE("Waiting to receive %ld bytes\n", nResult
);
2340 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2343 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2344 MAX_REPLY_LEN
, 0, 0, 0);
2345 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2346 /* That means that we got an error getting the file. */
2351 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2353 close(lpwfs
->lstnSocket
);
2354 lpwfs
->lstnSocket
= -1;
2361 /***********************************************************************
2362 * FTP_RetrieveData (internal)
2364 * Retrieve data from server
2371 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2373 DWORD nBytesWritten
;
2374 DWORD nBytesReceived
= 0;
2380 if (INVALID_HANDLE_VALUE
== hFile
)
2383 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2384 if (NULL
== lpszBuffer
)
2386 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2390 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2392 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2395 /* other side closed socket. */
2398 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2399 nBytesReceived
+= nRC
;
2402 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived
, nBytes
,
2403 nBytesReceived
* 100 / nBytes
);
2406 TRACE("Data transfer complete\n");
2407 if (NULL
!= lpszBuffer
)
2408 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2415 /***********************************************************************
2416 * FTP_CloseSessionHandle (internal)
2418 * Deallocate session handle
2425 BOOL
FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs
)
2429 if (lpwfs
->download_in_progress
!= NULL
)
2430 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2432 if (lpwfs
->sndSocket
!= -1)
2433 close(lpwfs
->sndSocket
);
2435 if (lpwfs
->lstnSocket
!= -1)
2436 close(lpwfs
->lstnSocket
);
2438 if (lpwfs
->lpszPassword
)
2439 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2441 if (lpwfs
->lpszUserName
)
2442 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2444 HeapFree(GetProcessHeap(), 0, lpwfs
);
2450 /***********************************************************************
2451 * FTP_CloseFindNextHandle (internal)
2453 * Deallocate session handle
2460 BOOL
FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn
)
2466 for (i
= 0; i
< lpwfn
->size
; i
++)
2468 if (NULL
!= lpwfn
->lpafp
[i
].lpszName
)
2469 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2472 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2473 HeapFree(GetProcessHeap(), 0, lpwfn
);
2478 /***********************************************************************
2479 * FTP_CloseFileTransferHandle (internal)
2481 * Closes the file transfer handle. This also 'cleans' the data queue of
2482 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2489 BOOL
FTP_CloseFileTransferHandle(LPWININETFILE lpwh
)
2491 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) lpwh
->hdr
.lpwhparent
;
2496 if (!lpwh
->session_deleted
)
2497 lpwfs
->download_in_progress
= NULL
;
2499 /* This just serves to flush the control socket of any spurrious lines written
2500 to it (like '226 Transfer complete.').
2502 Wonder what to do if the server sends us an error code though...
2504 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2505 MAX_REPLY_LEN
, 0, 0, 0);
2507 if (lpwh
->nDataSocket
!= -1)
2508 close(lpwh
->nDataSocket
);
2510 HeapFree(GetProcessHeap(), 0, lpwh
);
2515 /***********************************************************************
2516 * FTP_ReceiveFileList (internal)
2518 * Read file list from server
2521 * Handle to file list on success
2525 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
2526 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
)
2529 LPFILEPROPERTIESA lpafp
= NULL
;
2530 LPWININETFINDNEXTA lpwfn
= NULL
;
2531 HINTERNET handle
= 0;
2535 if (FTP_ParseDirectory(lpwfs
, nSocket
, &lpafp
, &dwSize
))
2537 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2539 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFINDNEXTA
));
2542 handle
= WININET_AllocHandle( &lpwfn
->hdr
);
2545 lpwfn
->hdr
.htype
= WH_HFINDNEXT
;
2546 lpwfn
->hdr
.lpwhparent
= &lpwfs
->hdr
;
2547 lpwfn
->hdr
.dwContext
= dwContext
;
2548 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2549 lpwfn
->size
= dwSize
;
2550 lpwfn
->lpafp
= lpafp
;
2553 HeapFree( GetProcessHeap(), 0, lpwfn
);
2557 TRACE("Matched %ld files\n", dwSize
);
2562 /***********************************************************************
2563 * FTP_ConvertFileProp (internal)
2565 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2572 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp
, LPWIN32_FIND_DATAA lpFindFileData
)
2574 BOOL bSuccess
= FALSE
;
2576 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2580 /* Convert 'Unix' time to Windows time */
2581 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
2582 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
2584 /* Not all fields are filled in */
2585 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2586 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
2588 if (lpafp
->bIsDirectory
)
2589 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2591 if (lpafp
->lpszName
)
2592 strncpy(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2601 /***********************************************************************
2602 * FTP_ParseDirectory (internal)
2604 * Parse string of directory information
2610 * FIXME: - This function needs serious clea-up
2611 * - We should consider both UNIX and NT list formats
2613 #define MAX_MONTH_LEN 10
2614 #define MIN_LEN_DIR_ENTRY 15
2616 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
)
2619 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2622 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2628 CHAR pszMonth
[MAX_MONTH_LEN
];
2630 BOOL bSuccess
= TRUE
;
2631 DWORD nBufLen
= MAX_REPLY_LEN
;
2632 LPFILEPROPERTIESA curFileProp
= NULL
;
2633 CHAR
* pszLine
= NULL
;
2634 CHAR
* pszToken
= NULL
;
2635 INT nTokenToSkip
= 3;
2643 INT sizeFilePropArray
= 20;
2644 INT indexFilePropArray
= 0;
2648 /* Allocate intial file properties array */
2649 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESA
)*(sizeFilePropArray
));
2656 while ((pszLine
= INTERNET_GetNextLine(nSocket
, INTERNET_GetResponseBuffer(), &nBufLen
)) != NULL
)
2658 if (sizeFilePropArray
<= indexFilePropArray
)
2660 LPFILEPROPERTIESA tmpafp
;
2662 sizeFilePropArray
*= 2;
2663 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
2664 sizeof(FILEPROPERTIESA
)*sizeFilePropArray
);
2674 curFileProp
= &((*lpafp
)[indexFilePropArray
]);
2676 /* First Parse the permissions. */
2677 pszToken
= strtok(pszLine
, " \t" );
2679 /* HACK! If this is not a file listing skip the line */
2680 if (!pszToken
|| nBufLen
<= MIN_LEN_DIR_ENTRY
)
2682 nBufLen
= MAX_REPLY_LEN
;
2685 if (10 == strlen(pszToken
)) {
2686 /* Unix way of parsing ... */
2687 FTP_ParsePermission(pszToken
, curFileProp
);
2692 pszToken
= strtok( NULL
, " \t" );
2694 } while( nCount
<= nTokenToSkip
);
2696 /* Store the size of the file in the param list. */
2697 TRACE("nSize-> %s\n", pszToken
);
2698 if (pszToken
!= NULL
)
2699 curFileProp
->nSize
= atol(pszToken
);
2701 /* Parse last modified time. */
2709 pszToken
= strtok( NULL
, " \t" );
2710 strncpy(pszMonth
, pszToken
, MAX_MONTH_LEN
);
2711 CharUpperA(pszMonth
);
2712 pszMatch
= strstr(szMonths
, pszMonth
);
2713 if( pszMatch
!= NULL
)
2714 nMonth
= (pszMatch
- szMonths
) / 3;
2716 pszToken
= strtok(NULL
, " \t");
2717 TRACE("nDay -> %s\n", pszToken
);
2718 if (pszToken
!= NULL
)
2719 nDay
= atoi(pszToken
);
2721 pszToken
= strtok(NULL
, " \t");
2722 pszMinutes
= strchr(pszToken
, ':');
2723 if( pszMinutes
!= NULL
) {
2725 nMinutes
= atoi(pszMinutes
);
2726 pszHour
= pszMinutes
- 3;
2727 if (pszHour
!= NULL
)
2728 nHour
= atoi(pszHour
);
2730 apTM
= localtime( &aTime
);
2731 nYear
= apTM
->tm_year
;
2733 nYear
= atoi(pszToken
);
2738 curFileProp
->tmLastModified
.tm_sec
= nSeconds
;
2739 curFileProp
->tmLastModified
.tm_min
= nMinutes
;
2740 curFileProp
->tmLastModified
.tm_hour
= nHour
;
2741 curFileProp
->tmLastModified
.tm_mday
= nDay
;
2742 curFileProp
->tmLastModified
.tm_mon
= nMonth
;
2743 curFileProp
->tmLastModified
.tm_year
= nYear
;
2745 pszToken
= strtok(NULL
, " \t");
2746 if(pszToken
!= NULL
) {
2747 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2748 TRACE(": %s\n", curFileProp
->lpszName
);
2751 nBufLen
= MAX_REPLY_LEN
;
2752 indexFilePropArray
++;
2753 } else if (8 == strlen(pszToken
)) {
2754 /* NT way of parsing ... :
2756 07-13-03 08:55PM <DIR> sakpatch
2757 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2760 curFileProp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
2762 sscanf(pszToken
, "%d-%d-%d",
2763 &curFileProp
->tmLastModified
.tm_mon
,
2764 &curFileProp
->tmLastModified
.tm_mday
,
2765 &curFileProp
->tmLastModified
.tm_year
);
2767 /* Hacky and bad Y2K protection :-) */
2768 if (curFileProp
->tmLastModified
.tm_year
< 70)
2769 curFileProp
->tmLastModified
.tm_year
+= 100;
2771 pszToken
= strtok(NULL
, " \t");
2772 if (pszToken
== NULL
) {
2773 nBufLen
= MAX_REPLY_LEN
;
2776 sscanf(pszToken
, "%d:%d",
2777 &curFileProp
->tmLastModified
.tm_hour
,
2778 &curFileProp
->tmLastModified
.tm_min
);
2779 if ((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
2780 curFileProp
->tmLastModified
.tm_hour
+= 12;
2782 curFileProp
->tmLastModified
.tm_sec
= 0;
2784 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2785 curFileProp
->tmLastModified
.tm_hour
, curFileProp
->tmLastModified
.tm_min
, curFileProp
->tmLastModified
.tm_sec
,
2786 (curFileProp
->tmLastModified
.tm_year
>= 100) ? curFileProp
->tmLastModified
.tm_year
- 100 : curFileProp
->tmLastModified
.tm_year
,
2787 curFileProp
->tmLastModified
.tm_mon
, curFileProp
->tmLastModified
.tm_mday
);
2789 pszToken
= strtok(NULL
, " \t");
2790 if (pszToken
== NULL
) {
2791 nBufLen
= MAX_REPLY_LEN
;
2794 if (!strcasecmp(pszToken
, "<DIR>")) {
2795 curFileProp
->bIsDirectory
= TRUE
;
2796 TRACE("Is directory\n");
2798 curFileProp
->bIsDirectory
= FALSE
;
2799 curFileProp
->nSize
= atol(pszToken
);
2800 TRACE("nSize: %ld\n", curFileProp
->nSize
);
2803 pszToken
= strtok(NULL
, " \t");
2804 if (pszToken
== NULL
) {
2805 nBufLen
= MAX_REPLY_LEN
;
2808 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2809 TRACE("Name: %s\n", curFileProp
->lpszName
);
2811 nBufLen
= MAX_REPLY_LEN
;
2812 indexFilePropArray
++;
2814 nBufLen
= MAX_REPLY_LEN
;
2818 if (bSuccess
&& indexFilePropArray
)
2820 if (indexFilePropArray
< sizeFilePropArray
- 1)
2822 LPFILEPROPERTIESA tmpafp
;
2824 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
2825 sizeof(FILEPROPERTIESA
)*indexFilePropArray
);
2829 *dwfp
= indexFilePropArray
;
2833 HeapFree(GetProcessHeap(), 0, *lpafp
);
2834 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2843 /***********************************************************************
2844 * FTP_ParsePermission (internal)
2846 * Parse permission string of directory information
2853 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
)
2855 BOOL bSuccess
= TRUE
;
2856 unsigned short nPermission
= 0;
2861 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
2867 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
2873 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
2876 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
2879 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
2882 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
2885 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
2888 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
2891 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
2894 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
2897 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
2901 }while (nPos
<= nLast
);
2903 lpfp
->permissions
= nPermission
;
2908 /***********************************************************************
2909 * FTP_SetResponseError (internal)
2911 * Set the appropriate error code for a given response from the server
2916 DWORD
FTP_SetResponseError(DWORD dwResponse
)
2922 case 421: /* Service not available - Server may be shutting down. */
2923 dwCode
= ERROR_INTERNET_TIMEOUT
;
2926 case 425: /* Cannot open data connection. */
2927 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
2930 case 426: /* Connection closed, transer aborted. */
2931 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
2934 case 500: /* Syntax error. Command unrecognized. */
2935 case 501: /* Syntax error. Error in parameters or arguments. */
2936 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
2939 case 530: /* Not logged in. Login incorrect. */
2940 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
2943 case 550: /* File action not taken. File not found or no access. */
2944 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
2947 case 450: /* File action not taken. File may be busy. */
2948 case 451: /* Action aborted. Server error. */
2949 case 452: /* Action not taken. Insufficient storage space on server. */
2950 case 502: /* Command not implemented. */
2951 case 503: /* Bad sequence of command. */
2952 case 504: /* Command not implemented for that parameter. */
2953 case 532: /* Need account for storing files */
2954 case 551: /* Requested action aborted. Page type unknown */
2955 case 552: /* Action aborted. Exceeded storage allocation */
2956 case 553: /* Action not taken. File name not allowed. */
2959 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
2963 INTERNET_SetLastError(dwCode
);