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
;
173 workRequest
.asyncall
= FTPPUTFILEA
;
174 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
175 workRequest
.LPSZLOCALFILE
= (DWORD
)FTP_strdup(lpszLocalFile
);
176 workRequest
.LPSZNEWREMOTEFILE
= (DWORD
)FTP_strdup(lpszNewRemoteFile
);
177 workRequest
.DWFLAGS
= dwFlags
;
178 workRequest
.DWCONTEXT
= dwContext
;
180 return INTERNET_AsyncCall(&workRequest
);
184 return FTP_FtpPutFileA(hConnect
, lpszLocalFile
,
185 lpszNewRemoteFile
, dwFlags
, dwContext
);
189 /***********************************************************************
190 * FTP_FtpPutFileA (Internal)
192 * Uploads a file to the FTP server
199 BOOL WINAPI
FTP_FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
200 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
203 BOOL bSuccess
= FALSE
;
204 LPWININETAPPINFOA hIC
= NULL
;
205 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
208 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile
, lpszNewRemoteFile
);
209 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
211 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
215 /* Clear any error information */
216 INTERNET_SetLastError(0);
218 /* Open file to be uploaded */
219 if (INVALID_HANDLE_VALUE
==
220 (hFile
= CreateFileA(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
222 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND
);
226 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
227 if (hIC
->lpfnStatusCB
)
228 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
230 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
234 /* Get data socket to server */
235 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
237 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
239 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
240 MAX_REPLY_LEN
, 0, 0, 0);
246 FTP_SetResponseError(nResCode
);
252 if (lpwfs
->lstnSocket
!= -1)
253 close(lpwfs
->lstnSocket
);
255 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
257 INTERNET_ASYNC_RESULT iar
;
259 iar
.dwResult
= (DWORD
)bSuccess
;
260 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
261 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
262 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
272 /***********************************************************************
273 * FtpSetCurrentDirectoryA (WININET.@)
275 * Change the working directory on the FTP server
282 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
284 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
285 LPWININETAPPINFOA hIC
= NULL
;
287 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
289 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
293 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
295 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
296 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
298 WORKREQUEST workRequest
;
300 workRequest
.asyncall
= FTPSETCURRENTDIRECTORYA
;
301 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
302 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
304 return INTERNET_AsyncCall(&workRequest
);
308 return FTP_FtpSetCurrentDirectoryA(hConnect
, lpszDirectory
);
313 /***********************************************************************
314 * FtpSetCurrentDirectoryW (WININET.@)
316 * Change the working directory on the FTP server
323 BOOL WINAPI
FtpSetCurrentDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
329 len
= lstrlenW(lpszDirectory
)+1;
330 if (!(szDir
= (CHAR
*)malloc(len
*sizeof(CHAR
))))
332 WideCharToMultiByte(CP_ACP
, -1, lpszDirectory
, -1, szDir
, len
, NULL
, NULL
);
333 rc
= FtpSetCurrentDirectoryA(hConnect
, szDir
);
340 /***********************************************************************
341 * FTP_FtpSetCurrentDirectoryA (Internal)
343 * Change the working directory on the FTP server
350 BOOL WINAPI
FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
353 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
354 LPWININETAPPINFOA hIC
= NULL
;
355 DWORD bSuccess
= FALSE
;
357 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
359 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
361 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
365 /* Clear any error information */
366 INTERNET_SetLastError(0);
368 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
369 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
370 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
373 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
374 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
381 FTP_SetResponseError(nResCode
);
385 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
387 INTERNET_ASYNC_RESULT iar
;
389 iar
.dwResult
= (DWORD
)bSuccess
;
390 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
391 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
392 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
398 /***********************************************************************
399 * FtpCreateDirectoryA (WININET.@)
401 * Create new directory on the FTP server
408 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
410 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
411 LPWININETAPPINFOA hIC
= NULL
;
413 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
415 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
419 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
420 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
422 WORKREQUEST workRequest
;
424 workRequest
.asyncall
= FTPCREATEDIRECTORYA
;
425 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
426 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
428 return INTERNET_AsyncCall(&workRequest
);
432 return FTP_FtpCreateDirectoryA(hConnect
, lpszDirectory
);
437 /***********************************************************************
438 * FtpCreateDirectoryW (WININET.@)
440 * Create new directory on the FTP server
447 BOOL WINAPI
FtpCreateDirectoryW(HINTERNET hConnect
, LPCWSTR lpszDirectory
)
453 len
= lstrlenW(lpszDirectory
)+1;
454 if (!(szDir
= (CHAR
*)malloc(len
*sizeof(CHAR
))))
456 WideCharToMultiByte(CP_ACP
, -1, lpszDirectory
, -1, szDir
, len
, NULL
, NULL
);
457 rc
= FtpCreateDirectoryA(hConnect
, szDir
);
464 /***********************************************************************
465 * FTP_FtpCreateDirectoryA (Internal)
467 * Create new directory on the FTP server
474 BOOL WINAPI
FTP_FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
477 BOOL bSuccess
= FALSE
;
478 LPWININETAPPINFOA hIC
= NULL
;
479 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
482 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
484 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
488 /* Clear any error information */
489 INTERNET_SetLastError(0);
491 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
494 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
495 MAX_REPLY_LEN
, 0, 0, 0);
501 FTP_SetResponseError(nResCode
);
505 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
506 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
508 INTERNET_ASYNC_RESULT iar
;
510 iar
.dwResult
= (DWORD
)bSuccess
;
511 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
512 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
513 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
520 /***********************************************************************
521 * FtpFindFirstFileA (WININET.@)
523 * Search the specified directory
526 * HINTERNET on success
530 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
531 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
533 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
534 LPWININETAPPINFOA hIC
= NULL
;
536 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
538 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
542 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
543 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
545 WORKREQUEST workRequest
;
547 workRequest
.asyncall
= FTPFINDFIRSTFILEA
;
548 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
549 workRequest
.LPSZSEARCHFILE
= (DWORD
)FTP_strdup(lpszSearchFile
);
550 workRequest
.LPFINDFILEDATA
= (DWORD
)lpFindFileData
;
551 workRequest
.DWFLAGS
= dwFlags
;
552 workRequest
.DWCONTEXT
= dwContext
;
554 INTERNET_AsyncCall(&workRequest
);
559 return FTP_FtpFindFirstFileA(hConnect
, lpszSearchFile
, lpFindFileData
,
565 /***********************************************************************
566 * FtpFindFirstFileA (WININET.@)
568 * Search the specified directory
571 * HINTERNET on success
575 HINTERNET WINAPI
FtpFindFirstFileW(HINTERNET hConnect
,
576 LPCWSTR lpszSearchFile
, LPWIN32_FIND_DATAW lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
583 /***********************************************************************
584 * FTP_FtpFindFirstFileA (Internal)
586 * Search the specified directory
589 * HINTERNET on success
593 HINTERNET WINAPI
FTP_FtpFindFirstFileA(HINTERNET hConnect
,
594 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
597 LPWININETAPPINFOA hIC
= NULL
;
598 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
599 LPWININETFINDNEXTA hFindNext
= NULL
;
603 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
605 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
609 /* Clear any error information */
610 INTERNET_SetLastError(0);
612 if (!FTP_InitListenSocket(lpwfs
))
615 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
618 if (!FTP_SendPortOrPasv(lpwfs
))
621 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
622 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, lpszSearchFile
,
623 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
626 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
627 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
630 if (nResCode
== 125 || nResCode
== 150)
634 /* Get data socket to server */
635 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
637 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpFindFileData
, dwContext
);
639 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
640 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
641 if (nResCode
!= 226 && nResCode
!= 250)
642 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
648 FTP_SetResponseError(nResCode
);
652 if (lpwfs
->lstnSocket
!= -1)
653 close(lpwfs
->lstnSocket
);
655 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
657 INTERNET_ASYNC_RESULT iar
;
661 iar
.dwResult
= (DWORD
)hFindNext
;
662 iar
.dwError
= ERROR_SUCCESS
;
663 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
664 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
667 iar
.dwResult
= (DWORD
)hFindNext
;
668 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
669 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
670 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
673 return (HINTERNET
)hFindNext
;
677 /***********************************************************************
678 * FtpGetCurrentDirectoryA (WININET.@)
680 * Retrieves the current directory
687 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
688 LPDWORD lpdwCurrentDirectory
)
690 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
691 LPWININETAPPINFOA hIC
= NULL
;
693 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
695 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
697 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
701 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
702 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
704 WORKREQUEST workRequest
;
706 workRequest
.asyncall
= FTPGETCURRENTDIRECTORYA
;
707 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
708 workRequest
.LPSZDIRECTORY
= (DWORD
)lpszCurrentDirectory
;
709 workRequest
.LPDWDIRECTORY
= (DWORD
)lpdwCurrentDirectory
;
711 return INTERNET_AsyncCall(&workRequest
);
715 return FTP_FtpGetCurrentDirectoryA(hFtpSession
, lpszCurrentDirectory
,
716 lpdwCurrentDirectory
);
721 /***********************************************************************
722 * FtpGetCurrentDirectoryW (WININET.@)
724 * Retrieves the current directory
731 BOOL WINAPI
FtpGetCurrentDirectoryW(HINTERNET hFtpSession
, LPWSTR lpszCurrentDirectory
,
732 LPDWORD lpdwCurrentDirectory
)
739 /***********************************************************************
740 * FTP_FtpGetCurrentDirectoryA (Internal)
742 * Retrieves the current directory
749 BOOL WINAPI
FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
750 LPDWORD lpdwCurrentDirectory
)
753 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
754 LPWININETAPPINFOA hIC
= NULL
;
755 DWORD bSuccess
= FALSE
;
757 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
759 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
761 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
765 /* Clear any error information */
766 INTERNET_SetLastError(0);
768 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
770 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
771 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
772 hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
))
775 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
776 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
);
779 if (nResCode
== 257) /* Extract directory name */
781 INT firstpos
, lastpos
, len
;
782 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
784 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
786 if ('"' == lpszResponseBuffer
[lastpos
])
795 len
= lastpos
- firstpos
- 1;
796 strncpy(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1],
797 len
< *lpdwCurrentDirectory
? len
: *lpdwCurrentDirectory
);
798 *lpdwCurrentDirectory
= len
;
802 FTP_SetResponseError(nResCode
);
806 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
808 INTERNET_ASYNC_RESULT iar
;
810 iar
.dwResult
= (DWORD
)bSuccess
;
811 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
812 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
813 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
816 return (DWORD
) bSuccess
;
819 /***********************************************************************
820 * FtpOpenFileA (WININET.@)
822 * Open a remote file for writing or reading
825 * HINTERNET handle on success
829 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
830 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
833 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
834 LPWININETAPPINFOA hIC
= NULL
;
836 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
838 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
842 if (lpwfs
->download_in_progress
!= NULL
) {
843 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
847 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
848 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
850 WORKREQUEST workRequest
;
852 workRequest
.asyncall
= FTPOPENFILEA
;
853 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
854 workRequest
.LPSZFILENAME
= (DWORD
)FTP_strdup(lpszFileName
);
855 workRequest
.FDWACCESS
= fdwAccess
;
856 workRequest
.DWFLAGS
= dwFlags
;
857 workRequest
.DWCONTEXT
= dwContext
;
859 INTERNET_AsyncCall(&workRequest
);
864 return FTP_FtpOpenFileA(hFtpSession
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
869 /***********************************************************************
870 * FtpOpenFileW (WININET.@)
872 * Open a remote file for writing or reading
875 * HINTERNET handle on success
879 HINTERNET WINAPI
FtpOpenFileW(HINTERNET hFtpSession
,
880 LPCWSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
888 /***********************************************************************
889 * FTP_FtpOpenFileA (Internal)
891 * Open a remote file for writing or reading
894 * HINTERNET handle on success
898 HINTERNET
FTP_FtpOpenFileA(HINTERNET hFtpSession
,
899 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
903 BOOL bSuccess
= FALSE
;
904 LPWININETFILE hFile
= NULL
;
905 LPWININETAPPINFOA hIC
= NULL
;
906 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
910 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
912 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
916 /* Clear any error information */
917 INTERNET_SetLastError(0);
919 if (GENERIC_READ
== fdwAccess
)
921 /* Set up socket to retrieve data */
922 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
924 else if (GENERIC_WRITE
== fdwAccess
)
926 /* Set up socket to send data */
927 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
930 /* Get data socket to server */
931 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
933 hFile
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE
));
934 hFile
->hdr
.htype
= WH_HFILE
;
935 hFile
->hdr
.dwFlags
= dwFlags
;
936 hFile
->hdr
.dwContext
= dwContext
;
937 hFile
->hdr
.lpwhparent
= hFtpSession
;
938 hFile
->nDataSocket
= nDataSocket
;
939 hFile
->session_deleted
= FALSE
;
941 /* Indicate that a download is currently in progress */
942 lpwfs
->download_in_progress
= hFile
;
945 if (lpwfs
->lstnSocket
!= -1)
946 close(lpwfs
->lstnSocket
);
948 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
949 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
951 INTERNET_ASYNC_RESULT iar
;
955 iar
.dwResult
= (DWORD
)hFile
;
956 iar
.dwError
= ERROR_SUCCESS
;
957 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
958 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
961 iar
.dwResult
= (DWORD
)bSuccess
;
962 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
963 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
964 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
967 return (HINTERNET
)hFile
;
971 /***********************************************************************
972 * FtpGetFileA (WININET.@)
974 * Retrieve file from the FTP server
981 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
982 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
985 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hInternet
;
986 LPWININETAPPINFOA hIC
= NULL
;
988 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
990 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
994 if (lpwfs
->download_in_progress
!= NULL
) {
995 INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS
);
999 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1000 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1002 WORKREQUEST workRequest
;
1004 workRequest
.asyncall
= FTPGETFILEA
;
1005 workRequest
.HFTPSESSION
= (DWORD
)hInternet
;
1006 workRequest
.LPSZREMOTEFILE
= (DWORD
)FTP_strdup(lpszRemoteFile
);
1007 workRequest
.LPSZNEWFILE
= (DWORD
)FTP_strdup(lpszNewFile
);
1008 workRequest
.DWLOCALFLAGSATTRIBUTE
= dwLocalFlagsAttribute
;
1009 workRequest
.FFAILIFEXISTS
= (DWORD
)fFailIfExists
;
1010 workRequest
.DWFLAGS
= dwInternetFlags
;
1011 workRequest
.DWCONTEXT
= dwContext
;
1013 return INTERNET_AsyncCall(&workRequest
);
1017 return FTP_FtpGetFileA(hInternet
, lpszRemoteFile
, lpszNewFile
,
1018 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
1023 /***********************************************************************
1024 * FtpGetFileW (WININET.@)
1026 * Retrieve file from the FTP server
1033 BOOL WINAPI
FtpGetFileW(HINTERNET hInternet
, LPCWSTR lpszRemoteFile
, LPCWSTR lpszNewFile
,
1034 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1042 /***********************************************************************
1043 * FTP_FtpGetFileA (Internal)
1045 * Retrieve file from the FTP server
1052 BOOL WINAPI
FTP_FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
1053 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
1057 BOOL bSuccess
= FALSE
;
1059 LPWININETAPPINFOA hIC
= NULL
;
1060 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hInternet
;
1062 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile
, lpszNewFile
);
1063 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1065 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1069 /* Clear any error information */
1070 INTERNET_SetLastError(0);
1072 /* Ensure we can write to lpszNewfile by opening it */
1073 hFile
= CreateFileA(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
1074 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
1075 if (INVALID_HANDLE_VALUE
== hFile
)
1078 /* Set up socket to retrieve data */
1079 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
1085 /* Get data socket to server */
1086 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
1091 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
1092 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1093 MAX_REPLY_LEN
, 0, 0, 0);
1096 if (nResCode
== 226)
1099 FTP_SetResponseError(nResCode
);
1106 if (lpwfs
->lstnSocket
!= -1)
1107 close(lpwfs
->lstnSocket
);
1112 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1113 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1115 INTERNET_ASYNC_RESULT iar
;
1117 iar
.dwResult
= (DWORD
)bSuccess
;
1118 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1119 hIC
->lpfnStatusCB(hInternet
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1120 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1127 /***********************************************************************
1128 * FtpDeleteFileA (WININET.@)
1130 * Delete a file on the ftp server
1137 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1139 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1140 LPWININETAPPINFOA hIC
= NULL
;
1142 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1144 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1148 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1149 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1151 WORKREQUEST workRequest
;
1153 workRequest
.asyncall
= FTPRENAMEFILEA
;
1154 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1155 workRequest
.LPSZFILENAME
= (DWORD
)FTP_strdup(lpszFileName
);
1157 return INTERNET_AsyncCall(&workRequest
);
1161 return FTP_FtpDeleteFileA(hFtpSession
, lpszFileName
);
1166 /***********************************************************************
1167 * FTP_FtpDeleteFileA (Internal)
1169 * Delete a file on the ftp server
1176 BOOL
FTP_FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1179 BOOL bSuccess
= FALSE
;
1180 LPWININETAPPINFOA hIC
= NULL
;
1181 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1183 TRACE("0x%08lx\n", (ULONG
) hFtpSession
);
1184 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1186 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1190 /* Clear any error information */
1191 INTERNET_SetLastError(0);
1193 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1196 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1197 MAX_REPLY_LEN
, 0, 0, 0);
1200 if (nResCode
== 250)
1203 FTP_SetResponseError(nResCode
);
1206 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1207 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1209 INTERNET_ASYNC_RESULT iar
;
1211 iar
.dwResult
= (DWORD
)bSuccess
;
1212 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1213 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1214 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1221 /***********************************************************************
1222 * FtpRemoveDirectoryA (WININET.@)
1224 * Remove a directory on the ftp server
1231 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1233 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1234 LPWININETAPPINFOA hIC
= NULL
;
1236 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1238 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1242 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1243 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1245 WORKREQUEST workRequest
;
1247 workRequest
.asyncall
= FTPREMOVEDIRECTORYA
;
1248 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1249 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
1251 return INTERNET_AsyncCall(&workRequest
);
1255 return FTP_FtpRemoveDirectoryA(hFtpSession
, lpszDirectory
);
1260 /***********************************************************************
1261 * FTP_FtpRemoveDirectoryA (Internal)
1263 * Remove a directory on the ftp server
1270 BOOL
FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1273 BOOL bSuccess
= FALSE
;
1274 LPWININETAPPINFOA hIC
= NULL
;
1275 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1278 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1280 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1284 /* Clear any error information */
1285 INTERNET_SetLastError(0);
1287 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1290 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1291 MAX_REPLY_LEN
, 0, 0, 0);
1294 if (nResCode
== 250)
1297 FTP_SetResponseError(nResCode
);
1301 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1302 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1304 INTERNET_ASYNC_RESULT iar
;
1306 iar
.dwResult
= (DWORD
)bSuccess
;
1307 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1308 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1309 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1316 /***********************************************************************
1317 * FtpRenameFileA (WININET.@)
1319 * Rename a file on the ftp server
1326 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1328 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1329 LPWININETAPPINFOA hIC
= NULL
;
1331 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1333 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1337 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1338 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1340 WORKREQUEST workRequest
;
1342 workRequest
.asyncall
= FTPRENAMEFILEA
;
1343 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1344 workRequest
.LPSZSRCFILE
= (DWORD
)FTP_strdup(lpszSrc
);
1345 workRequest
.LPSZDESTFILE
= (DWORD
)FTP_strdup(lpszDest
);
1347 return INTERNET_AsyncCall(&workRequest
);
1351 return FTP_FtpRenameFileA(hFtpSession
, lpszSrc
, lpszDest
);
1355 /***********************************************************************
1356 * FTP_FtpRenameFileA (Internal)
1358 * Rename a file on the ftp server
1365 BOOL
FTP_FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1368 BOOL bSuccess
= FALSE
;
1369 LPWININETAPPINFOA hIC
= NULL
;
1370 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1373 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1375 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1379 /* Clear any error information */
1380 INTERNET_SetLastError(0);
1382 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1385 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1386 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1387 if (nResCode
== 350)
1389 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1392 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1393 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1396 if (nResCode
== 250)
1399 FTP_SetResponseError(nResCode
);
1402 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1403 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1405 INTERNET_ASYNC_RESULT iar
;
1407 iar
.dwResult
= (DWORD
)bSuccess
;
1408 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1409 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1410 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1417 /***********************************************************************
1418 * FTP_Connect (internal)
1420 * Connect to a ftp server
1423 * HINTERNET a session handle on success
1428 HINTERNET
FTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
1429 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
1430 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
1432 struct sockaddr_in socketAddr
;
1433 struct hostent
*phe
= NULL
;
1434 INT nsocket
= -1, sock_namelen
;
1435 LPWININETAPPINFOA hIC
= NULL
;
1436 BOOL bSuccess
= FALSE
;
1437 LPWININETFTPSESSIONA lpwfs
= NULL
;
1439 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1440 (ULONG
) hInternet
, lpszServerName
,
1441 nServerPort
, lpszUserName
, lpszPassword
);
1443 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
1446 hIC
= (LPWININETAPPINFOA
) hInternet
;
1448 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1450 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME
);
1454 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1455 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1457 if (hIC
->lpfnStatusCB
)
1458 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1459 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1461 if (!GetAddress(lpszServerName
, nServerPort
, &phe
, &socketAddr
))
1463 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1467 if (hIC
->lpfnStatusCB
)
1468 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1469 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1471 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1474 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1478 if (hIC
->lpfnStatusCB
)
1479 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1480 &socketAddr
, sizeof(struct sockaddr_in
));
1482 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1484 ERR("Unable to connect (%s)\n", strerror(errno
));
1485 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1489 TRACE("Connected to server\n");
1490 if (hIC
->lpfnStatusCB
)
1491 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1492 &socketAddr
, sizeof(struct sockaddr_in
));
1494 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA
));
1497 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1501 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1502 lpwfs
->hdr
.dwFlags
= dwFlags
;
1503 lpwfs
->hdr
.dwContext
= dwContext
;
1504 lpwfs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
1505 lpwfs
->sndSocket
= nsocket
;
1506 lpwfs
->download_in_progress
= NULL
;
1507 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1508 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1509 lpwfs
->phostent
= phe
;
1511 if (NULL
== lpszUserName
)
1513 lpwfs
->lpszUserName
= FTP_strdup("anonymous");
1514 lpwfs
->lpszPassword
= FTP_strdup("user@server");
1518 lpwfs
->lpszUserName
= FTP_strdup(lpszUserName
);
1519 lpwfs
->lpszPassword
= FTP_strdup(lpszPassword
);
1522 if (FTP_ConnectToHost(lpwfs
))
1524 if (hIC
->lpfnStatusCB
)
1526 INTERNET_ASYNC_RESULT iar
;
1528 iar
.dwResult
= (DWORD
)lpwfs
;
1529 iar
.dwError
= ERROR_SUCCESS
;
1531 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1532 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1534 TRACE("Successfully logged into server\n");
1540 if (!bSuccess
&& nsocket
== -1)
1543 if (!bSuccess
&& lpwfs
)
1545 HeapFree(GetProcessHeap(), 0, lpwfs
);
1549 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1551 INTERNET_ASYNC_RESULT iar
;
1553 iar
.dwResult
= (DWORD
)lpwfs
;
1554 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1555 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1556 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1559 return (HINTERNET
) lpwfs
;
1563 /***********************************************************************
1564 * FTP_ConnectToHost (internal)
1566 * Connect to a ftp server
1573 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
)
1576 BOOL bSuccess
= FALSE
;
1579 FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1581 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1584 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1585 MAX_REPLY_LEN
, 0, 0, 0);
1588 /* Login successful... */
1589 if (nResCode
== 230)
1591 /* User name okay, need password... */
1592 else if (nResCode
== 331)
1593 bSuccess
= FTP_SendPassword(lpwfs
);
1594 /* Need account for login... */
1595 else if (nResCode
== 332)
1596 bSuccess
= FTP_SendAccount(lpwfs
);
1598 FTP_SetResponseError(nResCode
);
1601 TRACE("Returning %d\n", bSuccess
);
1607 /***********************************************************************
1608 * FTP_SendCommand (internal)
1610 * Send command to server
1617 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
1618 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1622 DWORD nBytesSent
= 0;
1626 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
1629 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1631 bParamHasLen
= lpszParam
&& strlen(lpszParam
) > 0;
1632 len
= (bParamHasLen
? strlen(lpszParam
) : -1) + strlen(szFtpCommands
[ftpCmd
]) +
1634 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1636 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1639 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], bParamHasLen
? " " : "",
1640 bParamHasLen
? lpszParam
: "", szCRLF
);
1642 TRACE("Sending (%s) len(%ld)\n", buf
, len
);
1643 while((nBytesSent
< len
) && (nRC
!= -1))
1645 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1649 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1652 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1653 &nBytesSent
, sizeof(DWORD
));
1655 TRACE("Sent %ld bytes\n", nBytesSent
);
1660 /***********************************************************************
1661 * FTP_ReceiveResponse (internal)
1663 * Receive response from server
1666 * Reply code on success
1671 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
1672 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1676 char firstprefix
[5];
1677 BOOL multiline
= FALSE
;
1680 TRACE("socket(%d) \n", nSocket
);
1683 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
1688 if (!INTERNET_GetNextLine(nSocket
, lpszResponse
, &nRecv
))
1695 if(lpszResponse
[3] != '-')
1698 { /* Start of multiline repsonse. Loop until we get "nnn " */
1700 memcpy(firstprefix
, lpszResponse
, 3);
1701 firstprefix
[3] = ' ';
1702 firstprefix
[4] = '\0';
1707 if(!memcmp(firstprefix
, lpszResponse
, 4))
1715 rc
= atoi(lpszResponse
);
1718 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
1719 &nRecv
, sizeof(DWORD
));
1723 TRACE("return %d\n", rc
);
1728 /***********************************************************************
1729 * FTP_SendPassword (internal)
1731 * Send password to ftp server
1738 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
)
1741 BOOL bSuccess
= FALSE
;
1744 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
1747 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1748 MAX_REPLY_LEN
, 0, 0, 0);
1751 TRACE("Received reply code %d\n", nResCode
);
1752 /* Login successful... */
1753 if (nResCode
== 230)
1755 /* Command not implemented, superfluous at the server site... */
1756 /* Need account for login... */
1757 else if (nResCode
== 332)
1758 bSuccess
= FTP_SendAccount(lpwfs
);
1760 FTP_SetResponseError(nResCode
);
1764 TRACE("Returning %d\n", bSuccess
);
1769 /***********************************************************************
1770 * FTP_SendAccount (internal)
1779 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
)
1782 BOOL bSuccess
= FALSE
;
1785 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, NOACCOUNT
, 0, 0, 0))
1788 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1789 MAX_REPLY_LEN
, 0, 0, 0);
1793 FTP_SetResponseError(nResCode
);
1800 /***********************************************************************
1801 * FTP_SendStore (internal)
1803 * Send request to upload file to ftp server
1810 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
1813 BOOL bSuccess
= FALSE
;
1816 if (!FTP_InitListenSocket(lpwfs
))
1819 if (!FTP_SendType(lpwfs
, dwType
))
1822 if (!FTP_SendPortOrPasv(lpwfs
))
1825 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
1827 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1828 MAX_REPLY_LEN
, 0, 0, 0);
1831 if (nResCode
== 150)
1834 FTP_SetResponseError(nResCode
);
1838 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
1840 close(lpwfs
->lstnSocket
);
1841 lpwfs
->lstnSocket
= -1;
1848 /***********************************************************************
1849 * FTP_InitListenSocket (internal)
1851 * Create a socket to listen for server response
1858 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
)
1860 BOOL bSuccess
= FALSE
;
1861 size_t namelen
= sizeof(struct sockaddr_in
);
1865 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
1866 if (lpwfs
->lstnSocket
== -1)
1868 TRACE("Unable to create listening socket\n");
1872 /* We obtain our ip addr from the name of the command channel socket */
1873 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
1875 /* and get the system to assign us a port */
1876 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
1878 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
1880 TRACE("Unable to bind socket\n");
1884 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
1886 TRACE("listen failed\n");
1890 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
1894 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
1896 close(lpwfs
->lstnSocket
);
1897 lpwfs
->lstnSocket
= -1;
1904 /***********************************************************************
1905 * FTP_SendType (internal)
1907 * Tell server type of data being transferred
1913 * W98SE doesn't cache the type that's currently set
1914 * (i.e. it sends it always),
1915 * so we probably don't want to do that either.
1917 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
)
1920 CHAR type
[2] = { "I" };
1921 BOOL bSuccess
= FALSE
;
1924 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
1927 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
1930 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1931 MAX_REPLY_LEN
, 0, 0, 0)/100;
1937 FTP_SetResponseError(nResCode
);
1944 /***********************************************************************
1945 * FTP_GetFileSize (internal)
1947 * Retrieves from the server the size of the given file
1954 BOOL
FTP_GetFileSize(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD
*dwSize
)
1957 BOOL bSuccess
= FALSE
;
1961 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_SIZE
, lpszRemoteFile
, 0, 0, 0))
1964 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1965 MAX_REPLY_LEN
, 0, 0, 0);
1968 if (nResCode
== 213) {
1969 /* Now parses the output to get the actual file size */
1971 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
1973 for (i
= 0; (lpszResponseBuffer
[i
] != ' ') && (lpszResponseBuffer
[i
] != '\0'); i
++) ;
1974 if (lpszResponseBuffer
[i
] == '\0') return FALSE
;
1975 *dwSize
= atol(&(lpszResponseBuffer
[i
+ 1]));
1979 FTP_SetResponseError(nResCode
);
1988 /***********************************************************************
1989 * FTP_SendPort (internal)
1991 * Tell server which port to use
1998 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
)
2001 CHAR szIPAddress
[64];
2002 BOOL bSuccess
= FALSE
;
2005 sprintf(szIPAddress
, "%d,%d,%d,%d,%d,%d",
2006 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
2007 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
2008 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
2009 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
2010 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
2011 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
2013 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
2016 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2017 MAX_REPLY_LEN
,0, 0, 0);
2020 if (nResCode
== 200)
2023 FTP_SetResponseError(nResCode
);
2031 /***********************************************************************
2032 * FTP_DoPassive (internal)
2034 * Tell server that we want to do passive transfers
2035 * and connect data socket
2042 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
)
2045 BOOL bSuccess
= FALSE
;
2048 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
2051 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2052 MAX_REPLY_LEN
,0, 0, 0);
2055 if (nResCode
== 227)
2057 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2061 char *pAddr
, *pPort
;
2063 struct sockaddr_in dataSocketAddress
;
2065 p
= lpszResponseBuffer
+4; /* skip status code */
2067 /* do a very strict check; we can improve that later. */
2069 if (strncmp(p
, "Entering Passive Mode", 21))
2071 ERR("unknown response '%.*s', aborting\n", 21, p
);
2074 p
+= 21; /* skip string */
2075 if ((*p
++ != ' ') || (*p
++ != '('))
2077 ERR("unknown response format, aborting\n");
2081 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
2084 ERR("unknown response address format '%s', aborting\n", p
);
2087 for (i
=0; i
< 6; i
++)
2090 dataSocketAddress
= lpwfs
->socketAddress
;
2091 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
2092 pPort
= (char *)&(dataSocketAddress
.sin_port
);
2100 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
2104 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
2106 ERR("can't connect passive FTP data port.\n");
2109 lpwfs
->pasvSocket
= nsocket
;
2113 FTP_SetResponseError(nResCode
);
2121 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
)
2123 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2125 if (!FTP_DoPassive(lpwfs
))
2130 if (!FTP_SendPort(lpwfs
))
2137 /***********************************************************************
2138 * FTP_GetDataSocket (internal)
2140 * Either accepts an incoming data socket connection from the server
2141 * or just returns the already opened socket after a PASV command
2142 * in case of passive FTP.
2150 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
)
2152 struct sockaddr_in saddr
;
2153 size_t addrlen
= sizeof(struct sockaddr
);
2156 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
2158 *nDataSocket
= lpwfs
->pasvSocket
;
2162 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
2163 close(lpwfs
->lstnSocket
);
2164 lpwfs
->lstnSocket
= -1;
2166 return *nDataSocket
!= -1;
2170 /***********************************************************************
2171 * FTP_SendData (internal)
2173 * Send data to the server
2180 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
)
2182 BY_HANDLE_FILE_INFORMATION fi
;
2183 DWORD nBytesRead
= 0;
2184 DWORD nBytesSent
= 0;
2185 DWORD nTotalSent
= 0;
2186 DWORD nBytesToSend
, nLen
, nRC
= 1;
2187 time_t s_long_time
, e_long_time
;
2192 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2193 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2195 /* Get the size of the file. */
2196 GetFileInformationByHandle(hFile
, &fi
);
2201 nBytesToSend
= nBytesRead
- nBytesSent
;
2203 if (nBytesToSend
<= 0)
2205 /* Read data from file. */
2207 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2208 ERR("Failed reading from file\n");
2211 nBytesToSend
= nBytesRead
;
2216 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2217 DATA_PACKET_SIZE
: nBytesToSend
;
2218 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2226 /* Do some computation to display the status. */
2228 nSeconds
= e_long_time
- s_long_time
;
2229 if( nSeconds
/ 60 > 0 )
2231 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2232 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2233 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2237 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2238 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2239 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2241 } while (nRC
!= -1);
2243 TRACE("file transfer complete!\n");
2245 if(lpszBuffer
!= NULL
)
2246 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2252 /***********************************************************************
2253 * FTP_SendRetrieve (internal)
2255 * Send request to retrieve a file
2258 * Number of bytes to be received on success
2262 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
2268 if (!FTP_InitListenSocket(lpwfs
))
2271 if (!FTP_SendType(lpwfs
, dwType
))
2274 if (!FTP_SendPortOrPasv(lpwfs
))
2277 if (!FTP_GetFileSize(lpwfs
, lpszRemoteFile
, &nResult
))
2280 TRACE("Waiting to receive %ld bytes\n", nResult
);
2282 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2285 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2286 MAX_REPLY_LEN
, 0, 0, 0);
2287 if ((nResCode
!= 125) && (nResCode
!= 150)) {
2288 /* That means that we got an error getting the file. */
2293 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2295 close(lpwfs
->lstnSocket
);
2296 lpwfs
->lstnSocket
= -1;
2303 /***********************************************************************
2304 * FTP_RetrieveData (internal)
2306 * Retrieve data from server
2313 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2315 DWORD nBytesWritten
;
2316 DWORD nBytesReceived
= 0;
2322 if (INVALID_HANDLE_VALUE
== hFile
)
2325 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2326 if (NULL
== lpszBuffer
)
2328 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2332 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2334 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2337 /* other side closed socket. */
2340 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2341 nBytesReceived
+= nRC
;
2344 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived
, nBytes
,
2345 nBytesReceived
* 100 / nBytes
);
2348 TRACE("Data transfer complete\n");
2349 if (NULL
!= lpszBuffer
)
2350 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2357 /***********************************************************************
2358 * FTP_CloseSessionHandle (internal)
2360 * Deallocate session handle
2367 BOOL
FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs
)
2371 if (lpwfs
->download_in_progress
!= NULL
)
2372 lpwfs
->download_in_progress
->session_deleted
= TRUE
;
2374 if (lpwfs
->sndSocket
!= -1)
2375 close(lpwfs
->sndSocket
);
2377 if (lpwfs
->lstnSocket
!= -1)
2378 close(lpwfs
->lstnSocket
);
2380 if (lpwfs
->lpszPassword
)
2381 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2383 if (lpwfs
->lpszUserName
)
2384 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2386 HeapFree(GetProcessHeap(), 0, lpwfs
);
2392 /***********************************************************************
2393 * FTP_CloseFindNextHandle (internal)
2395 * Deallocate session handle
2402 BOOL
FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn
)
2408 for (i
= 0; i
< lpwfn
->size
; i
++)
2410 if (NULL
!= lpwfn
->lpafp
[i
].lpszName
)
2411 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2414 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2415 HeapFree(GetProcessHeap(), 0, lpwfn
);
2420 /***********************************************************************
2421 * FTP_CloseFileTransferHandle (internal)
2423 * Closes the file transfer handle. This also 'cleans' the data queue of
2424 * the 'transfer conplete' message (this is a bit of a hack though :-/ )
2431 BOOL
FTP_CloseFileTransferHandle(LPWININETFILE lpwh
)
2433 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) lpwh
->hdr
.lpwhparent
;
2438 if (!lpwh
->session_deleted
)
2439 lpwfs
->download_in_progress
= NULL
;
2441 /* This just serves to flush the control socket of any spurrious lines written
2442 to it (like '226 Transfer complete.').
2444 Wonder what to do if the server sends us an error code though...
2446 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2447 MAX_REPLY_LEN
, 0, 0, 0);
2449 if (lpwh
->nDataSocket
!= -1)
2450 close(lpwh
->nDataSocket
);
2452 HeapFree(GetProcessHeap(), 0, lpwh
);
2457 /***********************************************************************
2458 * FTP_ReceiveFileList (internal)
2460 * Read file list from server
2463 * Handle to file list on success
2467 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
2468 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
)
2471 LPFILEPROPERTIESA lpafp
= NULL
;
2472 LPWININETFINDNEXTA lpwfn
= NULL
;
2476 if (FTP_ParseDirectory(lpwfs
, nSocket
, &lpafp
, &dwSize
))
2478 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2480 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFINDNEXTA
));
2483 lpwfn
->hdr
.htype
= WH_HFINDNEXT
;
2484 lpwfn
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)lpwfs
;
2485 lpwfn
->hdr
.dwContext
= dwContext
;
2486 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2487 lpwfn
->size
= dwSize
;
2488 lpwfn
->lpafp
= lpafp
;
2492 TRACE("Matched %ld files\n", dwSize
);
2493 return (HINTERNET
)lpwfn
;
2497 /***********************************************************************
2498 * FTP_ConvertFileProp (internal)
2500 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2507 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp
, LPWIN32_FIND_DATAA lpFindFileData
)
2509 BOOL bSuccess
= FALSE
;
2511 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2515 /* Convert 'Unix' time to Windows time */
2516 RtlSecondsSince1970ToTime(mktime(&lpafp
->tmLastModified
),
2517 (LARGE_INTEGER
*) &(lpFindFileData
->ftLastAccessTime
));
2519 /* Not all fields are filled in */
2520 lpFindFileData
->nFileSizeHigh
= 0; /* We do not handle files bigger than 0xFFFFFFFF bytes yet :-) */
2521 lpFindFileData
->nFileSizeLow
= lpafp
->nSize
;
2523 if (lpafp
->bIsDirectory
)
2524 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2526 if (lpafp
->lpszName
)
2527 strncpy(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2536 /***********************************************************************
2537 * FTP_ParseDirectory (internal)
2539 * Parse string of directory information
2545 * FIXME: - This function needs serious clea-up
2546 * - We should consider both UNIX and NT list formats
2548 #define MAX_MONTH_LEN 10
2549 #define MIN_LEN_DIR_ENTRY 15
2551 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
)
2554 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2557 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2563 CHAR pszMonth
[MAX_MONTH_LEN
];
2565 BOOL bSuccess
= TRUE
;
2566 DWORD nBufLen
= MAX_REPLY_LEN
;
2567 LPFILEPROPERTIESA curFileProp
= NULL
;
2568 CHAR
* pszLine
= NULL
;
2569 CHAR
* pszToken
= NULL
;
2570 INT nTokenToSkip
= 3;
2578 INT sizeFilePropArray
= 20;
2579 INT indexFilePropArray
= 0;
2583 /* Allocate intial file properties array */
2584 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESA
)*(sizeFilePropArray
));
2591 while ((pszLine
= INTERNET_GetNextLine(nSocket
, INTERNET_GetResponseBuffer(), &nBufLen
)) != NULL
)
2593 if (sizeFilePropArray
<= indexFilePropArray
)
2595 LPFILEPROPERTIESA tmpafp
;
2597 sizeFilePropArray
*= 2;
2598 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
2599 sizeof(FILEPROPERTIESA
)*sizeFilePropArray
);
2609 curFileProp
= &((*lpafp
)[indexFilePropArray
]);
2611 /* First Parse the permissions. */
2612 pszToken
= strtok(pszLine
, " \t" );
2614 /* HACK! If this is not a file listing skip the line */
2615 if (!pszToken
|| nBufLen
<= MIN_LEN_DIR_ENTRY
)
2617 nBufLen
= MAX_REPLY_LEN
;
2620 if (10 == strlen(pszToken
)) {
2621 /* Unix way of parsing ... */
2622 FTP_ParsePermission(pszToken
, curFileProp
);
2627 pszToken
= strtok( NULL
, " \t" );
2629 } while( nCount
<= nTokenToSkip
);
2631 /* Store the size of the file in the param list. */
2632 TRACE("nSize-> %s\n", pszToken
);
2633 if (pszToken
!= NULL
)
2634 curFileProp
->nSize
= atol(pszToken
);
2636 /* Parse last modified time. */
2644 pszToken
= strtok( NULL
, " \t" );
2645 strncpy(pszMonth
, pszToken
, MAX_MONTH_LEN
);
2646 CharUpperA(pszMonth
);
2647 pszMatch
= strstr(szMonths
, pszMonth
);
2648 if( pszMatch
!= NULL
)
2649 nMonth
= (pszMatch
- szMonths
) / 3;
2651 pszToken
= strtok(NULL
, " \t");
2652 TRACE("nDay -> %s\n", pszToken
);
2653 if (pszToken
!= NULL
)
2654 nDay
= atoi(pszToken
);
2656 pszToken
= strtok(NULL
, " \t");
2657 pszMinutes
= strchr(pszToken
, ':');
2658 if( pszMinutes
!= NULL
) {
2660 nMinutes
= atoi(pszMinutes
);
2661 pszHour
= pszMinutes
- 3;
2662 if (pszHour
!= NULL
)
2663 nHour
= atoi(pszHour
);
2665 apTM
= localtime( &aTime
);
2666 nYear
= apTM
->tm_year
;
2668 nYear
= atoi(pszToken
);
2673 curFileProp
->tmLastModified
.tm_sec
= nSeconds
;
2674 curFileProp
->tmLastModified
.tm_min
= nMinutes
;
2675 curFileProp
->tmLastModified
.tm_hour
= nHour
;
2676 curFileProp
->tmLastModified
.tm_mday
= nDay
;
2677 curFileProp
->tmLastModified
.tm_mon
= nMonth
;
2678 curFileProp
->tmLastModified
.tm_year
= nYear
;
2680 pszToken
= strtok(NULL
, " \t");
2681 if(pszToken
!= NULL
) {
2682 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2683 TRACE(": %s\n", curFileProp
->lpszName
);
2686 nBufLen
= MAX_REPLY_LEN
;
2687 indexFilePropArray
++;
2688 } else if (8 == strlen(pszToken
)) {
2689 /* NT way of parsing ... :
2691 07-13-03 08:55PM <DIR> sakpatch
2692 05-09-03 06:02PM 12656686 2003-04-21bgm_cmd_e.rgz
2695 curFileProp
->permissions
= 0xFFFF; /* No idea, put full permission :-) */
2697 sscanf(pszToken
, "%d-%d-%d",
2698 &curFileProp
->tmLastModified
.tm_mon
,
2699 &curFileProp
->tmLastModified
.tm_mday
,
2700 &curFileProp
->tmLastModified
.tm_year
);
2702 /* Hacky and bad Y2K protection :-) */
2703 if (curFileProp
->tmLastModified
.tm_year
< 70)
2704 curFileProp
->tmLastModified
.tm_year
+= 100;
2706 pszToken
= strtok(NULL
, " \t");
2707 if (pszToken
== NULL
) {
2708 nBufLen
= MAX_REPLY_LEN
;
2711 sscanf(pszToken
, "%d:%d",
2712 &curFileProp
->tmLastModified
.tm_hour
,
2713 &curFileProp
->tmLastModified
.tm_min
);
2714 if ((pszToken
[5] == 'P') && (pszToken
[6] == 'M')) {
2715 curFileProp
->tmLastModified
.tm_hour
+= 12;
2717 curFileProp
->tmLastModified
.tm_sec
= 0;
2719 TRACE("Mod time: %2d:%2d:%2d %2d/%2d/%2d\n",
2720 curFileProp
->tmLastModified
.tm_hour
, curFileProp
->tmLastModified
.tm_min
, curFileProp
->tmLastModified
.tm_sec
,
2721 (curFileProp
->tmLastModified
.tm_year
>= 100) ? curFileProp
->tmLastModified
.tm_year
- 100 : curFileProp
->tmLastModified
.tm_year
,
2722 curFileProp
->tmLastModified
.tm_mon
, curFileProp
->tmLastModified
.tm_mday
);
2724 pszToken
= strtok(NULL
, " \t");
2725 if (pszToken
== NULL
) {
2726 nBufLen
= MAX_REPLY_LEN
;
2729 if (!strcasecmp(pszToken
, "<DIR>")) {
2730 curFileProp
->bIsDirectory
= TRUE
;
2731 TRACE("Is directory\n");
2733 curFileProp
->bIsDirectory
= FALSE
;
2734 curFileProp
->nSize
= atol(pszToken
);
2735 TRACE("nSize: %ld\n", curFileProp
->nSize
);
2738 pszToken
= strtok(NULL
, " \t");
2739 if (pszToken
== NULL
) {
2740 nBufLen
= MAX_REPLY_LEN
;
2743 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2744 TRACE("Name: %s\n", curFileProp
->lpszName
);
2746 nBufLen
= MAX_REPLY_LEN
;
2747 indexFilePropArray
++;
2749 nBufLen
= MAX_REPLY_LEN
;
2753 if (bSuccess
&& indexFilePropArray
)
2755 if (indexFilePropArray
< sizeFilePropArray
- 1)
2757 LPFILEPROPERTIESA tmpafp
;
2759 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
2760 sizeof(FILEPROPERTIESA
)*indexFilePropArray
);
2764 *dwfp
= indexFilePropArray
;
2768 HeapFree(GetProcessHeap(), 0, *lpafp
);
2769 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2778 /***********************************************************************
2779 * FTP_ParsePermission (internal)
2781 * Parse permission string of directory information
2788 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
)
2790 BOOL bSuccess
= TRUE
;
2791 unsigned short nPermission
= 0;
2796 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
2802 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
2808 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
2811 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
2814 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
2817 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
2820 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
2823 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
2826 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
2829 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
2832 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
2836 }while (nPos
<= nLast
);
2838 lpfp
->permissions
= nPermission
;
2843 /***********************************************************************
2844 * FTP_SetResponseError (internal)
2846 * Set the appropriate error code for a given response from the server
2851 DWORD
FTP_SetResponseError(DWORD dwResponse
)
2857 case 421: /* Service not available - Server may be shutting down. */
2858 dwCode
= ERROR_INTERNET_TIMEOUT
;
2861 case 425: /* Cannot open data connection. */
2862 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
2865 case 426: /* Connection closed, transer aborted. */
2866 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
2869 case 500: /* Syntax error. Command unrecognized. */
2870 case 501: /* Syntax error. Error in parameters or arguments. */
2871 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
2874 case 530: /* Not logged in. Login incorrect. */
2875 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
2878 case 550: /* File action not taken. File not found or no access. */
2879 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
2882 case 450: /* File action not taken. File may be busy. */
2883 case 451: /* Action aborted. Server error. */
2884 case 452: /* Action not taken. Insufficient storage space on server. */
2885 case 502: /* Command not implemented. */
2886 case 503: /* Bad sequence of command. */
2887 case 504: /* Command not implemented for that parameter. */
2888 case 532: /* Need account for storing files */
2889 case 551: /* Requested action aborted. Page type unknown */
2890 case 552: /* Action aborted. Exceeded storage allocation */
2891 case 553: /* Action not taken. File name not allowed. */
2894 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
2898 INTERNET_SetLastError(dwCode
);