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>
28 #ifdef HAVE_NETINET_IN_SYSTM_H
29 # include <netinet/in_systm.h>
31 #ifdef HAVE_NETINET_IN_H
32 # include <netinet/in.h>
34 #ifdef HAVE_NETINET_IP_H
35 # include <netinet/ip.h>
46 #include "debugtools.h"
49 DEFAULT_DEBUG_CHANNEL(wininet
);
51 #define NOACCOUNT "noaccount"
52 #define DATA_PACKET_SIZE 0x2000
57 /* FTP commands with arguments. */
72 /* FTP commands without arguments. */
81 static const CHAR
*szFtpCommands
[] = {
103 static const CHAR szMonths
[] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC";
105 BOOL
FTP_SendCommand(INT nSocket
, FTP_COMMAND ftpCmd
, LPCSTR lpszParam
,
106 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
);
107 BOOL
FTP_SendStore(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
);
108 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
);
109 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
);
110 INT
FTP_ReceiveResponse(INT nSocket
, LPSTR lpszResponse
, DWORD dwResponse
,
111 INTERNET_STATUS_CALLBACK lpfnStatusCB
, HINTERNET hHandle
, DWORD dwContext
);
112 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
);
113 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
);
114 BOOL
FTP_InitListenSocket(LPWININETFTPSESSIONA lpwfs
);
115 BOOL
FTP_ConnectToHost(LPWININETFTPSESSIONA lpwfs
);
116 BOOL
FTP_SendPassword(LPWININETFTPSESSIONA lpwfs
);
117 BOOL
FTP_SendAccount(LPWININETFTPSESSIONA lpwfs
);
118 BOOL
FTP_SendType(LPWININETFTPSESSIONA lpwfs
, DWORD dwType
);
119 BOOL
FTP_SendPort(LPWININETFTPSESSIONA lpwfs
);
120 BOOL
FTP_DoPassive(LPWININETFTPSESSIONA lpwfs
);
121 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
);
122 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
);
123 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
);
124 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
125 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
);
126 DWORD
FTP_SetResponseError(DWORD dwResponse
);
128 inline static LPSTR
FTP_strdup( LPCSTR str
)
130 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, strlen(str
) + 1 );
131 if (ret
) strcpy( ret
, str
);
135 /***********************************************************************
136 * FtpPutFileA (WININET.43)
138 * Uploads a file to the FTP server
145 BOOL WINAPI
FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
146 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
148 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
149 LPWININETAPPINFOA hIC
= NULL
;
151 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
153 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
157 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
158 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
160 WORKREQUEST workRequest
;
162 workRequest
.asyncall
= FTPPUTFILEA
;
163 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
164 workRequest
.LPSZLOCALFILE
= (DWORD
)FTP_strdup(lpszLocalFile
);
165 workRequest
.LPSZNEWREMOTEFILE
= (DWORD
)FTP_strdup(lpszNewRemoteFile
);
166 workRequest
.DWFLAGS
= dwFlags
;
167 workRequest
.DWCONTEXT
= dwContext
;
169 return INTERNET_AsyncCall(&workRequest
);
173 return FTP_FtpPutFileA(hConnect
, lpszLocalFile
,
174 lpszNewRemoteFile
, dwFlags
, dwContext
);
178 /***********************************************************************
179 * FTP_FtpPutFileA (Internal)
181 * Uploads a file to the FTP server
188 BOOL WINAPI
FTP_FtpPutFileA(HINTERNET hConnect
, LPCSTR lpszLocalFile
,
189 LPCSTR lpszNewRemoteFile
, DWORD dwFlags
, DWORD dwContext
)
191 HANDLE hFile
= (HANDLE
)NULL
;
192 BOOL bSuccess
= FALSE
;
193 LPWININETAPPINFOA hIC
= NULL
;
194 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
197 TRACE(" lpszLocalFile(%s) lpszNewRemoteFile(%s)\n", lpszLocalFile
, lpszNewRemoteFile
);
198 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
200 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
204 /* Clear any error information */
205 INTERNET_SetLastError(0);
207 /* Open file to be uploaded */
208 if (INVALID_HANDLE_VALUE
==
209 (hFile
= CreateFileA(lpszLocalFile
, GENERIC_READ
, 0, 0, OPEN_EXISTING
, 0, 0)))
211 INTERNET_SetLastError(ERROR_FILE_NOT_FOUND
);
215 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
216 if (hIC
->lpfnStatusCB
)
217 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
219 if (FTP_SendStore(lpwfs
, lpszNewRemoteFile
, dwFlags
))
223 /* Get data socket to server */
224 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
226 FTP_SendData(lpwfs
, nDataSocket
, hFile
);
228 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
229 MAX_REPLY_LEN
, 0, 0, 0);
235 FTP_SetResponseError(nResCode
);
241 if (lpwfs
->lstnSocket
!= INVALID_SOCKET
)
242 close(lpwfs
->lstnSocket
);
244 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
246 INTERNET_ASYNC_RESULT iar
;
248 iar
.dwResult
= (DWORD
)bSuccess
;
249 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
250 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
251 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
261 /***********************************************************************
262 * FtpSetCurrentDirectoryA (WININET.49)
264 * Change the working directory on the FTP server
271 BOOL WINAPI
FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
273 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
274 LPWININETAPPINFOA hIC
= NULL
;
276 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
278 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
282 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
284 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
285 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
287 WORKREQUEST workRequest
;
289 workRequest
.asyncall
= FTPSETCURRENTDIRECTORYA
;
290 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
291 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
293 return INTERNET_AsyncCall(&workRequest
);
297 return FTP_FtpSetCurrentDirectoryA(hConnect
, lpszDirectory
);
302 /***********************************************************************
303 * FTP_FtpSetCurrentDirectoryA (Internal)
305 * Change the working directory on the FTP server
312 BOOL WINAPI
FTP_FtpSetCurrentDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
315 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
316 LPWININETAPPINFOA hIC
= NULL
;
317 DWORD bSuccess
= FALSE
;
319 TRACE("lpszDirectory(%s)\n", lpszDirectory
);
321 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
323 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
327 /* Clear any error information */
328 INTERNET_SetLastError(0);
330 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
331 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_CWD
, lpszDirectory
,
332 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
335 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
336 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
343 FTP_SetResponseError(nResCode
);
347 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
349 INTERNET_ASYNC_RESULT iar
;
351 iar
.dwResult
= (DWORD
)bSuccess
;
352 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
353 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
354 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
360 /***********************************************************************
361 * FtpCreateDirectoryA (WININET.31)
363 * Create new directory on the FTP server
370 BOOL WINAPI
FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
372 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
373 LPWININETAPPINFOA hIC
= NULL
;
375 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
377 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
381 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
382 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
384 WORKREQUEST workRequest
;
386 workRequest
.asyncall
= FTPCREATEDIRECTORYA
;
387 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
388 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
390 return INTERNET_AsyncCall(&workRequest
);
394 return FTP_FtpCreateDirectoryA(hConnect
, lpszDirectory
);
399 /***********************************************************************
400 * FTP_FtpCreateDirectoryA (Internal)
402 * Create new directory on the FTP server
409 BOOL WINAPI
FTP_FtpCreateDirectoryA(HINTERNET hConnect
, LPCSTR lpszDirectory
)
412 BOOL bSuccess
= FALSE
;
413 LPWININETAPPINFOA hIC
= NULL
;
414 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
417 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
419 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
423 /* Clear any error information */
424 INTERNET_SetLastError(0);
426 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_MKD
, lpszDirectory
, 0, 0, 0))
429 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
430 MAX_REPLY_LEN
, 0, 0, 0);
436 FTP_SetResponseError(nResCode
);
440 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
441 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
443 INTERNET_ASYNC_RESULT iar
;
445 iar
.dwResult
= (DWORD
)bSuccess
;
446 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
447 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
448 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
455 /***********************************************************************
456 * FtpFindFirstFileA (WININET.35)
458 * Search the specified directory
461 * HINTERNET on success
465 INTERNETAPI HINTERNET WINAPI
FtpFindFirstFileA(HINTERNET hConnect
,
466 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
468 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
469 LPWININETAPPINFOA hIC
= NULL
;
471 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
473 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
477 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
478 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
480 WORKREQUEST workRequest
;
482 workRequest
.asyncall
= FTPFINDFIRSTFILEA
;
483 workRequest
.HFTPSESSION
= (DWORD
)hConnect
;
484 workRequest
.LPSZSEARCHFILE
= (DWORD
)FTP_strdup(lpszSearchFile
);
485 workRequest
.LPFINDFILEDATA
= (DWORD
)lpFindFileData
;
486 workRequest
.DWFLAGS
= dwFlags
;
487 workRequest
.DWCONTEXT
= dwContext
;
489 INTERNET_AsyncCall(&workRequest
);
494 return FTP_FtpFindFirstFileA(hConnect
, lpszSearchFile
, lpFindFileData
,
500 /***********************************************************************
501 * FTP_FtpFindFirstFileA (Internal)
503 * Search the specified directory
506 * HINTERNET on success
510 INTERNETAPI HINTERNET WINAPI
FTP_FtpFindFirstFileA(HINTERNET hConnect
,
511 LPCSTR lpszSearchFile
, LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwFlags
, DWORD dwContext
)
514 LPWININETAPPINFOA hIC
= NULL
;
515 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hConnect
;
516 LPWININETFINDNEXTA hFindNext
= NULL
;
520 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
522 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
526 /* Clear any error information */
527 INTERNET_SetLastError(0);
529 if (!FTP_InitListenSocket(lpwfs
))
532 if (!FTP_SendType(lpwfs
, INTERNET_FLAG_TRANSFER_ASCII
))
535 if (!FTP_SendPortOrPasv(lpwfs
))
538 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
539 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_LIST
, lpszSearchFile
,
540 hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
))
543 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
544 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
547 if (nResCode
== 125 || nResCode
== 150)
551 /* Get data socket to server */
552 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
554 hFindNext
= FTP_ReceiveFileList(lpwfs
, nDataSocket
, lpFindFileData
, dwContext
);
556 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
557 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hConnect
, lpwfs
->hdr
.dwContext
);
558 if (nResCode
!= 226 && nResCode
!= 250)
559 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
565 FTP_SetResponseError(nResCode
);
569 if (lpwfs
->lstnSocket
!= INVALID_SOCKET
)
570 close(lpwfs
->lstnSocket
);
572 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
574 INTERNET_ASYNC_RESULT iar
;
578 iar
.dwResult
= (DWORD
)hFindNext
;
579 iar
.dwError
= ERROR_SUCCESS
;
580 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
581 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
584 iar
.dwResult
= (DWORD
)hFindNext
;
585 iar
.dwError
= hFindNext
? ERROR_SUCCESS
: INTERNET_GetLastError();
586 hIC
->lpfnStatusCB(hConnect
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
587 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
590 return (HINTERNET
)hFindNext
;
594 /***********************************************************************
595 * FtpGetCurrentDirectoryA (WININET.37)
597 * Retrieves the current directory
604 BOOL WINAPI
FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
605 LPDWORD lpdwCurrentDirectory
)
607 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
608 LPWININETAPPINFOA hIC
= NULL
;
610 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
612 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
614 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
618 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
619 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
621 WORKREQUEST workRequest
;
623 workRequest
.asyncall
= FTPGETCURRENTDIRECTORYA
;
624 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
625 workRequest
.LPSZDIRECTORY
= (DWORD
)lpszCurrentDirectory
;
626 workRequest
.LPDWDIRECTORY
= (DWORD
)lpdwCurrentDirectory
;
628 return INTERNET_AsyncCall(&workRequest
);
632 return FTP_FtpGetCurrentDirectoryA(hFtpSession
, lpszCurrentDirectory
,
633 lpdwCurrentDirectory
);
638 /***********************************************************************
639 * FTP_FtpGetCurrentDirectoryA (Internal)
641 * Retrieves the current directory
648 BOOL WINAPI
FTP_FtpGetCurrentDirectoryA(HINTERNET hFtpSession
, LPSTR lpszCurrentDirectory
,
649 LPDWORD lpdwCurrentDirectory
)
652 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
653 LPWININETAPPINFOA hIC
= NULL
;
654 DWORD bSuccess
= FALSE
;
656 TRACE("len(%ld)\n", *lpdwCurrentDirectory
);
658 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
660 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
664 /* Clear any error information */
665 INTERNET_SetLastError(0);
667 ZeroMemory(lpszCurrentDirectory
, *lpdwCurrentDirectory
);
669 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
670 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_PWD
, NULL
,
671 hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
))
674 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
675 MAX_REPLY_LEN
, hIC
->lpfnStatusCB
, hFtpSession
, lpwfs
->hdr
.dwContext
);
678 if (nResCode
== 257) /* Extract directory name */
680 INT firstpos
, lastpos
, len
;
681 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
683 for (firstpos
= 0, lastpos
= 0; lpszResponseBuffer
[lastpos
]; lastpos
++)
685 if ('"' == lpszResponseBuffer
[lastpos
])
694 len
= lastpos
- firstpos
- 1;
695 strncpy(lpszCurrentDirectory
, &lpszResponseBuffer
[firstpos
+1],
696 len
< *lpdwCurrentDirectory
? len
: *lpdwCurrentDirectory
);
697 *lpdwCurrentDirectory
= len
;
701 FTP_SetResponseError(nResCode
);
705 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
707 INTERNET_ASYNC_RESULT iar
;
709 iar
.dwResult
= (DWORD
)bSuccess
;
710 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: ERROR_INTERNET_EXTENDED_ERROR
;
711 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
712 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
715 return (DWORD
) bSuccess
;
718 /***********************************************************************
719 * FtpOpenFileA (WININET.41)
721 * Open a remote file for writing or reading
724 * HINTERNET handle on success
728 INTERNETAPI HINTERNET WINAPI
FtpOpenFileA(HINTERNET hFtpSession
,
729 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
732 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
733 LPWININETAPPINFOA hIC
= NULL
;
735 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
737 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
741 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
742 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
744 WORKREQUEST workRequest
;
746 workRequest
.asyncall
= FTPOPENFILEA
;
747 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
748 workRequest
.LPSZFILENAME
= (DWORD
)FTP_strdup(lpszFileName
);
749 workRequest
.FDWACCESS
= fdwAccess
;
750 workRequest
.DWFLAGS
= dwFlags
;
751 workRequest
.DWCONTEXT
= dwContext
;
753 INTERNET_AsyncCall(&workRequest
);
758 return FTP_FtpOpenFileA(hFtpSession
, lpszFileName
, fdwAccess
, dwFlags
, dwContext
);
763 /***********************************************************************
764 * FTP_FtpOpenFileA (Internal)
766 * Open a remote file for writing or reading
769 * HINTERNET handle on success
773 HINTERNET
FTP_FtpOpenFileA(HINTERNET hFtpSession
,
774 LPCSTR lpszFileName
, DWORD fdwAccess
, DWORD dwFlags
,
778 BOOL bSuccess
= FALSE
;
779 LPWININETFILE hFile
= NULL
;
780 LPWININETAPPINFOA hIC
= NULL
;
781 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
785 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
787 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
791 /* Clear any error information */
792 INTERNET_SetLastError(0);
794 if (GENERIC_READ
== fdwAccess
)
796 /* Set up socket to retrieve data */
797 bSuccess
= FTP_SendRetrieve(lpwfs
, lpszFileName
, dwFlags
);
799 else if (GENERIC_WRITE
== fdwAccess
)
801 /* Set up socket to send data */
802 bSuccess
= FTP_SendStore(lpwfs
, lpszFileName
, dwFlags
);
805 /* Get data socket to server */
806 if (bSuccess
&& FTP_GetDataSocket(lpwfs
, &nDataSocket
))
808 hFile
= HeapAlloc(GetProcessHeap(), 0, sizeof(WININETFILE
));
809 hFile
->hdr
.htype
= WH_HFILE
;
810 hFile
->hdr
.dwFlags
= dwFlags
;
811 hFile
->hdr
.dwContext
= dwContext
;
812 hFile
->hdr
.lpwhparent
= hFtpSession
;
813 hFile
->nDataSocket
= nDataSocket
;
816 if (lpwfs
->lstnSocket
!= INVALID_SOCKET
)
817 close(lpwfs
->lstnSocket
);
819 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
820 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
822 INTERNET_ASYNC_RESULT iar
;
826 iar
.dwResult
= (DWORD
)hFile
;
827 iar
.dwError
= ERROR_SUCCESS
;
828 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
829 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
832 iar
.dwResult
= (DWORD
)bSuccess
;
833 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
834 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
835 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
838 return (HINTERNET
)hFile
;
842 /***********************************************************************
843 * FtpGetFileA (WININET.39)
845 * Retrieve file from the FTP server
852 BOOL WINAPI
FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
853 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
856 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hInternet
;
857 LPWININETAPPINFOA hIC
= NULL
;
859 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
861 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
865 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
866 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
868 WORKREQUEST workRequest
;
870 workRequest
.asyncall
= FTPGETFILEA
;
871 workRequest
.HFTPSESSION
= (DWORD
)hInternet
;
872 workRequest
.LPSZREMOTEFILE
= (DWORD
)FTP_strdup(lpszRemoteFile
);
873 workRequest
.LPSZNEWFILE
= (DWORD
)FTP_strdup(lpszNewFile
);
874 workRequest
.DWLOCALFLAGSATTRIBUTE
= dwLocalFlagsAttribute
;
875 workRequest
.FFAILIFEXISTS
= (DWORD
)fFailIfExists
;
876 workRequest
.DWFLAGS
= dwInternetFlags
;
877 workRequest
.DWCONTEXT
= dwContext
;
879 return INTERNET_AsyncCall(&workRequest
);
883 return FTP_FtpGetFileA(hInternet
, lpszRemoteFile
, lpszNewFile
,
884 fFailIfExists
, dwLocalFlagsAttribute
, dwInternetFlags
, dwContext
);
889 /***********************************************************************
890 * FTP_FtpGetFileA (Internal)
892 * Retrieve file from the FTP server
899 BOOL WINAPI
FTP_FtpGetFileA(HINTERNET hInternet
, LPCSTR lpszRemoteFile
, LPCSTR lpszNewFile
,
900 BOOL fFailIfExists
, DWORD dwLocalFlagsAttribute
, DWORD dwInternetFlags
,
904 BOOL bSuccess
= FALSE
;
906 LPWININETAPPINFOA hIC
= NULL
;
907 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hInternet
;
909 TRACE("lpszRemoteFile(%s) lpszNewFile(%s)\n", lpszRemoteFile
, lpszNewFile
);
910 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
912 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
916 /* Clear any error information */
917 INTERNET_SetLastError(0);
919 /* Ensure we can write to lpszNewfile by opening it */
920 hFile
= CreateFileA(lpszNewFile
, GENERIC_WRITE
, 0, 0, fFailIfExists
?
921 CREATE_NEW
: CREATE_ALWAYS
, dwLocalFlagsAttribute
, 0);
922 if (INVALID_HANDLE_VALUE
== hFile
)
925 /* Set up socket to retrieve data */
926 nBytes
= FTP_SendRetrieve(lpwfs
, lpszRemoteFile
, dwInternetFlags
);
932 /* Get data socket to server */
933 if (FTP_GetDataSocket(lpwfs
, &nDataSocket
))
938 FTP_RetrieveFileData(lpwfs
, nDataSocket
, nBytes
, hFile
);
939 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
940 MAX_REPLY_LEN
, 0, 0, 0);
946 FTP_SetResponseError(nResCode
);
953 if (lpwfs
->lstnSocket
!= INVALID_SOCKET
)
954 close(lpwfs
->lstnSocket
);
959 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
960 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
962 INTERNET_ASYNC_RESULT iar
;
964 iar
.dwResult
= (DWORD
)bSuccess
;
965 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
966 hIC
->lpfnStatusCB(hInternet
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
967 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
974 /***********************************************************************
975 * FtpDeleteFileA (WININET.33)
977 * Delete a file on the ftp server
984 BOOL WINAPI
FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
986 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
987 LPWININETAPPINFOA hIC
= NULL
;
989 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
991 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
995 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
996 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
998 WORKREQUEST workRequest
;
1000 workRequest
.asyncall
= FTPRENAMEFILEA
;
1001 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1002 workRequest
.LPSZFILENAME
= (DWORD
)FTP_strdup(lpszFileName
);
1004 return INTERNET_AsyncCall(&workRequest
);
1008 return FTP_FtpDeleteFileA(hFtpSession
, lpszFileName
);
1013 /***********************************************************************
1014 * FTP_FtpDeleteFileA (Internal)
1016 * Delete a file on the ftp server
1023 BOOL
FTP_FtpDeleteFileA(HINTERNET hFtpSession
, LPCSTR lpszFileName
)
1026 BOOL bSuccess
= FALSE
;
1027 LPWININETAPPINFOA hIC
= NULL
;
1028 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1030 TRACE("0x%08lx\n", (ULONG
) hFtpSession
);
1031 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1033 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1037 /* Clear any error information */
1038 INTERNET_SetLastError(0);
1040 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_DELE
, lpszFileName
, 0, 0, 0))
1043 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1044 MAX_REPLY_LEN
, 0, 0, 0);
1047 if (nResCode
== 250)
1050 FTP_SetResponseError(nResCode
);
1053 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1054 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1056 INTERNET_ASYNC_RESULT iar
;
1058 iar
.dwResult
= (DWORD
)bSuccess
;
1059 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1060 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1061 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1068 /***********************************************************************
1069 * FtpRemoveDirectoryA (WININET.45)
1071 * Remove a directory on the ftp server
1078 BOOL WINAPI
FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1080 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1081 LPWININETAPPINFOA hIC
= NULL
;
1083 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1085 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1089 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1090 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1092 WORKREQUEST workRequest
;
1094 workRequest
.asyncall
= FTPREMOVEDIRECTORYA
;
1095 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1096 workRequest
.LPSZDIRECTORY
= (DWORD
)FTP_strdup(lpszDirectory
);
1098 return INTERNET_AsyncCall(&workRequest
);
1102 return FTP_FtpRemoveDirectoryA(hFtpSession
, lpszDirectory
);
1107 /***********************************************************************
1108 * FTP_FtpRemoveDirectoryA (Internal)
1110 * Remove a directory on the ftp server
1117 BOOL
FTP_FtpRemoveDirectoryA(HINTERNET hFtpSession
, LPCSTR lpszDirectory
)
1120 BOOL bSuccess
= FALSE
;
1121 LPWININETAPPINFOA hIC
= NULL
;
1122 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1125 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1127 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1131 /* Clear any error information */
1132 INTERNET_SetLastError(0);
1134 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RMD
, lpszDirectory
, 0, 0, 0))
1137 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
1138 MAX_REPLY_LEN
, 0, 0, 0);
1141 if (nResCode
== 250)
1144 FTP_SetResponseError(nResCode
);
1148 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1149 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1151 INTERNET_ASYNC_RESULT iar
;
1153 iar
.dwResult
= (DWORD
)bSuccess
;
1154 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1155 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1156 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1163 /***********************************************************************
1164 * FtpRenameFileA (WININET.47)
1166 * Rename a file on the ftp server
1173 BOOL WINAPI
FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1175 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1176 LPWININETAPPINFOA hIC
= NULL
;
1178 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1180 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1184 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1185 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
1187 WORKREQUEST workRequest
;
1189 workRequest
.asyncall
= FTPRENAMEFILEA
;
1190 workRequest
.HFTPSESSION
= (DWORD
)hFtpSession
;
1191 workRequest
.LPSZSRCFILE
= (DWORD
)FTP_strdup(lpszSrc
);
1192 workRequest
.LPSZDESTFILE
= (DWORD
)FTP_strdup(lpszDest
);
1194 return INTERNET_AsyncCall(&workRequest
);
1198 return FTP_FtpRenameFileA(hFtpSession
, lpszSrc
, lpszDest
);
1202 /***********************************************************************
1203 * FTP_FtpRenameFileA (Internal)
1205 * Rename a file on the ftp server
1212 BOOL
FTP_FtpRenameFileA(HINTERNET hFtpSession
, LPCSTR lpszSrc
, LPCSTR lpszDest
)
1215 BOOL bSuccess
= FALSE
;
1216 LPWININETAPPINFOA hIC
= NULL
;
1217 LPWININETFTPSESSIONA lpwfs
= (LPWININETFTPSESSIONA
) hFtpSession
;
1220 if (NULL
== lpwfs
|| WH_HFTPSESSION
!= lpwfs
->hdr
.htype
)
1222 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
1226 /* Clear any error information */
1227 INTERNET_SetLastError(0);
1229 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNFR
, lpszSrc
, 0, 0, 0))
1232 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1233 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1234 if (nResCode
== 350)
1236 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RNTO
, lpszDest
, 0, 0, 0))
1239 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
,
1240 INTERNET_GetResponseBuffer(), MAX_REPLY_LEN
, 0, 0, 0);
1243 if (nResCode
== 250)
1246 FTP_SetResponseError(nResCode
);
1249 hIC
= (LPWININETAPPINFOA
) lpwfs
->hdr
.lpwhparent
;
1250 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
1252 INTERNET_ASYNC_RESULT iar
;
1254 iar
.dwResult
= (DWORD
)bSuccess
;
1255 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
1256 hIC
->lpfnStatusCB(hFtpSession
, lpwfs
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
1257 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
1264 /***********************************************************************
1265 * FTP_Connect (internal)
1267 * Connect to a ftp server
1270 * HINTERNET a session handle on success
1275 HINTERNET
FTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
1276 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
1277 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
1279 struct sockaddr_in socketAddr
;
1280 struct hostent
*phe
= NULL
;
1281 INT nsocket
= INVALID_SOCKET
, sock_namelen
;
1282 LPWININETAPPINFOA hIC
= NULL
;
1283 BOOL bSuccess
= FALSE
;
1284 LPWININETFTPSESSIONA lpwfs
= NULL
;
1286 TRACE("0x%08lx Server(%s) Port(%d) User(%s) Paswd(%s)\n",
1287 (ULONG
) hInternet
, lpszServerName
,
1288 nServerPort
, lpszUserName
, lpszPassword
);
1290 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
1293 hIC
= (LPWININETAPPINFOA
) hInternet
;
1295 if (NULL
== lpszUserName
&& NULL
!= lpszPassword
)
1297 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_USER_NAME
);
1301 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
1302 nServerPort
= INTERNET_DEFAULT_FTP_PORT
;
1304 if (hIC
->lpfnStatusCB
)
1305 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
1306 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1308 if (!GetAddress(lpszServerName
, nServerPort
, &phe
, &socketAddr
))
1310 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
1314 if (hIC
->lpfnStatusCB
)
1315 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
1316 (LPSTR
) lpszServerName
, strlen(lpszServerName
));
1318 if (INVALID_SOCKET
== (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
&& INVALID_SOCKET
!= nsocket
)
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
!= SOCKET_ERROR
))
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
);
1501 return (nRC
!= SOCKET_ERROR
);
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
&& INVALID_SOCKET
!= lpwfs
->lstnSocket
)
1686 close(lpwfs
->lstnSocket
);
1687 lpwfs
->lstnSocket
= INVALID_SOCKET
;
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 (INVALID_SOCKET
== lpwfs
->lstnSocket
)
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 (SOCKET_ERROR
== bind(lpwfs
->lstnSocket
,(struct sockaddr
*) &lpwfs
->lstnSocketAddress
, sizeof(struct sockaddr_in
)))
1726 TRACE("Unable to bind socket\n");
1730 if (SOCKET_ERROR
== listen(lpwfs
->lstnSocket
, MAX_BACKLOG
))
1732 TRACE("listen failed\n");
1736 if (SOCKET_ERROR
!= getsockname(lpwfs
->lstnSocket
, (struct sockaddr
*) &lpwfs
->lstnSocketAddress
, &namelen
))
1740 if (!bSuccess
&& INVALID_SOCKET
== lpwfs
->lstnSocket
)
1742 close(lpwfs
->lstnSocket
);
1743 lpwfs
->lstnSocket
= INVALID_SOCKET
;
1750 /***********************************************************************
1751 * FTP_SendType (internal)
1753 * Tell server type of data being transfered
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
;
1865 INT nsocket
= INVALID_SOCKET
;
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 if (INVALID_SOCKET
== (nsocket
= socket(AF_INET
,SOCK_STREAM
,0)))
1906 if (connect(nsocket
, (struct sockaddr
*)&dataSocketAddress
, sizeof(dataSocketAddress
)))
1908 ERR("can't connect passive FTP data port.\n");
1911 lpwfs
->pasvSocket
= nsocket
;
1915 FTP_SetResponseError(nResCode
);
1923 BOOL
FTP_SendPortOrPasv(LPWININETFTPSESSIONA lpwfs
)
1925 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
1927 if (!FTP_DoPassive(lpwfs
))
1932 if (!FTP_SendPort(lpwfs
))
1939 /***********************************************************************
1940 * FTP_GetDataSocket (internal)
1942 * Either accepts an incoming data socket connection from the server
1943 * or just returns the already opened socket after a PASV command
1944 * in case of passive FTP.
1952 BOOL
FTP_GetDataSocket(LPWININETFTPSESSIONA lpwfs
, LPINT nDataSocket
)
1954 struct sockaddr_in saddr
;
1955 size_t addrlen
= sizeof(struct sockaddr
);
1958 if (lpwfs
->hdr
.dwFlags
& INTERNET_FLAG_PASSIVE
)
1960 *nDataSocket
= lpwfs
->pasvSocket
;
1964 *nDataSocket
= accept(lpwfs
->lstnSocket
, (struct sockaddr
*) &saddr
, &addrlen
);
1965 close(lpwfs
->lstnSocket
);
1966 lpwfs
->lstnSocket
= INVALID_SOCKET
;
1968 return *nDataSocket
!= INVALID_SOCKET
;
1972 /***********************************************************************
1973 * FTP_SendData (internal)
1975 * Send data to the server
1982 BOOL
FTP_SendData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, HANDLE hFile
)
1984 BY_HANDLE_FILE_INFORMATION fi
;
1985 DWORD nBytesRead
= 0;
1986 DWORD nBytesSent
= 0;
1987 DWORD nTotalSent
= 0;
1988 DWORD nBytesToSend
, nLen
, nRC
= 1;
1989 time_t s_long_time
, e_long_time
;
1994 lpszBuffer
= HeapAlloc(GetProcessHeap(), 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
1995 memset(lpszBuffer
, 0, sizeof(CHAR
)*DATA_PACKET_SIZE
);
1997 /* Get the size of the file. */
1998 GetFileInformationByHandle(hFile
, &fi
);
2003 nBytesToSend
= nBytesRead
- nBytesSent
;
2005 if (nBytesToSend
<= 0)
2007 /* Read data from file. */
2009 if (!ReadFile(hFile
, lpszBuffer
, DATA_PACKET_SIZE
, &nBytesRead
, 0))
2010 ERR("Failed reading from file\n");
2013 nBytesToSend
= nBytesRead
;
2018 nLen
= DATA_PACKET_SIZE
< nBytesToSend
?
2019 DATA_PACKET_SIZE
: nBytesToSend
;
2020 nRC
= send(nDataSocket
, lpszBuffer
, nLen
, 0);
2022 if (nRC
!= SOCKET_ERROR
)
2028 /* Do some computation to display the status. */
2030 nSeconds
= e_long_time
- s_long_time
;
2031 if( nSeconds
/ 60 > 0 )
2033 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld min %ld sec estimated remainig time %ld sec\n",
2034 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
/ 60,
2035 nSeconds
% 60, (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2039 TRACE( "%ld bytes of %d bytes (%ld%%) in %ld sec estimated remainig time %ld sec\n",
2040 nTotalSent
, fi
.nFileSizeLow
, nTotalSent
*100/fi
.nFileSizeLow
, nSeconds
,
2041 (fi
.nFileSizeLow
- nTotalSent
) * nSeconds
/ nTotalSent
);
2043 } while (nRC
!= SOCKET_ERROR
);
2045 TRACE("file transfer complete!\n");
2047 if(lpszBuffer
!= NULL
)
2048 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2054 /***********************************************************************
2055 * FTP_SendRetrieve (internal)
2057 * Send request to retrieve a file
2060 * Number of bytes to be received on success
2064 DWORD
FTP_SendRetrieve(LPWININETFTPSESSIONA lpwfs
, LPCSTR lpszRemoteFile
, DWORD dwType
)
2070 if (!FTP_InitListenSocket(lpwfs
))
2073 if (!FTP_SendType(lpwfs
, dwType
))
2076 if (!FTP_SendPortOrPasv(lpwfs
))
2079 if (!FTP_SendCommand(lpwfs
->sndSocket
, FTP_CMD_RETR
, lpszRemoteFile
, 0, 0, 0))
2082 nResCode
= FTP_ReceiveResponse(lpwfs
->sndSocket
, INTERNET_GetResponseBuffer(),
2083 MAX_REPLY_LEN
, 0, 0, 0);
2086 if (nResCode
== 125 || nResCode
== 150)
2088 /* Parse size of data to be retrieved */
2089 INT i
, sizepos
= -1;
2090 LPSTR lpszResponseBuffer
= INTERNET_GetResponseBuffer();
2091 for (i
= strlen(lpszResponseBuffer
) - 1; i
>= 0; i
--)
2093 if ('(' == lpszResponseBuffer
[i
])
2102 nResult
= atol(&lpszResponseBuffer
[sizepos
+1]);
2103 TRACE("Waiting to receive %ld bytes\n", nResult
);
2109 if (0 == nResult
&& INVALID_SOCKET
!= lpwfs
->lstnSocket
)
2111 close(lpwfs
->lstnSocket
);
2112 lpwfs
->lstnSocket
= INVALID_SOCKET
;
2119 /***********************************************************************
2120 * FTP_RetrieveData (internal)
2122 * Retrieve data from server
2129 BOOL
FTP_RetrieveFileData(LPWININETFTPSESSIONA lpwfs
, INT nDataSocket
, DWORD nBytes
, HANDLE hFile
)
2131 DWORD nBytesWritten
;
2132 DWORD nBytesReceived
= 0;
2138 if (INVALID_HANDLE_VALUE
== hFile
)
2141 lpszBuffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CHAR
)*DATA_PACKET_SIZE
);
2142 if (NULL
== lpszBuffer
)
2144 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
2148 while (nBytesReceived
< nBytes
&& nRC
!= SOCKET_ERROR
)
2150 nRC
= recv(nDataSocket
, lpszBuffer
, DATA_PACKET_SIZE
, 0);
2151 if (nRC
!= SOCKET_ERROR
)
2153 /* other side closed socket. */
2156 WriteFile(hFile
, lpszBuffer
, nRC
, &nBytesWritten
, NULL
);
2157 nBytesReceived
+= nRC
;
2160 TRACE("%ld bytes of %ld (%ld%%)\r", nBytesReceived
, nBytes
,
2161 nBytesReceived
* 100 / nBytes
);
2164 TRACE("Data transfer complete\n");
2165 if (NULL
!= lpszBuffer
)
2166 HeapFree(GetProcessHeap(), 0, lpszBuffer
);
2169 return (nRC
!= SOCKET_ERROR
);
2173 /***********************************************************************
2174 * FTP_CloseSessionHandle (internal)
2176 * Deallocate session handle
2183 BOOL
FTP_CloseSessionHandle(LPWININETFTPSESSIONA lpwfs
)
2185 if (INVALID_SOCKET
!= lpwfs
->sndSocket
)
2186 close(lpwfs
->sndSocket
);
2188 if (INVALID_SOCKET
!= lpwfs
->lstnSocket
)
2189 close(lpwfs
->lstnSocket
);
2191 if (lpwfs
->lpszPassword
)
2192 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszPassword
);
2194 if (lpwfs
->lpszUserName
)
2195 HeapFree(GetProcessHeap(), 0, lpwfs
->lpszUserName
);
2197 HeapFree(GetProcessHeap(), 0, lpwfs
);
2203 /***********************************************************************
2204 * FTP_CloseSessionHandle (internal)
2206 * Deallocate session handle
2213 BOOL
FTP_CloseFindNextHandle(LPWININETFINDNEXTA lpwfn
)
2219 for (i
= 0; i
< lpwfn
->size
; i
++)
2221 if (NULL
!= lpwfn
->lpafp
[i
].lpszName
)
2222 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
[i
].lpszName
);
2225 HeapFree(GetProcessHeap(), 0, lpwfn
->lpafp
);
2226 HeapFree(GetProcessHeap(), 0, lpwfn
);
2232 /***********************************************************************
2233 * FTP_ReceiveFileList (internal)
2235 * Read file list from server
2238 * Handle to file list on success
2242 HINTERNET
FTP_ReceiveFileList(LPWININETFTPSESSIONA lpwfs
, INT nSocket
,
2243 LPWIN32_FIND_DATAA lpFindFileData
, DWORD dwContext
)
2246 LPFILEPROPERTIESA lpafp
= NULL
;
2247 LPWININETFINDNEXTA lpwfn
= NULL
;
2251 if (FTP_ParseDirectory(lpwfs
, nSocket
, &lpafp
, &dwSize
))
2253 FTP_ConvertFileProp(lpafp
, lpFindFileData
);
2255 lpwfn
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETFINDNEXTA
));
2258 lpwfn
->hdr
.htype
= WH_HFINDNEXT
;
2259 lpwfn
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)lpwfs
;
2260 lpwfn
->hdr
.dwContext
= dwContext
;
2261 lpwfn
->index
= 1; /* Next index is 1 since we return index 0 */
2262 lpwfn
->size
= dwSize
;
2263 lpwfn
->lpafp
= lpafp
;
2267 TRACE("Matched %ld files\n", dwSize
);
2268 return (HINTERNET
)lpwfn
;
2272 /***********************************************************************
2273 * FTP_ConvertFileProp (internal)
2275 * Converts FILEPROPERTIESA struct to WIN32_FIND_DATAA
2282 BOOL
FTP_ConvertFileProp(LPFILEPROPERTIESA lpafp
, LPWIN32_FIND_DATAA lpFindFileData
)
2284 BOOL bSuccess
= FALSE
;
2286 ZeroMemory(lpFindFileData
, sizeof(WIN32_FIND_DATAA
));
2290 DWORD access
= mktime(&lpafp
->tmLastModified
);
2292 /* Not all fields are filled in */
2293 lpFindFileData
->ftLastAccessTime
.dwHighDateTime
= HIWORD(access
);
2294 lpFindFileData
->ftLastAccessTime
.dwLowDateTime
= LOWORD(access
);
2295 lpFindFileData
->nFileSizeHigh
= HIWORD(lpafp
->nSize
);
2296 lpFindFileData
->nFileSizeLow
= LOWORD(lpafp
->nSize
);
2298 if (lpafp
->bIsDirectory
)
2299 lpFindFileData
->dwFileAttributes
|= FILE_ATTRIBUTE_DIRECTORY
;
2301 if (lpafp
->lpszName
)
2302 strncpy(lpFindFileData
->cFileName
, lpafp
->lpszName
, MAX_PATH
);
2311 /***********************************************************************
2312 * FTP_ParseDirectory (internal)
2314 * Parse string of directory information
2320 * FIXME: - This function needs serious clea-up
2321 * - We should consider both UNIX and NT list formats
2323 #define MAX_MONTH_LEN 10
2324 #define MIN_LEN_DIR_ENTRY 15
2326 BOOL
FTP_ParseDirectory(LPWININETFTPSESSIONA lpwfs
, INT nSocket
, LPFILEPROPERTIESA
*lpafp
, LPDWORD dwfp
)
2329 * <Permissions> <NoLinks> <owner> <group> <size> <date> <time or year> <filename>
2332 * drwx--s--- 2 pcarrier ens 512 Sep 28 1995 pcarrier
2338 CHAR pszMonth
[MAX_MONTH_LEN
];
2340 BOOL bSuccess
= TRUE
;
2341 DWORD nBufLen
= MAX_REPLY_LEN
;
2342 LPFILEPROPERTIESA curFileProp
= NULL
;
2343 CHAR
* pszLine
= NULL
;
2344 CHAR
* pszToken
= NULL
;
2345 INT nTokenToSkip
= 3;
2353 INT sizeFilePropArray
= 20;
2354 INT indexFilePropArray
= 0;
2358 /* Allocate intial file properties array */
2359 *lpafp
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(FILEPROPERTIESA
)*(sizeFilePropArray
));
2366 while ((pszLine
= INTERNET_GetNextLine(nSocket
, INTERNET_GetResponseBuffer(), &nBufLen
)) != NULL
)
2368 if (sizeFilePropArray
<= indexFilePropArray
)
2370 LPFILEPROPERTIESA tmpafp
;
2372 sizeFilePropArray
*= 2;
2373 tmpafp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *lpafp
,
2374 sizeof(FILEPROPERTIESA
)*sizeFilePropArray
);
2384 curFileProp
= &((*lpafp
)[indexFilePropArray
]);
2386 /* First Parse the permissions. */
2387 pszToken
= strtok(pszLine
, " \t" );
2389 /* HACK! If this is not a file listing skip the line */
2390 if (!pszToken
|| 10 != strlen(pszToken
) || nBufLen
<= MIN_LEN_DIR_ENTRY
)
2392 nBufLen
= MAX_REPLY_LEN
;
2396 FTP_ParsePermission(pszToken
, curFileProp
);
2402 pszToken
= strtok( NULL
, " \t" );
2404 } while( nCount
<= nTokenToSkip
);
2406 /* Store the size of the file in the param list. */
2407 TRACE("nSize-> %s\n", pszToken
);
2408 if (pszToken
!= NULL
)
2409 curFileProp
->nSize
= atol(pszToken
);
2411 /* Parse last modified time. */
2419 pszToken
= strtok( NULL
, " \t" );
2420 strncpy(pszMonth
, pszToken
, MAX_MONTH_LEN
);
2421 CharUpperA(pszMonth
);
2422 pszMatch
= strstr(szMonths
, pszMonth
);
2423 if( pszMatch
!= NULL
)
2424 nMonth
= (pszMatch
- szMonths
) / 3;
2426 pszToken
= strtok(NULL
, " \t");
2427 TRACE("nDay -> %s\n", pszToken
);
2428 if (pszToken
!= NULL
)
2429 nDay
= atoi(pszToken
);
2431 pszToken
= strtok(NULL
, " \t");
2432 pszMinutes
= strchr(pszToken
, ':');
2433 if( pszMinutes
!= NULL
)
2436 nMinutes
= atoi(pszMinutes
);
2437 pszHour
= pszMinutes
- 3;
2438 if (pszHour
!= NULL
)
2439 nHour
= atoi(pszHour
);
2441 apTM
= localtime( &aTime
);
2442 nYear
= apTM
->tm_year
;
2446 nYear
= atoi(pszToken
);
2451 curFileProp
->tmLastModified
.tm_sec
= nSeconds
;
2452 curFileProp
->tmLastModified
.tm_min
= nMinutes
;
2453 curFileProp
->tmLastModified
.tm_hour
= nHour
;
2454 curFileProp
->tmLastModified
.tm_mday
= nDay
;
2455 curFileProp
->tmLastModified
.tm_mon
= nMonth
;
2456 curFileProp
->tmLastModified
.tm_year
= nYear
;
2458 pszToken
= strtok(NULL
, " \t");
2459 if(pszToken
!= NULL
)
2461 curFileProp
->lpszName
= FTP_strdup(pszToken
);
2462 TRACE(": %s\n", curFileProp
->lpszName
);
2465 nBufLen
= MAX_REPLY_LEN
;
2466 indexFilePropArray
++;
2469 if (bSuccess
&& indexFilePropArray
)
2471 if (indexFilePropArray
< sizeFilePropArray
- 1)
2473 LPFILEPROPERTIESA tmpafp
;
2475 tmpafp
= HeapReAlloc(GetProcessHeap(), 0, *lpafp
,
2476 sizeof(FILEPROPERTIESA
)*indexFilePropArray
);
2480 *dwfp
= indexFilePropArray
;
2484 HeapFree(GetProcessHeap(), 0, *lpafp
);
2485 INTERNET_SetLastError(ERROR_NO_MORE_FILES
);
2494 /***********************************************************************
2495 * FTP_ParsePermission (internal)
2497 * Parse permission string of directory information
2504 BOOL
FTP_ParsePermission(LPCSTR lpszPermission
, LPFILEPROPERTIESA lpfp
)
2506 BOOL bSuccess
= TRUE
;
2507 unsigned short nPermission
= 0;
2512 if ((*lpszPermission
!= 'd') && (*lpszPermission
!= '-') && (*lpszPermission
!= 'l'))
2518 lpfp
->bIsDirectory
= (*lpszPermission
== 'd');
2524 nPermission
|= (*(lpszPermission
+1) == 'r' ? 1 : 0) << 8;
2527 nPermission
|= (*(lpszPermission
+2) == 'w' ? 1 : 0) << 7;
2530 nPermission
|= (*(lpszPermission
+3) == 'x' ? 1 : 0) << 6;
2533 nPermission
|= (*(lpszPermission
+4) == 'r' ? 1 : 0) << 5;
2536 nPermission
|= (*(lpszPermission
+5) == 'w' ? 1 : 0) << 4;
2539 nPermission
|= (*(lpszPermission
+6) == 'x' ? 1 : 0) << 3;
2542 nPermission
|= (*(lpszPermission
+7) == 'r' ? 1 : 0) << 2;
2545 nPermission
|= (*(lpszPermission
+8) == 'w' ? 1 : 0) << 1;
2548 nPermission
|= (*(lpszPermission
+9) == 'x' ? 1 : 0);
2552 }while (nPos
<= nLast
);
2554 lpfp
->permissions
= nPermission
;
2559 /***********************************************************************
2560 * FTP_SetResponseError (internal)
2562 * Set the appropriate error code for a given response from the server
2567 DWORD
FTP_SetResponseError(DWORD dwResponse
)
2573 case 421: /* Service not available - Server may be shutting down. */
2574 dwCode
= ERROR_INTERNET_TIMEOUT
;
2577 case 425: /* Cannot open data connection. */
2578 dwCode
= ERROR_INTERNET_CANNOT_CONNECT
;
2581 case 426: /* Connection closed, transer aborted. */
2582 dwCode
= ERROR_INTERNET_CONNECTION_ABORTED
;
2585 case 500: /* Syntax error. Command unrecognized. */
2586 case 501: /* Syntax error. Error in parameters or arguments. */
2587 dwCode
= ERROR_INTERNET_INCORRECT_FORMAT
;
2590 case 530: /* Not logged in. Login incorrect. */
2591 dwCode
= ERROR_INTERNET_LOGIN_FAILURE
;
2594 case 550: /* File action not taken. File not found or no access. */
2595 dwCode
= ERROR_INTERNET_ITEM_NOT_FOUND
;
2598 case 450: /* File action not taken. File may be busy. */
2599 case 451: /* Action aborted. Server error. */
2600 case 452: /* Action not taken. Insufficient storage space on server. */
2601 case 502: /* Command not implemented. */
2602 case 503: /* Bad sequence of command. */
2603 case 504: /* Command not implemented for that parameter. */
2604 case 532: /* Need account for storing files */
2605 case 551: /* Requested action aborted. Page type unknown */
2606 case 552: /* Action aborted. Exceeded storage allocation */
2607 case 553: /* Action not taken. File name not allowed. */
2610 dwCode
= ERROR_INTERNET_INTERNAL_ERROR
;
2614 INTERNET_SetLastError(dwCode
);