2 * WININET - Ftp implementation
4 * Copyright 1999 Corel Corporation
9 * Copyright 2000 Andreas Mohr
21 #include <sys/types.h>
22 #ifdef HAVE_SYS_SOCKET_H
23 # include <sys/socket.h>
27 #ifdef HAVE_NETINET_IN_SYSTM_H
28 # include <netinet/in_systm.h>
30 #ifdef HAVE_NETINET_IN_H
31 # include <netinet/in.h>
33 #ifdef HAVE_NETINET_IP_H
34 # include <netinet/ip.h>
45 #include "debugtools.h"
48 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.43)
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
!= INVALID_SOCKET
)
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.49)
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.31)
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.35)
457 * Search the specified directory
460 * HINTERNET on success
464 INTERNETAPI 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 INTERNETAPI 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
!= INVALID_SOCKET
)
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.37)
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.41)
720 * Open a remote file for writing or reading
723 * HINTERNET handle on success
727 INTERNETAPI 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
!= INVALID_SOCKET
)
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.39)
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
!= INVALID_SOCKET
)
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.33)
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.45)
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.47)
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
= INVALID_SOCKET
, 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 if (INVALID_SOCKET
== (nsocket
= socket(AF_INET
,SOCK_STREAM
,0)))
1319 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1323 if (hIC
->lpfnStatusCB
)
1324 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTING_TO_SERVER
,
1325 &socketAddr
, sizeof(struct sockaddr_in
));
1327 if (connect(nsocket
, (struct sockaddr
*)&socketAddr
, sizeof(socketAddr
)) < 0)
1329 ERR("Unable to connect (%s)\n", strerror(errno
));
1330 INTERNET_SetLastError(ERROR_INTERNET_CANNOT_CONNECT
);
1334 TRACE("Connected to server\n");
1335 if (hIC
->lpfnStatusCB
)
1336 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_CONNECTED_TO_SERVER
,
1337 &socketAddr
, sizeof(struct sockaddr_in
));
1339 lpwfs
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFTPSESSIONA
));
1342 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1346 lpwfs
->hdr
.htype
= WH_HFTPSESSION
;
1347 lpwfs
->hdr
.dwFlags
= dwFlags
;
1348 lpwfs
->hdr
.dwContext
= dwContext
;
1349 lpwfs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
1350 lpwfs
->sndSocket
= nsocket
;
1351 sock_namelen
= sizeof(lpwfs
->socketAddress
);
1352 getsockname(nsocket
, (struct sockaddr
*) &lpwfs
->socketAddress
, &sock_namelen
);
1353 lpwfs
->phostent
= phe
;
1355 if (NULL
== lpszUserName
)
1357 lpwfs
->lpszUserName
= FTP_strdup("anonymous");
1358 lpwfs
->lpszPassword
= FTP_strdup("user@server");
1362 lpwfs
->lpszUserName
= FTP_strdup(lpszUserName
);
1363 lpwfs
->lpszPassword
= FTP_strdup(lpszPassword
);
1366 if (FTP_ConnectToHost(lpwfs
))
1368 if (hIC
->lpfnStatusCB
)
1370 INTERNET_ASYNC_RESULT iar
;
1372 iar
.dwResult
= (DWORD
)lpwfs
;
1373 iar
.dwError
= ERROR_SUCCESS
;
1375 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
1376 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1378 TRACE("Successfully logged into server\n");
1384 if (!bSuccess
&& INVALID_SOCKET
!= nsocket
)
1387 if (!bSuccess
&& lpwfs
)
1389 HeapFree(GetProcessHeap(), 0, lpwfs
);
1393 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1395 INTERNET_ASYNC_RESULT iar
;
1397 iar
.dwResult
= (DWORD
)lpwfs
;
1398 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1399 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1400 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1403 return (HINTERNET
) lpwfs
;
1407 /***********************************************************************
1408 * FTP_ConnectToHost (internal)
1410 * Connect to a ftp server
1417 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
)
1420 BOOL bSuccess
= FALSE
;
1423 FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1425 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_USER
, lpwfs
->lpszUserName
, 0, 0, 0))
1428 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1429 MAX_REPLY_LEN
, 0, 0, 0);
1432 /* Login successful... */
1433 if (nResCode
== 230)
1435 /* User name okay, need password... */
1436 else if (nResCode
== 331)
1437 bSuccess
= FTP_SendPassword(lpwfs
);
1438 /* Need account for login... */
1439 else if (nResCode
== 332)
1440 bSuccess
= FTP_SendAccount(lpwfs
);
1442 FTP_SetResponseError(nResCode
);
1445 TRACE("Returning %d\n", bSuccess
);
1451 /***********************************************************************
1452 * FTP_SendCommand (internal)
1454 * Send command to server
1461 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
1462 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1466 DWORD nBytesSent
= 0;
1470 TRACE("%d: (%s) %d\n", ftpCmd
, lpszParam
, nSocket
);
1473 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
1475 bParamHasLen
= lpszParam
&& strlen(lpszParam
) > 0;
1476 len
= (bParamHasLen
? strlen(lpszParam
) : -1) + strlen(szFtpCommands
[ftpCmd
]) +
1478 if (NULL
== (buf
= HeapAlloc(GetProcessHeap(), 0, len
+1)))
1480 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1483 sprintf(buf
, "%s%s%s%s", szFtpCommands
[ftpCmd
], bParamHasLen
? " " : "",
1484 bParamHasLen
? lpszParam
: "", szCRLF
);
1486 TRACE("Sending (%s) len(%ld)\n", buf
, len
);
1487 while((nBytesSent
< len
) && (nRC
!= SOCKET_ERROR
))
1489 nRC
= send(nSocket
, buf
+nBytesSent
, len
- nBytesSent
, 0);
1493 HeapFree(GetProcessHeap(), 0, (LPVOID
)buf
);
1496 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_REQUEST_SENT
,
1497 &nBytesSent
, sizeof(DWORD
));
1499 TRACE("Sent %ld bytes\n", nBytesSent
);
1500 return (nRC
!= SOCKET_ERROR
);
1504 /***********************************************************************
1505 * FTP_ReceiveResponse (internal)
1507 * Receive response from server
1510 * Reply code on success
1515 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
1516 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
)
1520 char firstprefix
[5];
1521 BOOL multiline
= FALSE
;
1524 TRACE("socket(%d) \n", nSocket
);
1527 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
1532 if (!INTERNET_GetNextLine(nSocket
, lpszResponse
, &nRecv
))
1539 if(lpszResponse
[3] != '-')
1542 { /* Start of multiline repsonse. Loop until we get "nnn " */
1544 memcpy(firstprefix
, lpszResponse
, 3);
1545 firstprefix
[3] = ' ';
1546 firstprefix
[4] = '\0';
1551 if(!memcmp(firstprefix
, lpszResponse
, 4))
1559 lpszResponse
[nRecv
] = '\0';
1560 rc
= atoi(lpszResponse
);
1563 lpfnStatusCB(hHandle
, dwContext
, INTERNET_STATUS_RESPONSE_RECEIVED
,
1564 &nRecv
, sizeof(DWORD
));
1568 TRACE("return %d\n", rc
);
1573 /***********************************************************************
1574 * FTP_SendPassword (internal)
1576 * Send password to ftp server
1583 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
)
1586 BOOL bSuccess
= FALSE
;
1589 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASS
, lpwfs
->lpszPassword
, 0, 0, 0))
1592 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1593 MAX_REPLY_LEN
, 0, 0, 0);
1596 TRACE("Received reply code %d\n", nResCode
);
1597 /* Login successful... */
1598 if (nResCode
== 230)
1600 /* Command not implemented, superfluous at the server site... */
1601 /* Need account for login... */
1602 else if (nResCode
== 332)
1603 bSuccess
= FTP_SendAccount(lpwfs
);
1605 FTP_SetResponseError(nResCode
);
1609 TRACE("Returning %d\n", bSuccess
);
1614 /***********************************************************************
1615 * FTP_SendAccount (internal)
1624 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
)
1627 BOOL bSuccess
= FALSE
;
1630 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_ACCT
, NOACCOUNT
, 0, 0, 0))
1633 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1634 MAX_REPLY_LEN
, 0, 0, 0);
1638 FTP_SetResponseError(nResCode
);
1645 /***********************************************************************
1646 * FTP_SendStore (internal)
1648 * Send request to upload file to ftp server
1655 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
1658 BOOL bSuccess
= FALSE
;
1661 if (!FTP_InitListenSocket(lpwfs
))
1664 if (!FTP_SendType(lpwfs
, dwType
))
1667 if (!FTP_SendPortOrPasv(lpwfs
))
1670 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_STOR
, lpszRemoteFile
, 0, 0, 0))
1672 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1673 MAX_REPLY_LEN
, 0, 0, 0);
1676 if (nResCode
== 150)
1679 FTP_SetResponseError(nResCode
);
1683 if (!bSuccess
&& INVALID_SOCKET
!= lpwfs
->lstnSocket
)
1685 close(lpwfs
->lstnSocket
);
1686 lpwfs
->lstnSocket
= INVALID_SOCKET
;
1693 /***********************************************************************
1694 * FTP_InitListenSocket (internal)
1696 * Create a socket to listen for server response
1703 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
)
1705 BOOL bSuccess
= FALSE
;
1706 size_t namelen
= sizeof(struct sockaddr_in
);
1710 lpwfs
->lstnSocket
= socket(PF_INET
, SOCK_STREAM
, 0);
1711 if (INVALID_SOCKET
== lpwfs
->lstnSocket
)
1713 TRACE("Unable to create listening socket\n");
1717 /* We obtain our ip addr from the name of the command channel socket */
1718 lpwfs
->lstnSocketAddress
= lpwfs
->socketAddress
;
1720 /* and get the system to assign us a port */
1721 lpwfs
->lstnSocketAddress
.sin_port
= htons((u_short
) 0);
1723 if (SOCKET_ERROR
== bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)))
1725 TRACE("Unable to bind socket\n");
1729 if (SOCKET_ERROR
== listen(lpwfs
->lstnSocket
, MAX_BACKLOG
))
1731 TRACE("listen failed\n");
1735 if (SOCKET_ERROR
!= getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
))
1739 if (!bSuccess
&& INVALID_SOCKET
== lpwfs
->lstnSocket
)
1741 close(lpwfs
->lstnSocket
);
1742 lpwfs
->lstnSocket
= INVALID_SOCKET
;
1749 /***********************************************************************
1750 * FTP_SendType (internal)
1752 * Tell server type of data being transfered
1758 * W98SE doesn't cache the type that's currently set
1759 * (i.e. it sends it always),
1760 * so we probably don't want to do that either.
1762 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
)
1765 CHAR type
[2] = { "I\0" };
1766 BOOL bSuccess
= FALSE
;
1769 if (dwType
& INTERNET_FLAG_TRANSFER_ASCII
)
1772 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_TYPE
, type
, 0, 0, 0))
1775 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1776 MAX_REPLY_LEN
, 0, 0, 0)/100;
1782 FTP_SetResponseError(nResCode
);
1790 /***********************************************************************
1791 * FTP_SendPort (internal)
1793 * Tell server which port to use
1800 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
)
1803 CHAR szIPAddress
[64];
1804 BOOL bSuccess
= FALSE
;
1807 sprintf(szIPAddress
, "%d,%d,%d,%d,%d,%d",
1808 lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x000000FF,
1809 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x0000FF00)>>8,
1810 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0x00FF0000)>>16,
1811 (lpwfs
->lstnSocketAddress
.sin_addr
.s_addr
&0xFF000000)>>24,
1812 lpwfs
->lstnSocketAddress
.sin_port
& 0xFF,
1813 (lpwfs
->lstnSocketAddress
.sin_port
& 0xFF00)>>8);
1815 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PORT
, szIPAddress
, 0, 0, 0))
1818 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1819 MAX_REPLY_LEN
,0, 0, 0);
1822 if (nResCode
== 200)
1825 FTP_SetResponseError(nResCode
);
1833 /***********************************************************************
1834 * FTP_DoPassive (internal)
1836 * Tell server that we want to do passive transfers
1837 * and connect data socket
1844 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
)
1847 BOOL bSuccess
= FALSE
;
1850 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PASV
, NULL
, 0, 0, 0))
1853 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1854 MAX_REPLY_LEN
,0, 0, 0);
1857 if (nResCode
== 227)
1859 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
1863 char *pAddr
, *pPort
;
1864 INT nsocket
= INVALID_SOCKET
;
1865 struct sockaddr_in dataSocketAddress
;
1867 p
= lpszResponseBuffer
+4; /* skip status code */
1869 /* do a very strict check; we can improve that later. */
1871 if (strncmp(p
, "Entering Passive Mode", 21))
1873 ERR("unknown response '%.*s', aborting\n", 21, p
);
1876 p
+= 21; /* skip string */
1877 if ((*p
++ != ' ') || (*p
++ != '('))
1879 ERR("unknown response format, aborting\n");
1883 if (sscanf(p
, "%d,%d,%d,%d,%d,%d", &f
[0], &f
[1], &f
[2], &f
[3],
1886 ERR("unknown response address format '%s', aborting\n", p
);
1889 for (i
=0; i
< 6; i
++)
1892 dataSocketAddress
= lpwfs
->socketAddress
;
1893 pAddr
= (char *)&(dataSocketAddress
.sin_addr
.s_addr
);
1894 pPort
= (char *)&(dataSocketAddress
.sin_port
);
1902 if (INVALID_SOCKET
== (nsocket
= socket(AF_INET
,SOCK_STREAM
,0)))
1905 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
1907 ERR("can't connect passive FTP data port.\n");
1910 lpwfs
->pasvSocket
= nsocket
;
1914 FTP_SetResponseError(nResCode
);
1922 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
)
1924 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
1926 if (!FTP_DoPassive(lpwfs
))
1931 if (!FTP_SendPort(lpwfs
))
1938 /***********************************************************************
1939 * FTP_GetDataSocket (internal)
1941 * Either accepts an incoming data socket connection from the server
1942 * or just returns the already opened socket after a PASV command
1943 * in case of passive FTP.
1951 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
)
1953 struct sockaddr_in saddr
;
1954 size_t addrlen
= sizeof(struct sockaddr
);
1957 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
1959 *nDataSocket
= lpwfs
->pasvSocket
;
1963 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
1964 close(lpwfs
->lstnSocket
);
1965 lpwfs
->lstnSocket
= INVALID_SOCKET
;
1967 return *nDataSocket
!= INVALID_SOCKET
;
1971 /***********************************************************************
1972 * FTP_SendData (internal)
1974 * Send data to the server
1981 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
)
1983 BY_HANDLE_FILE_INFORMATION fi
;
1984 DWORD nBytesRead
= 0;
1985 DWORD nBytesSent
= 0;
1986 DWORD nTotalSent
= 0;
1987 DWORD nBytesToSend
, nLen
, nRC
= 1;
1988 time_t s_long_time
, e_long_time
;
1993 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
1994 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
1996 /* Get the size of the file. */
1997 GetFileInformationByHandle(hFile
, &fi
);
2002 nBytesToSend
= nBytesRead
- nBytesSent
;
2004 if (nBytesToSend
<= 0)
2006 /* Read data from file. */
2008 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2009 ERR("Failed reading from file\n");
2012 nBytesToSend
= nBytesRead
;
2017 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2018 DATA_PACKET_SIZE
: nBytesToSend
;
2019 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2021 if (nRC
!= SOCKET_ERROR
)
2027 /* Do some computation to display the status. */
2029 nSeconds
= e_long_time
- s_long_time
;
2030 if( nSeconds
/ 60 > 0 )
2032 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2033 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2034 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2038 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2039 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2040 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2042 } while (nRC
!= SOCKET_ERROR
);
2044 TRACE("file transfer complete!\n");
2046 if(lpszBuffer
!= NULL
)
2047 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2053 /***********************************************************************
2054 * FTP_SendRetrieve (internal)
2056 * Send request to retrieve a file
2059 * Number of bytes to be received on success
2063 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
2069 if (!FTP_InitListenSocket(lpwfs
))
2072 if (!FTP_SendType(lpwfs
, dwType
))
2075 if (!FTP_SendPortOrPasv(lpwfs
))
2078 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2081 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2082 MAX_REPLY_LEN
, 0, 0, 0);
2085 if (nResCode
== 125 || nResCode
== 150)
2087 /* Parse size of data to be retrieved */
2088 INT i
, sizepos
= -1;
2089 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2090 for (i
= strlen(lpszResponseBuffer
) - 1; i
>= 0; i
--)
2092 if ('(' == lpszResponseBuffer
[i
])
2101 nResult
= atol(&lpszResponseBuffer
[sizepos
+1]);
2102 TRACE("Waiting to receive %ld bytes\n", nResult
);
2108 if (0 == nResult
&& INVALID_SOCKET
!= lpwfs
->lstnSocket
)
2110 close(lpwfs
->lstnSocket
);
2111 lpwfs
->lstnSocket
= INVALID_SOCKET
;
2118 /***********************************************************************
2119 * FTP_RetrieveData (internal)
2121 * Retrieve data from server
2128 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2130 DWORD nBytesWritten
;
2131 DWORD nBytesReceived
= 0;
2137 if (INVALID_HANDLE_VALUE
== hFile
)
2140 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2141 if (NULL
== lpszBuffer
)
2143 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2147 while (nBytesReceived
< nBytes
&& nRC
!= SOCKET_ERROR
)
2149 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2150 if (nRC
!= SOCKET_ERROR
)
2152 /* other side closed socket. */
2155 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2156 nBytesReceived
+= nRC
;
2159 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived
, nBytes
,
2160 nBytesReceived
* 100 / nBytes
);
2163 TRACE("Data transfer complete\n");
2164 if (NULL
!= lpszBuffer
)
2165 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2168 return (nRC
!= SOCKET_ERROR
);
2172 /***********************************************************************
2173 * FTP_CloseSessionHandle (internal)
2175 * Deallocate session handle
2182 BOOL
FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs
)
2184 if (INVALID_SOCKET
!= lpwfs
->sndSocket
)
2185 close(lpwfs
->sndSocket
);
2187 if (INVALID_SOCKET
!= lpwfs
->lstnSocket
)
2188 close(lpwfs
->lstnSocket
);
2190 if (lpwfs
->lpszPassword
)
2191 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2193 if (lpwfs
->lpszUserName
)
2194 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2196 HeapFree(GetProcessHeap(), 0, lpwfs
);
2202 /***********************************************************************
2203 * FTP_CloseSessionHandle (internal)
2205 * Deallocate session handle
2212 BOOL
FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn
)
2218 for (i
= 0; i
< lpwfn
->size
; i
++)
2220 if (NULL
!= lpwfn
->lpafp
[i
].lpszName
)
2221 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2224 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2225 HeapFree(GetProcessHeap(), 0, lpwfn
);
2231 /***********************************************************************
2232 * FTP_ReceiveFileList (internal)
2234 * Read file list from server
2237 * Handle to file list on success
2241 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
2242 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
)
2245 LPFILEPROPERTIESA lpafp
= NULL
;
2246 LPWININETFINDNEXTA lpwfn
= NULL
;
2250 if (FTP_ParseDirectory(lpwfs
, nSocket
, &lpafp
, &dwSize
))
2252 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2254 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFINDNEXTA
));
2257 lpwfn
->hdr
.htype
= WH_HFINDNEXT
;
2258 lpwfn
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)lpwfs
;
2259 lpwfn
->hdr
.dwContext
= dwContext
;
2260 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2261 lpwfn
->size
= dwSize
;
2262 lpwfn
->lpafp
= lpafp
;
2266 TRACE("Matched %ld files\n", dwSize
);
2267 return (HINTERNET
)lpwfn
;
2271 /***********************************************************************
2272 * FTP_ConvertFileProp (internal)
2274 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2281 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp
, LPWIN32_FIND_DATAA lpFindFileData
)
2283 BOOL bSuccess
= FALSE
;
2285 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2289 DWORD access
= mktime(&lpafp
->tmLastModified
);
2291 /* Not all fields are filled in */
2292 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= HIWORD(access
);
2293 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= LOWORD(access
);
2294 lpFindFileData
->nFileSizeHigh
= HIWORD(lpafp
->nSize
);
2295 lpFindFileData
->nFileSizeLow
= LOWORD(lpafp
->nSize
);
2297 if (lpafp
->bIsDirectory
)
2298 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2300 if (lpafp
->lpszName
)
2301 strncpy(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2310 /***********************************************************************
2311 * FTP_ParseDirectory (internal)
2313 * Parse string of directory information
2319 * FIXME: - This function needs serious clea-up
2320 * - We should consider both UNIX and NT list formats
2322 #define MAX_MONTH_LEN 10
2323 #define MIN_LEN_DIR_ENTRY 15
2325 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
)
2328 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2331 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2337 CHAR pszMonth
[MAX_MONTH_LEN
];
2339 BOOL bSuccess
= TRUE
;
2340 DWORD nBufLen
= MAX_REPLY_LEN
;
2341 LPFILEPROPERTIESA curFileProp
= NULL
;
2342 CHAR
* pszLine
= NULL
;
2343 CHAR
* pszToken
= NULL
;
2344 INT nTokenToSkip
= 3;
2352 INT sizeFilePropArray
= 20;
2353 INT indexFilePropArray
= 0;
2357 /* Allocate intial file properties array */
2358 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESA
)*(sizeFilePropArray
));
2365 while ((pszLine
= INTERNET_GetNextLine(nSocket
, INTERNET_GetResponseBuffer(), &nBufLen
)) != NULL
)
2367 if (sizeFilePropArray
<= indexFilePropArray
)
2369 LPFILEPROPERTIESA tmpafp
;
2371 sizeFilePropArray
*= 2;
2372 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
2373 sizeof(FILEPROPERTIESA
)*sizeFilePropArray
);
2383 curFileProp
= &((*lpafp
)[indexFilePropArray
]);
2385 /* First Parse the permissions. */
2386 pszToken
= strtok(pszLine
, " \t" );
2388 /* HACK! If this is not a file listing skip the line */
2389 if (!pszToken
|| 10 != strlen(pszToken
) || nBufLen
<= MIN_LEN_DIR_ENTRY
)
2391 nBufLen
= MAX_REPLY_LEN
;
2395 FTP_ParsePermission(pszToken
, curFileProp
);
2401 pszToken
= strtok( NULL
, " \t" );
2403 } while( nCount
<= nTokenToSkip
);
2405 /* Store the size of the file in the param list. */
2406 TRACE("nSize-> %s\n", pszToken
);
2407 if (pszToken
!= NULL
)
2408 curFileProp
->nSize
= atol(pszToken
);
2410 /* Parse last modified time. */
2418 pszToken
= strtok( NULL
, " \t" );
2419 strncpy(pszMonth
, pszToken
, MAX_MONTH_LEN
);
2420 CharUpperA(pszMonth
);
2421 pszMatch
= strstr(szMonths
, pszMonth
);
2422 if( pszMatch
!= NULL
)
2423 nMonth
= (pszMatch
- szMonths
) / 3;
2425 pszToken
= strtok(NULL
, " \t");
2426 TRACE("nDay -> %s\n", pszToken
);
2427 if (pszToken
!= NULL
)
2428 nDay
= atoi(pszToken
);
2430 pszToken
= strtok(NULL
, " \t");
2431 pszMinutes
= strchr(pszToken
, ':');
2432 if( pszMinutes
!= NULL
)
2435 nMinutes
= atoi(pszMinutes
);
2436 pszHour
= pszMinutes
- 3;
2437 if (pszHour
!= NULL
)
2438 nHour
= atoi(pszHour
);
2440 apTM
= localtime( &aTime
);
2441 nYear
= apTM
->tm_year
;
2445 nYear
= atoi(pszToken
);
2450 curFileProp
->tmLastModified
.tm_sec
= nSeconds
;
2451 curFileProp
->tmLastModified
.tm_min
= nMinutes
;
2452 curFileProp
->tmLastModified
.tm_hour
= nHour
;
2453 curFileProp
->tmLastModified
.tm_mday
= nDay
;
2454 curFileProp
->tmLastModified
.tm_mon
= nMonth
;
2455 curFileProp
->tmLastModified
.tm_year
= nYear
;
2457 pszToken
= strtok(NULL
, " \t");
2458 if(pszToken
!= NULL
)
2460 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2461 TRACE(": %s\n", curFileProp
->lpszName
);
2464 nBufLen
= MAX_REPLY_LEN
;
2465 indexFilePropArray
++;
2468 if (bSuccess
&& indexFilePropArray
)
2470 if (indexFilePropArray
< sizeFilePropArray
- 1)
2472 LPFILEPROPERTIESA tmpafp
;
2474 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
2475 sizeof(FILEPROPERTIESA
)*indexFilePropArray
);
2479 *dwfp
= indexFilePropArray
;
2483 HeapFree(GetProcessHeap(), 0, *lpafp
);
2484 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2493 /***********************************************************************
2494 * FTP_ParsePermission (internal)
2496 * Parse permission string of directory information
2503 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
)
2505 BOOL bSuccess
= TRUE
;
2506 unsigned short nPermission
= 0;
2511 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
2517 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
2523 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
2526 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
2529 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
2532 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
2535 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
2538 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
2541 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
2544 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
2547 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
2551 }while (nPos
<= nLast
);
2553 lpfp
->permissions
= nPermission
;
2558 /***********************************************************************
2559 * FTP_SetResponseError (internal)
2561 * Set the appropriate error code for a given response from the server
2566 DWORD
FTP_SetResponseError(DWORD dwResponse
)
2572 case 421: /* Service not available - Server may be shutting down. */
2573 dwCode
= ERROR_INTERNET_TIMEOUT
;
2576 case 425: /* Cannot open data connection. */
2577 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
2580 case 426: /* Connection closed, transer aborted. */
2581 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
2584 case 500: /* Syntax error. Command unrecognized. */
2585 case 501: /* Syntax error. Error in parameters or arguments. */
2586 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
2589 case 530: /* Not logged in. Login incorrect. */
2590 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
2593 case 550: /* File action not taken. File not found or no access. */
2594 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
2597 case 450: /* File action not taken. File may be busy. */
2598 case 451: /* Action aborted. Server error. */
2599 case 452: /* Action not taken. Insufficient storage space on server. */
2600 case 502: /* Command not implemented. */
2601 case 503: /* Bad sequence of command. */
2602 case 504: /* Command not implemented for that parameter. */
2603 case 532: /* Need account for storing files */
2604 case 551: /* Requested action aborted. Page type unknown */
2605 case 552: /* Action aborted. Exceeded storage allocation */
2606 case 553: /* Action not taken. File name not allowed. */
2609 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
2613 INTERNET_SetLastError(dwCode
);