2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
9 * Copyright 2000 Andreas Mohr
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include <sys/types.h>
33 #ifdef HAVE_SYS_SOCKET_H
34 # include <sys/socket.h>
45 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
50 #define NOACCOUNT "noaccount"
51 #define DATA_PACKET_SIZE 0x2000
56 /* FTP commands with arguments. */
71 /* FTP commands without arguments. */
80 static const CHAR
*szFtpCommands
[] = {
102 static const CHAR szMonths
[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
104 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
105 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
);
106 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
);
107 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
);
108 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
);
109 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
110 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
);
111 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
);
112 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
);
113 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
);
114 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
);
115 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
);
116 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
);
117 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
);
118 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
);
119 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
);
120 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
);
121 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
);
122 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
);
123 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
124 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
);
125 DWORD
FTP_SetResponseError(DWORD dwResponse
);
127 inline static LPSTR
FTP_strdup( LPCSTR str
)
129 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, strlen(str
) + 1 );
130 if (ret
) strcpy( ret
, str
);
134 /***********************************************************************
135 * FtpPutFileA (WININET.@)
137 * Uploads a file to the FTP server
144 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
145 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
147 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
148 LPWININETAPPINFOA hIC
= NULL
;
150 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
152 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
156 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
157 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
159 WORKREQUEST workRequest
;
161 workRequest
.asyncall
= FTPPUTFILEA
;
162 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
163 workRequest
.LPSZLOCALFILE
= (DWORD
)FTP_strdup(lpszLocalFile
);
164 workRequest
.LPSZNEWREMOTEFILE
= (DWORD
)FTP_strdup(lpszNewRemoteFile
);
165 workRequest
.DWFLAGS
= dwFlags
;
166 workRequest
.DWCONTEXT
= dwContext
;
168 return INTERNET_AsyncCall(&workRequest
);
172 return FTP_FtpPutFileA(hConnect
, lpszLocalFile
,
173 lpszNewRemoteFile
, dwFlags
, dwContext
);
177 /***********************************************************************
178 * FTP_FtpPutFileA (Internal)
180 * Uploads a file to the FTP server
187 BOOL WINAPI
FTP_FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
188 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
190 HANDLE hFile
= (HANDLE
)NULL
;
191 BOOL bSuccess
= FALSE
;
192 LPWININETAPPINFOA hIC
= NULL
;
193 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
196 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile
, lpszNewRemoteFile
);
197 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
199 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
203 /* Clear any error information */
204 INTERNET_SetLastError(0);
206 /* Open file to be uploaded */
207 if (INVALID_HANDLE_VALUE
==
208 (hFile
= CreateFileA(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
210 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND
);
214 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
215 if (hIC
->lpfnStatusCB
)
216 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
218 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
222 /* Get data socket to server */
223 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
225 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
227 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
228 MAX_REPLY_LEN
, 0, 0, 0);
234 FTP_SetResponseError(nResCode
);
240 if (lpwfs
->lstnSocket
!= -1)
241 close(lpwfs
->lstnSocket
);
243 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
245 INTERNET_ASYNC_RESULT iar
;
247 iar
.dwResult
= (DWORD
)bSuccess
;
248 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
249 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
250 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
260 /***********************************************************************
261 * FtpSetCurrentDirectoryA (WININET.@)
263 * Change the working directory on the FTP server
270 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
272 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
273 LPWININETAPPINFOA hIC
= NULL
;
275 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
277 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
281 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
283 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
284 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
286 WORKREQUEST workRequest
;
288 workRequest
.asyncall
= FTPSETCURRENTDIRECTORYA
;
289 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
290 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
292 return INTERNET_AsyncCall(&workRequest
);
296 return FTP_FtpSetCurrentDirectoryA(hConnect
, lpszDirectory
);
301 /***********************************************************************
302 * FTP_FtpSetCurrentDirectoryA (Internal)
304 * Change the working directory on the FTP server
311 BOOL WINAPI
FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
314 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
315 LPWININETAPPINFOA hIC
= NULL
;
316 DWORD bSuccess
= FALSE
;
318 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
320 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
322 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
326 /* Clear any error information */
327 INTERNET_SetLastError(0);
329 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
330 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
331 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
334 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
335 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
342 FTP_SetResponseError(nResCode
);
346 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
348 INTERNET_ASYNC_RESULT iar
;
350 iar
.dwResult
= (DWORD
)bSuccess
;
351 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
352 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
353 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
359 /***********************************************************************
360 * FtpCreateDirectoryA (WININET.@)
362 * Create new directory on the FTP server
369 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
371 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
372 LPWININETAPPINFOA hIC
= NULL
;
374 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
376 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
380 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
381 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
383 WORKREQUEST workRequest
;
385 workRequest
.asyncall
= FTPCREATEDIRECTORYA
;
386 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
387 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
389 return INTERNET_AsyncCall(&workRequest
);
393 return FTP_FtpCreateDirectoryA(hConnect
, lpszDirectory
);
398 /***********************************************************************
399 * FTP_FtpCreateDirectoryA (Internal)
401 * Create new directory on the FTP server
408 BOOL WINAPI
FTP_FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
411 BOOL bSuccess
= FALSE
;
412 LPWININETAPPINFOA hIC
= NULL
;
413 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
416 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
418 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
422 /* Clear any error information */
423 INTERNET_SetLastError(0);
425 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
428 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
429 MAX_REPLY_LEN
, 0, 0, 0);
435 FTP_SetResponseError(nResCode
);
439 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
440 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
442 INTERNET_ASYNC_RESULT iar
;
444 iar
.dwResult
= (DWORD
)bSuccess
;
445 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
446 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
447 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
454 /***********************************************************************
455 * FtpFindFirstFileA (WININET.@)
457 * Search the specified directory
460 * HINTERNET on success
464 HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
465 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
467 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
468 LPWININETAPPINFOA hIC
= NULL
;
470 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
472 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
476 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
477 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
479 WORKREQUEST workRequest
;
481 workRequest
.asyncall
= FTPFINDFIRSTFILEA
;
482 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
483 workRequest
.LPSZSEARCHFILE
= (DWORD
)FTP_strdup(lpszSearchFile
);
484 workRequest
.LPFINDFILEDATA
= (DWORD
)lpFindFileData
;
485 workRequest
.DWFLAGS
= dwFlags
;
486 workRequest
.DWCONTEXT
= dwContext
;
488 INTERNET_AsyncCall(&workRequest
);
493 return FTP_FtpFindFirstFileA(hConnect
, lpszSearchFile
, lpFindFileData
,
499 /***********************************************************************
500 * FTP_FtpFindFirstFileA (Internal)
502 * Search the specified directory
505 * HINTERNET on success
509 HINTERNET WINAPI
FTP_FtpFindFirstFileA(HINTERNET hConnect
,
510 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
513 LPWININETAPPINFOA hIC
= NULL
;
514 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
515 LPWININETFINDNEXTA hFindNext
= NULL
;
519 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
521 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
525 /* Clear any error information */
526 INTERNET_SetLastError(0);
528 if (!FTP_InitListenSocket(lpwfs
))
531 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
534 if (!FTP_SendPortOrPasv(lpwfs
))
537 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
538 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, lpszSearchFile
,
539 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
542 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
543 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
546 if (nResCode
== 125 || nResCode
== 150)
550 /* Get data socket to server */
551 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
553 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpFindFileData
, dwContext
);
555 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
556 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
557 if (nResCode
!= 226 && nResCode
!= 250)
558 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
564 FTP_SetResponseError(nResCode
);
568 if (lpwfs
->lstnSocket
!= -1)
569 close(lpwfs
->lstnSocket
);
571 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
573 INTERNET_ASYNC_RESULT iar
;
577 iar
.dwResult
= (DWORD
)hFindNext
;
578 iar
.dwError
= ERROR_SUCCESS
;
579 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
580 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
583 iar
.dwResult
= (DWORD
)hFindNext
;
584 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
585 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
586 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
589 return (HINTERNET
)hFindNext
;
593 /***********************************************************************
594 * FtpGetCurrentDirectoryA (WININET.@)
596 * Retrieves the current directory
603 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
604 LPDWORD lpdwCurrentDirectory
)
606 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
607 LPWININETAPPINFOA hIC
= NULL
;
609 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
611 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
613 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
617 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
618 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
620 WORKREQUEST workRequest
;
622 workRequest
.asyncall
= FTPGETCURRENTDIRECTORYA
;
623 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
624 workRequest
.LPSZDIRECTORY
= (DWORD
)lpszCurrentDirectory
;
625 workRequest
.LPDWDIRECTORY
= (DWORD
)lpdwCurrentDirectory
;
627 return INTERNET_AsyncCall(&workRequest
);
631 return FTP_FtpGetCurrentDirectoryA(hFtpSession
, lpszCurrentDirectory
,
632 lpdwCurrentDirectory
);
637 /***********************************************************************
638 * FTP_FtpGetCurrentDirectoryA (Internal)
640 * Retrieves the current directory
647 BOOL WINAPI
FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
648 LPDWORD lpdwCurrentDirectory
)
651 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
652 LPWININETAPPINFOA hIC
= NULL
;
653 DWORD bSuccess
= FALSE
;
655 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
657 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
659 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
663 /* Clear any error information */
664 INTERNET_SetLastError(0);
666 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
668 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
669 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
670 hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
))
673 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
674 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
);
677 if (nResCode
== 257) /* Extract directory name */
679 INT firstpos
, lastpos
, len
;
680 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
682 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
684 if ('"' == lpszResponseBuffer
[lastpos
])
693 len
= lastpos
- firstpos
- 1;
694 strncpy(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1],
695 len
< *lpdwCurrentDirectory
? len
: *lpdwCurrentDirectory
);
696 *lpdwCurrentDirectory
= len
;
700 FTP_SetResponseError(nResCode
);
704 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
706 INTERNET_ASYNC_RESULT iar
;
708 iar
.dwResult
= (DWORD
)bSuccess
;
709 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
710 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
711 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
714 return (DWORD
) bSuccess
;
717 /***********************************************************************
718 * FtpOpenFileA (WININET.@)
720 * Open a remote file for writing or reading
723 * HINTERNET handle on success
727 HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
728 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
731 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
732 LPWININETAPPINFOA hIC
= NULL
;
734 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
736 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
740 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
741 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
743 WORKREQUEST workRequest
;
745 workRequest
.asyncall
= FTPOPENFILEA
;
746 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
747 workRequest
.LPSZFILENAME
= (DWORD
)FTP_strdup(lpszFileName
);
748 workRequest
.FDWACCESS
= fdwAccess
;
749 workRequest
.DWFLAGS
= dwFlags
;
750 workRequest
.DWCONTEXT
= dwContext
;
752 INTERNET_AsyncCall(&workRequest
);
757 return FTP_FtpOpenFileA(hFtpSession
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
762 /***********************************************************************
763 * FTP_FtpOpenFileA (Internal)
765 * Open a remote file for writing or reading
768 * HINTERNET handle on success
772 HINTERNET
FTP_FtpOpenFileA(HINTERNET hFtpSession
,
773 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
777 BOOL bSuccess
= FALSE
;
778 LPWININETFILE hFile
= NULL
;
779 LPWININETAPPINFOA hIC
= NULL
;
780 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
784 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
786 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
790 /* Clear any error information */
791 INTERNET_SetLastError(0);
793 if (GENERIC_READ
== fdwAccess
)
795 /* Set up socket to retrieve data */
796 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
798 else if (GENERIC_WRITE
== fdwAccess
)
800 /* Set up socket to send data */
801 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
804 /* Get data socket to server */
805 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
807 hFile
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE
));
808 hFile
->hdr
.htype
= WH_HFILE
;
809 hFile
->hdr
.dwFlags
= dwFlags
;
810 hFile
->hdr
.dwContext
= dwContext
;
811 hFile
->hdr
.lpwhparent
= hFtpSession
;
812 hFile
->nDataSocket
= nDataSocket
;
815 if (lpwfs
->lstnSocket
!= -1)
816 close(lpwfs
->lstnSocket
);
818 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
819 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
821 INTERNET_ASYNC_RESULT iar
;
825 iar
.dwResult
= (DWORD
)hFile
;
826 iar
.dwError
= ERROR_SUCCESS
;
827 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
828 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
831 iar
.dwResult
= (DWORD
)bSuccess
;
832 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
833 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
834 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
837 return (HINTERNET
)hFile
;
841 /***********************************************************************
842 * FtpGetFileA (WININET.@)
844 * Retrieve file from the FTP server
851 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
852 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
855 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hInternet
;
856 LPWININETAPPINFOA hIC
= NULL
;
858 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
860 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
864 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
865 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
867 WORKREQUEST workRequest
;
869 workRequest
.asyncall
= FTPGETFILEA
;
870 workRequest
.HFTPSESSION
= (DWORD
)hInternet
;
871 workRequest
.LPSZREMOTEFILE
= (DWORD
)FTP_strdup(lpszRemoteFile
);
872 workRequest
.LPSZNEWFILE
= (DWORD
)FTP_strdup(lpszNewFile
);
873 workRequest
.DWLOCALFLAGSATTRIBUTE
= dwLocalFlagsAttribute
;
874 workRequest
.FFAILIFEXISTS
= (DWORD
)fFailIfExists
;
875 workRequest
.DWFLAGS
= dwInternetFlags
;
876 workRequest
.DWCONTEXT
= dwContext
;
878 return INTERNET_AsyncCall(&workRequest
);
882 return FTP_FtpGetFileA(hInternet
, lpszRemoteFile
, lpszNewFile
,
883 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
888 /***********************************************************************
889 * FTP_FtpGetFileA (Internal)
891 * Retrieve file from the FTP server
898 BOOL WINAPI
FTP_FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
899 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
903 BOOL bSuccess
= FALSE
;
905 LPWININETAPPINFOA hIC
= NULL
;
906 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hInternet
;
908 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile
, lpszNewFile
);
909 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
911 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
915 /* Clear any error information */
916 INTERNET_SetLastError(0);
918 /* Ensure we can write to lpszNewfile by opening it */
919 hFile
= CreateFileA(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
920 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
921 if (INVALID_HANDLE_VALUE
== hFile
)
924 /* Set up socket to retrieve data */
925 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
931 /* Get data socket to server */
932 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
937 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
938 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
939 MAX_REPLY_LEN
, 0, 0, 0);
945 FTP_SetResponseError(nResCode
);
952 if (lpwfs
->lstnSocket
!= -1)
953 close(lpwfs
->lstnSocket
);
958 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
959 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
961 INTERNET_ASYNC_RESULT iar
;
963 iar
.dwResult
= (DWORD
)bSuccess
;
964 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
965 hIC
->lpfnStatusCB(hInternet
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
966 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
973 /***********************************************************************
974 * FtpDeleteFileA (WININET.@)
976 * Delete a file on the ftp server
983 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
985 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
986 LPWININETAPPINFOA hIC
= NULL
;
988 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
990 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
994 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
995 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
997 WORKREQUEST workRequest
;
999 workRequest
.asyncall
= FTPRENAMEFILEA
;
1000 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1001 workRequest
.LPSZFILENAME
= (DWORD
)FTP_strdup(lpszFileName
);
1003 return INTERNET_AsyncCall(&workRequest
);
1007 return FTP_FtpDeleteFileA(hFtpSession
, lpszFileName
);
1012 /***********************************************************************
1013 * FTP_FtpDeleteFileA (Internal)
1015 * Delete a file on the ftp server
1022 BOOL
FTP_FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1025 BOOL bSuccess
= FALSE
;
1026 LPWININETAPPINFOA hIC
= NULL
;
1027 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1029 TRACE("0x%08lx\n", (ULONG
) hFtpSession
);
1030 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1032 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1036 /* Clear any error information */
1037 INTERNET_SetLastError(0);
1039 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1042 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1043 MAX_REPLY_LEN
, 0, 0, 0);
1046 if (nResCode
== 250)
1049 FTP_SetResponseError(nResCode
);
1052 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1053 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1055 INTERNET_ASYNC_RESULT iar
;
1057 iar
.dwResult
= (DWORD
)bSuccess
;
1058 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1059 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1060 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1067 /***********************************************************************
1068 * FtpRemoveDirectoryA (WININET.@)
1070 * Remove a directory on the ftp server
1077 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1079 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1080 LPWININETAPPINFOA hIC
= NULL
;
1082 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1084 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1088 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1089 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1091 WORKREQUEST workRequest
;
1093 workRequest
.asyncall
= FTPREMOVEDIRECTORYA
;
1094 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1095 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
1097 return INTERNET_AsyncCall(&workRequest
);
1101 return FTP_FtpRemoveDirectoryA(hFtpSession
, lpszDirectory
);
1106 /***********************************************************************
1107 * FTP_FtpRemoveDirectoryA (Internal)
1109 * Remove a directory on the ftp server
1116 BOOL
FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1119 BOOL bSuccess
= FALSE
;
1120 LPWININETAPPINFOA hIC
= NULL
;
1121 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1124 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1126 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1130 /* Clear any error information */
1131 INTERNET_SetLastError(0);
1133 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1136 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1137 MAX_REPLY_LEN
, 0, 0, 0);
1140 if (nResCode
== 250)
1143 FTP_SetResponseError(nResCode
);
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(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1155 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1162 /***********************************************************************
1163 * FtpRenameFileA (WININET.@)
1165 * Rename a file on the ftp server
1172 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1174 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1175 LPWININETAPPINFOA hIC
= NULL
;
1177 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1179 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1183 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1184 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1186 WORKREQUEST workRequest
;
1188 workRequest
.asyncall
= FTPRENAMEFILEA
;
1189 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1190 workRequest
.LPSZSRCFILE
= (DWORD
)FTP_strdup(lpszSrc
);
1191 workRequest
.LPSZDESTFILE
= (DWORD
)FTP_strdup(lpszDest
);
1193 return INTERNET_AsyncCall(&workRequest
);
1197 return FTP_FtpRenameFileA(hFtpSession
, lpszSrc
, lpszDest
);
1201 /***********************************************************************
1202 * FTP_FtpRenameFileA (Internal)
1204 * Rename a file on the ftp server
1211 BOOL
FTP_FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1214 BOOL bSuccess
= FALSE
;
1215 LPWININETAPPINFOA hIC
= NULL
;
1216 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1219 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1221 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1225 /* Clear any error information */
1226 INTERNET_SetLastError(0);
1228 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1231 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1232 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1233 if (nResCode
== 350)
1235 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1238 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1239 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1242 if (nResCode
== 250)
1245 FTP_SetResponseError(nResCode
);
1248 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1249 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1251 INTERNET_ASYNC_RESULT iar
;
1253 iar
.dwResult
= (DWORD
)bSuccess
;
1254 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1255 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1256 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1263 /***********************************************************************
1264 * FTP_Connect (internal)
1266 * Connect to a ftp server
1269 * HINTERNET a session handle on success
1274 HINTERNET
FTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
1275 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
1276 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
1278 struct sockaddr_in socketAddr
;
1279 struct hostent
*phe
= NULL
;
1280 INT nsocket
= -1, sock_namelen
;
1281 LPWININETAPPINFOA hIC
= NULL
;
1282 BOOL bSuccess
= FALSE
;
1283 LPWININETFTPSESSIONA lpwfs
= NULL
;
1285 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1286 (ULONG
) hInternet
, lpszServerName
,
1287 nServerPort
, lpszUserName
, lpszPassword
);
1289 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
1292 hIC
= (LPWININETAPPINFOA
) hInternet
;
1294 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1296 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME
);
1300 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1301 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1303 if (hIC
->lpfnStatusCB
)
1304 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1305 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1307 if (!GetAddress(lpszServerName
, nServerPort
, &phe
, &socketAddr
))
1309 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1313 if (hIC
->lpfnStatusCB
)
1314 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1315 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1317 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1320 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1324 if (hIC
->lpfnStatusCB
)
1325 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1326 &socketAddr
, sizeof(struct sockaddr_in
));
1328 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1330 ERR("Unable to connect (%s)\n", strerror(errno
));
1331 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1335 TRACE("Connected to server\n");
1336 if (hIC
->lpfnStatusCB
)
1337 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1338 &socketAddr
, sizeof(struct sockaddr_in
));
1340 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA
));
1343 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1347 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1348 lpwfs
->hdr
.dwFlags
= dwFlags
;
1349 lpwfs
->hdr
.dwContext
= dwContext
;
1350 lpwfs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
1351 lpwfs
->sndSocket
= nsocket
;
1352 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1353 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1354 lpwfs
->phostent
= phe
;
1356 if (NULL
== lpszUserName
)
1358 lpwfs
->lpszUserName
= FTP_strdup("anonymous");
1359 lpwfs
->lpszPassword
= FTP_strdup("user@server");
1363 lpwfs
->lpszUserName
= FTP_strdup(lpszUserName
);
1364 lpwfs
->lpszPassword
= FTP_strdup(lpszPassword
);
1367 if (FTP_ConnectToHost(lpwfs
))
1369 if (hIC
->lpfnStatusCB
)
1371 INTERNET_ASYNC_RESULT iar
;
1373 iar
.dwResult
= (DWORD
)lpwfs
;
1374 iar
.dwError
= ERROR_SUCCESS
;
1376 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1377 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1379 TRACE("Successfully logged into server\n");
1385 if (!bSuccess
&& nsocket
== -1)
1388 if (!bSuccess
&& lpwfs
)
1390 HeapFree(GetProcessHeap(), 0, lpwfs
);
1394 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1396 INTERNET_ASYNC_RESULT iar
;
1398 iar
.dwResult
= (DWORD
)lpwfs
;
1399 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1400 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1401 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1404 return (HINTERNET
) lpwfs
;
1408 /***********************************************************************
1409 * FTP_ConnectToHost (internal)
1411 * Connect to a ftp server
1418 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
)
1421 BOOL bSuccess
= FALSE
;
1424 FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1426 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1429 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1430 MAX_REPLY_LEN
, 0, 0, 0);
1433 /* Login successful... */
1434 if (nResCode
== 230)
1436 /* User name okay, need password... */
1437 else if (nResCode
== 331)
1438 bSuccess
= FTP_SendPassword(lpwfs
);
1439 /* Need account for login... */
1440 else if (nResCode
== 332)
1441 bSuccess
= FTP_SendAccount(lpwfs
);
1443 FTP_SetResponseError(nResCode
);
1446 TRACE("Returning %d\n", bSuccess
);
1452 /***********************************************************************
1453 * FTP_SendCommand (internal)
1455 * Send command to server
1462 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
1463 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1467 DWORD nBytesSent
= 0;
1471 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
1474 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1476 bParamHasLen
= lpszParam
&& strlen(lpszParam
) > 0;
1477 len
= (bParamHasLen
? strlen(lpszParam
) : -1) + strlen(szFtpCommands
[ftpCmd
]) +
1479 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1481 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1484 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], bParamHasLen
? " " : "",
1485 bParamHasLen
? lpszParam
: "", szCRLF
);
1487 TRACE("Sending (%s) len(%ld)\n", buf
, len
);
1488 while((nBytesSent
< len
) && (nRC
!= -1))
1490 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1494 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1497 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1498 &nBytesSent
, sizeof(DWORD
));
1500 TRACE("Sent %ld bytes\n", nBytesSent
);
1505 /***********************************************************************
1506 * FTP_ReceiveResponse (internal)
1508 * Receive response from server
1511 * Reply code on success
1516 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
1517 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1521 char firstprefix
[5];
1522 BOOL multiline
= FALSE
;
1525 TRACE("socket(%d) \n", nSocket
);
1528 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
1533 if (!INTERNET_GetNextLine(nSocket
, lpszResponse
, &nRecv
))
1540 if(lpszResponse
[3] != '-')
1543 { /* Start of multiline repsonse. Loop until we get "nnn " */
1545 memcpy(firstprefix
, lpszResponse
, 3);
1546 firstprefix
[3] = ' ';
1547 firstprefix
[4] = '\0';
1552 if(!memcmp(firstprefix
, lpszResponse
, 4))
1560 lpszResponse
[nRecv
] = '\0';
1561 rc
= atoi(lpszResponse
);
1564 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
1565 &nRecv
, sizeof(DWORD
));
1569 TRACE("return %d\n", rc
);
1574 /***********************************************************************
1575 * FTP_SendPassword (internal)
1577 * Send password to ftp server
1584 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
)
1587 BOOL bSuccess
= FALSE
;
1590 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
1593 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1594 MAX_REPLY_LEN
, 0, 0, 0);
1597 TRACE("Received reply code %d\n", nResCode
);
1598 /* Login successful... */
1599 if (nResCode
== 230)
1601 /* Command not implemented, superfluous at the server site... */
1602 /* Need account for login... */
1603 else if (nResCode
== 332)
1604 bSuccess
= FTP_SendAccount(lpwfs
);
1606 FTP_SetResponseError(nResCode
);
1610 TRACE("Returning %d\n", bSuccess
);
1615 /***********************************************************************
1616 * FTP_SendAccount (internal)
1625 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
)
1628 BOOL bSuccess
= FALSE
;
1631 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, NOACCOUNT
, 0, 0, 0))
1634 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1635 MAX_REPLY_LEN
, 0, 0, 0);
1639 FTP_SetResponseError(nResCode
);
1646 /***********************************************************************
1647 * FTP_SendStore (internal)
1649 * Send request to upload file to ftp server
1656 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
1659 BOOL bSuccess
= FALSE
;
1662 if (!FTP_InitListenSocket(lpwfs
))
1665 if (!FTP_SendType(lpwfs
, dwType
))
1668 if (!FTP_SendPortOrPasv(lpwfs
))
1671 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
1673 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1674 MAX_REPLY_LEN
, 0, 0, 0);
1677 if (nResCode
== 150)
1680 FTP_SetResponseError(nResCode
);
1684 if (!bSuccess
&& lpwfs
->lstnSocket
!= -1)
1686 close(lpwfs
->lstnSocket
);
1687 lpwfs
->lstnSocket
= -1;
1694 /***********************************************************************
1695 * FTP_InitListenSocket (internal)
1697 * Create a socket to listen for server response
1704 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
)
1706 BOOL bSuccess
= FALSE
;
1707 size_t namelen
= sizeof(struct sockaddr_in
);
1711 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
1712 if (lpwfs
->lstnSocket
== -1)
1714 TRACE("Unable to create listening socket\n");
1718 /* We obtain our ip addr from the name of the command channel socket */
1719 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
1721 /* and get the system to assign us a port */
1722 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
1724 if (bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)) == -1)
1726 TRACE("Unable to bind socket\n");
1730 if (listen(lpwfs
->lstnSocket
, MAX_BACKLOG
) == -1)
1732 TRACE("listen failed\n");
1736 if (getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
) != -1)
1740 if (!bSuccess
&& lpwfs
->lstnSocket
== -1)
1742 close(lpwfs
->lstnSocket
);
1743 lpwfs
->lstnSocket
= -1;
1750 /***********************************************************************
1751 * FTP_SendType (internal)
1753 * Tell server type of data being transferred
1759 * W98SE doesn't cache the type that's currently set
1760 * (i.e. it sends it always),
1761 * so we probably don't want to do that either.
1763 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
)
1766 CHAR type
[2] = { "I\0" };
1767 BOOL bSuccess
= FALSE
;
1770 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
1773 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
1776 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1777 MAX_REPLY_LEN
, 0, 0, 0)/100;
1783 FTP_SetResponseError(nResCode
);
1791 /***********************************************************************
1792 * FTP_SendPort (internal)
1794 * Tell server which port to use
1801 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
)
1804 CHAR szIPAddress
[64];
1805 BOOL bSuccess
= FALSE
;
1808 sprintf(szIPAddress
, "%d,%d,%d,%d,%d,%d",
1809 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
1810 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
1811 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
1812 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
1813 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
1814 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
1816 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
1819 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1820 MAX_REPLY_LEN
,0, 0, 0);
1823 if (nResCode
== 200)
1826 FTP_SetResponseError(nResCode
);
1834 /***********************************************************************
1835 * FTP_DoPassive (internal)
1837 * Tell server that we want to do passive transfers
1838 * and connect data socket
1845 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
)
1848 BOOL bSuccess
= FALSE
;
1851 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
1854 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1855 MAX_REPLY_LEN
,0, 0, 0);
1858 if (nResCode
== 227)
1860 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
1864 char *pAddr
, *pPort
;
1866 struct sockaddr_in dataSocketAddress
;
1868 p
= lpszResponseBuffer
+4; /* skip status code */
1870 /* do a very strict check; we can improve that later. */
1872 if (strncmp(p
, "Entering Passive Mode", 21))
1874 ERR("unknown response '%.*s', aborting\n", 21, p
);
1877 p
+= 21; /* skip string */
1878 if ((*p
++ != ' ') || (*p
++ != '('))
1880 ERR("unknown response format, aborting\n");
1884 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
1887 ERR("unknown response address format '%s', aborting\n", p
);
1890 for (i
=0; i
< 6; i
++)
1893 dataSocketAddress
= lpwfs
->socketAddress
;
1894 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
1895 pPort
= (char *)&(dataSocketAddress
.sin_port
);
1903 nsocket
= socket(AF_INET
,SOCK_STREAM
,0);
1907 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
1909 ERR("can't connect passive FTP data port.\n");
1912 lpwfs
->pasvSocket
= nsocket
;
1916 FTP_SetResponseError(nResCode
);
1924 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
)
1926 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
1928 if (!FTP_DoPassive(lpwfs
))
1933 if (!FTP_SendPort(lpwfs
))
1940 /***********************************************************************
1941 * FTP_GetDataSocket (internal)
1943 * Either accepts an incoming data socket connection from the server
1944 * or just returns the already opened socket after a PASV command
1945 * in case of passive FTP.
1953 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
)
1955 struct sockaddr_in saddr
;
1956 size_t addrlen
= sizeof(struct sockaddr
);
1959 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
1961 *nDataSocket
= lpwfs
->pasvSocket
;
1965 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
1966 close(lpwfs
->lstnSocket
);
1967 lpwfs
->lstnSocket
= -1;
1969 return *nDataSocket
!= -1;
1973 /***********************************************************************
1974 * FTP_SendData (internal)
1976 * Send data to the server
1983 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
)
1985 BY_HANDLE_FILE_INFORMATION fi
;
1986 DWORD nBytesRead
= 0;
1987 DWORD nBytesSent
= 0;
1988 DWORD nTotalSent
= 0;
1989 DWORD nBytesToSend
, nLen
, nRC
= 1;
1990 time_t s_long_time
, e_long_time
;
1995 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
1996 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
1998 /* Get the size of the file. */
1999 GetFileInformationByHandle(hFile
, &fi
);
2004 nBytesToSend
= nBytesRead
- nBytesSent
;
2006 if (nBytesToSend
<= 0)
2008 /* Read data from file. */
2010 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2011 ERR("Failed reading from file\n");
2014 nBytesToSend
= nBytesRead
;
2019 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2020 DATA_PACKET_SIZE
: nBytesToSend
;
2021 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2029 /* Do some computation to display the status. */
2031 nSeconds
= e_long_time
- s_long_time
;
2032 if( nSeconds
/ 60 > 0 )
2034 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2035 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2036 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2040 TRACE( "%ld bytes of %ld bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2041 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2042 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2044 } while (nRC
!= -1);
2046 TRACE("file transfer complete!\n");
2048 if(lpszBuffer
!= NULL
)
2049 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2055 /***********************************************************************
2056 * FTP_SendRetrieve (internal)
2058 * Send request to retrieve a file
2061 * Number of bytes to be received on success
2065 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
2071 if (!FTP_InitListenSocket(lpwfs
))
2074 if (!FTP_SendType(lpwfs
, dwType
))
2077 if (!FTP_SendPortOrPasv(lpwfs
))
2080 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2083 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2084 MAX_REPLY_LEN
, 0, 0, 0);
2087 if (nResCode
== 125 || nResCode
== 150)
2089 /* Parse size of data to be retrieved */
2090 INT i
, sizepos
= -1;
2091 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2092 for (i
= strlen(lpszResponseBuffer
) - 1; i
>= 0; i
--)
2094 if ('(' == lpszResponseBuffer
[i
])
2103 nResult
= atol(&lpszResponseBuffer
[sizepos
+1]);
2104 TRACE("Waiting to receive %ld bytes\n", nResult
);
2110 if (0 == nResult
&& lpwfs
->lstnSocket
!= -1)
2112 close(lpwfs
->lstnSocket
);
2113 lpwfs
->lstnSocket
= -1;
2120 /***********************************************************************
2121 * FTP_RetrieveData (internal)
2123 * Retrieve data from server
2130 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2132 DWORD nBytesWritten
;
2133 DWORD nBytesReceived
= 0;
2139 if (INVALID_HANDLE_VALUE
== hFile
)
2142 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2143 if (NULL
== lpszBuffer
)
2145 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2149 while (nBytesReceived
< nBytes
&& nRC
!= -1)
2151 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2154 /* other side closed socket. */
2157 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2158 nBytesReceived
+= nRC
;
2161 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived
, nBytes
,
2162 nBytesReceived
* 100 / nBytes
);
2165 TRACE("Data transfer complete\n");
2166 if (NULL
!= lpszBuffer
)
2167 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2174 /***********************************************************************
2175 * FTP_CloseSessionHandle (internal)
2177 * Deallocate session handle
2184 BOOL
FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs
)
2186 if (lpwfs
->sndSocket
!= -1)
2187 close(lpwfs
->sndSocket
);
2189 if (lpwfs
->lstnSocket
!= -1)
2190 close(lpwfs
->lstnSocket
);
2192 if (lpwfs
->lpszPassword
)
2193 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2195 if (lpwfs
->lpszUserName
)
2196 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2198 HeapFree(GetProcessHeap(), 0, lpwfs
);
2204 /***********************************************************************
2205 * FTP_CloseSessionHandle (internal)
2207 * Deallocate session handle
2214 BOOL
FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn
)
2220 for (i
= 0; i
< lpwfn
->size
; i
++)
2222 if (NULL
!= lpwfn
->lpafp
[i
].lpszName
)
2223 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2226 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2227 HeapFree(GetProcessHeap(), 0, lpwfn
);
2233 /***********************************************************************
2234 * FTP_ReceiveFileList (internal)
2236 * Read file list from server
2239 * Handle to file list on success
2243 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
2244 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
)
2247 LPFILEPROPERTIESA lpafp
= NULL
;
2248 LPWININETFINDNEXTA lpwfn
= NULL
;
2252 if (FTP_ParseDirectory(lpwfs
, nSocket
, &lpafp
, &dwSize
))
2254 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2256 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFINDNEXTA
));
2259 lpwfn
->hdr
.htype
= WH_HFINDNEXT
;
2260 lpwfn
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)lpwfs
;
2261 lpwfn
->hdr
.dwContext
= dwContext
;
2262 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2263 lpwfn
->size
= dwSize
;
2264 lpwfn
->lpafp
= lpafp
;
2268 TRACE("Matched %ld files\n", dwSize
);
2269 return (HINTERNET
)lpwfn
;
2273 /***********************************************************************
2274 * FTP_ConvertFileProp (internal)
2276 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2283 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp
, LPWIN32_FIND_DATAA lpFindFileData
)
2285 BOOL bSuccess
= FALSE
;
2287 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2291 DWORD access
= mktime(&lpafp
->tmLastModified
);
2293 /* Not all fields are filled in */
2294 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= HIWORD(access
);
2295 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= LOWORD(access
);
2296 lpFindFileData
->nFileSizeHigh
= HIWORD(lpafp
->nSize
);
2297 lpFindFileData
->nFileSizeLow
= LOWORD(lpafp
->nSize
);
2299 if (lpafp
->bIsDirectory
)
2300 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2302 if (lpafp
->lpszName
)
2303 strncpy(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2312 /***********************************************************************
2313 * FTP_ParseDirectory (internal)
2315 * Parse string of directory information
2321 * FIXME: - This function needs serious clea-up
2322 * - We should consider both UNIX and NT list formats
2324 #define MAX_MONTH_LEN 10
2325 #define MIN_LEN_DIR_ENTRY 15
2327 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
)
2330 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2333 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2339 CHAR pszMonth
[MAX_MONTH_LEN
];
2341 BOOL bSuccess
= TRUE
;
2342 DWORD nBufLen
= MAX_REPLY_LEN
;
2343 LPFILEPROPERTIESA curFileProp
= NULL
;
2344 CHAR
* pszLine
= NULL
;
2345 CHAR
* pszToken
= NULL
;
2346 INT nTokenToSkip
= 3;
2354 INT sizeFilePropArray
= 20;
2355 INT indexFilePropArray
= 0;
2359 /* Allocate intial file properties array */
2360 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESA
)*(sizeFilePropArray
));
2367 while ((pszLine
= INTERNET_GetNextLine(nSocket
, INTERNET_GetResponseBuffer(), &nBufLen
)) != NULL
)
2369 if (sizeFilePropArray
<= indexFilePropArray
)
2371 LPFILEPROPERTIESA tmpafp
;
2373 sizeFilePropArray
*= 2;
2374 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
2375 sizeof(FILEPROPERTIESA
)*sizeFilePropArray
);
2385 curFileProp
= &((*lpafp
)[indexFilePropArray
]);
2387 /* First Parse the permissions. */
2388 pszToken
= strtok(pszLine
, " \t" );
2390 /* HACK! If this is not a file listing skip the line */
2391 if (!pszToken
|| 10 != strlen(pszToken
) || nBufLen
<= MIN_LEN_DIR_ENTRY
)
2393 nBufLen
= MAX_REPLY_LEN
;
2397 FTP_ParsePermission(pszToken
, curFileProp
);
2403 pszToken
= strtok( NULL
, " \t" );
2405 } while( nCount
<= nTokenToSkip
);
2407 /* Store the size of the file in the param list. */
2408 TRACE("nSize-> %s\n", pszToken
);
2409 if (pszToken
!= NULL
)
2410 curFileProp
->nSize
= atol(pszToken
);
2412 /* Parse last modified time. */
2420 pszToken
= strtok( NULL
, " \t" );
2421 strncpy(pszMonth
, pszToken
, MAX_MONTH_LEN
);
2422 CharUpperA(pszMonth
);
2423 pszMatch
= strstr(szMonths
, pszMonth
);
2424 if( pszMatch
!= NULL
)
2425 nMonth
= (pszMatch
- szMonths
) / 3;
2427 pszToken
= strtok(NULL
, " \t");
2428 TRACE("nDay -> %s\n", pszToken
);
2429 if (pszToken
!= NULL
)
2430 nDay
= atoi(pszToken
);
2432 pszToken
= strtok(NULL
, " \t");
2433 pszMinutes
= strchr(pszToken
, ':');
2434 if( pszMinutes
!= NULL
)
2437 nMinutes
= atoi(pszMinutes
);
2438 pszHour
= pszMinutes
- 3;
2439 if (pszHour
!= NULL
)
2440 nHour
= atoi(pszHour
);
2442 apTM
= localtime( &aTime
);
2443 nYear
= apTM
->tm_year
;
2447 nYear
= atoi(pszToken
);
2452 curFileProp
->tmLastModified
.tm_sec
= nSeconds
;
2453 curFileProp
->tmLastModified
.tm_min
= nMinutes
;
2454 curFileProp
->tmLastModified
.tm_hour
= nHour
;
2455 curFileProp
->tmLastModified
.tm_mday
= nDay
;
2456 curFileProp
->tmLastModified
.tm_mon
= nMonth
;
2457 curFileProp
->tmLastModified
.tm_year
= nYear
;
2459 pszToken
= strtok(NULL
, " \t");
2460 if(pszToken
!= NULL
)
2462 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2463 TRACE(": %s\n", curFileProp
->lpszName
);
2466 nBufLen
= MAX_REPLY_LEN
;
2467 indexFilePropArray
++;
2470 if (bSuccess
&& indexFilePropArray
)
2472 if (indexFilePropArray
< sizeFilePropArray
- 1)
2474 LPFILEPROPERTIESA tmpafp
;
2476 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
2477 sizeof(FILEPROPERTIESA
)*indexFilePropArray
);
2481 *dwfp
= indexFilePropArray
;
2485 HeapFree(GetProcessHeap(), 0, *lpafp
);
2486 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2495 /***********************************************************************
2496 * FTP_ParsePermission (internal)
2498 * Parse permission string of directory information
2505 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
)
2507 BOOL bSuccess
= TRUE
;
2508 unsigned short nPermission
= 0;
2513 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
2519 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
2525 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
2528 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
2531 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
2534 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
2537 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
2540 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
2543 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
2546 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
2549 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
2553 }while (nPos
<= nLast
);
2555 lpfp
->permissions
= nPermission
;
2560 /***********************************************************************
2561 * FTP_SetResponseError (internal)
2563 * Set the appropriate error code for a given response from the server
2568 DWORD
FTP_SetResponseError(DWORD dwResponse
)
2574 case 421: /* Service not available - Server may be shutting down. */
2575 dwCode
= ERROR_INTERNET_TIMEOUT
;
2578 case 425: /* Cannot open data connection. */
2579 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
2582 case 426: /* Connection closed, transer aborted. */
2583 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
2586 case 500: /* Syntax error. Command unrecognized. */
2587 case 501: /* Syntax error. Error in parameters or arguments. */
2588 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
2591 case 530: /* Not logged in. Login incorrect. */
2592 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
2595 case 550: /* File action not taken. File not found or no access. */
2596 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
2599 case 450: /* File action not taken. File may be busy. */
2600 case 451: /* Action aborted. Server error. */
2601 case 452: /* Action not taken. Insufficient storage space on server. */
2602 case 502: /* Command not implemented. */
2603 case 503: /* Bad sequence of command. */
2604 case 504: /* Command not implemented for that parameter. */
2605 case 532: /* Need account for storing files */
2606 case 551: /* Requested action aborted. Page type unknown */
2607 case 552: /* Action aborted. Exceeded storage allocation */
2608 case 553: /* Action not taken. File name not allowed. */
2611 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
2615 INTERNET_SetLastError(dwCode
);